Converting svg to png without changing the pixel values - python

I have been stuck in this problem for some time now. Essentially, I have a bunch of svg images. Each 'child' in the svg file has been labelled with some pixel value. Currently the number of this values is very small and everything is labelled as rgb(0.0, 0.0, 0.0), rgb(1.0, 1.0, 1.0) ... rgb(9.0, 9.0, 9.0), so essentially I have 10 different types of pixels.
Now, I want to convert these images into png format, and more importantly I need the mapping of pixel values to be 1-to-1. Essentially, all pixels that have values rgb(0.0, 0.0, 0.0) in svg files, need to have values rgb(x,x,x) in png files (or even better L(x)); rgb(1.0, 1.0, 1.0) on svg files need to be converted to rgb(y,y,y) on png files (or even better L(y)) and so on. This one to one mapping is a dealbreaker for my application, because this is essentially the ground truth for my work.
By simply writing in the console:
convert test.svg test.png
doesn't give me what I want. Checking the historgram of values, it seems that I have 248 unique values instead of 10, and that isn't good for me (despite that the vast majority of them have just a few pixels).
Does anyone know:
if this can be done.
how this can be done.
I've tried so far using other libraries like Python's cairosvg but that seems to work even worse. Yes, I know that svg and png are totally different formats.
For clarification, adding an svg and a png file:
svg: https://drive.google.com/open?id=0B_vhcDz1zxeYeGVDSnhfeWplOWs
png: https://drive.google.com/open?id=0B_vhcDz1zxeYUnYzZUtIUmVqVWM
Opening the file in Python, seems that there are 248 unique pixel values, while there should be only 4 (background + three symbols).
Thanks!

Your request isn't making a lot of sense. As far as I can see, your sample SVG file only has two colours: black and white (rgb(255.0, 255.0, 255.0)). So where does this 10 colours idea come from?
Also the SVG standard does not specify exactly how vector shapes should be converted to pixels. There will be subtle differences between SVG renderers.
Remember that vector shape edges that pass through the middle of a pixel will produce a grey pixel. This is called anti-aliasing. It is designed to give a smoother look to the edge. And I imagine that is why you are seeing many more pixel values than you expect.
Perhaps what you are saying is that you want a way to disable anti-aliasing? Some conversion programs may have options to do this. Alternatively you can try adding the shape-rendering attribute to the root <svg> tag of your file:
<ns0:svg ...(snip)... shape-rendering="crispEdges">
However some SVG conversion programs may not support this attribute. But you can see it working if you try it in most browsers.
The output generated by turning antialiasing off will not look as good. But perhaps for your purposes you don't care about that.
Alternatively, perhaps you are wanting to know how to convert the SVG to a bitmap, whilst limiting the antialiasing to 10 specific levels of grey? Imagemagick lets you do that. I am not an Imagemagick user, but apparently you can tell imagemagick to use a specific colour paletter by passing a palette image using the -map parameter.

3 Years but no great solution gg:
I found 2 good ones:
in the ImageMagick command line you can use:
"convert in.svg +antialias out.png"
but be careful my source said that "+" deactivates AA and "-" activates it. But the source is pretty old and this seems strange so. I couldn't try this
Inkscape brought a great solution in an update (I tried this in Version 1.0.1):
in the Advanced Settings for "export png" you can choose Antialiasing directly "CAIRO_ANTIALIAS_NONE" works perfectly for me

Related

image rendering issue in psychopy

I am a long-time psychopy user, and i just upgraded to 1.81.03 (from 1.78.x). In one experiment, i present images (.jpgs) to the user and ask for a rating scale response. The code worked fine before the update, but now i am getting weird artifacts on some images. For example, here is one image i want to show:
But here is what shows up [screencapped]:
You can see that one border is missing. This occurs for many of my images, though it is not always the same border, and sometimes two or three borders are missing.
Does anyone have an idea about what might be going on?
I received this information from the psychopy-users group (Micahel MacAskill):
As a general point, you should avoid using .jpgs for line art: they aren't designed for this (if you zoom in, in the internal corners of your square, you'll see the typical compression artefacts that their natural image-optimised compression algorithm introduces when applied to line art). .png format is optimal for line art. It is lossless and for this sort of image will still be very small file-size wise.
Graphics cards sometimes do scaling-up and then down-scaling of bitmaps, which can lead to issues like this with single-pixel width lines. Perhaps this is particularly the issue here because (I think) this image was supposed to be 255 × 255 pixels, and cards will sometimes scale up to the nearest power-of-two size (256 × 256) and then down again, so easy to see how the border might be trimmed.
I grabbed your image off SO, it seemed to have a surrounding border around the black line to make it 321 × 321 in total. I made that surround transparent and saved it as .png (another benefit of png vs jpg). It displays without problems (although a version cropped to just the precise dimensions of the black line did show the error you mentioned). (Also, the compression artefacts are still there, as I just made this png directly from the jpg). See attached file.
If this is the sort of simple stimulus you are showing, you might want to use ShapeStim/Polygon stimuli instead of bitmaps. They will always be drawn precisely, without any scaling issues, and there wouldn't be the need for any jiggery pokery.
Why this changed from 1.78 I'm not sure. The issue is also there in 1.82.00

Changing the bit-depth of figures produced using Matplotlib

I'm using matplotlib to generate some figures via savefig. These figures are black and white and need to be saved at a very high resolution (1000 dpi) in TIFF format. It would therefore be beneficial to save them with a reduced bit depth so as to use less memory.
To that end, my question: how does one specify the bit depth when saving figures with matplotlib?
Thanks!
So far I get the impression that matplotlib doesn't support a bit-depth option. I'm thus using imagemagick to convert the image posthoc:
convert -monochrome +dither A.tiff B.tiff
Several things I'll mention in case someone else is trying to do similarly:
When I first changed the bitdepth by running convert -monochrome A.tiff B.tiff, the fonts looked unacceptably ugly (even at 1000 DPI!). This was because of antialiasing, which matplotlib performs by default. I couldn't find any option to turn this off, but its negative effects (when downsampling the DPI) can be largely circumvented by enabling dithering. Therefore, even if there is an option to change the DPI of the output image in matplotlib, it isn't useful unless it performs dithering or unless there's also an option to disable antialiasing.
Short answer, I would suggest to anyone in a similar situation as me to do their monochrome conversion posthoc as I have done.

Can PIL be used to get dimensions of an svg file?

I have svg files which I would like to compare based on their dimensions.
I read about PIL as the best image tool in python. Does PIL handle svg files? I can't seem to find this anywhere.
When googling I saw people interpreting svg files as text which seems counterintuitive.
What if not PIL is be the best way to get the x & y dimensions of a .svg file?
Thanks
PIL handles many image types, but not (yet?) SVG. Partly, this is because SVG is a set of instructions to produce an image, not a container for raw image data.
Fortunately, SVG can be read as XML, using the tool of your choice; for example, xml.etree.ElementTree in the Python standard library.
Unfortunately, by its nature, SVG doesn't have a single native size. Instead, it has two size concepts: the view box, and the height and width attributes.
If your svg file has width and height attributes, you can safely use those as the x and y dimensions, respectively. Otherwise, if it has a viewBox attribute, it is meant to scale to any size you need it to; however, you can use its third and fourth numbers as width and height, if you need to.
Worse, SVG files could lack either one. In that case, one could potentially compute a height and width based on the elements in the file, but that's trickier than anyone really wants to do, given the full capabilities of the format.

Python: replace a rgb colour with a colour with alpha pixels. batch convert 400 images

How can I replace a colour across multiple images with another in python? I have a folder with 400 sprite animations. I would like to change the block coloured shadow (111,79,51) with one which has alpha transparencies. I could easily do the batch converting using:
img = glob.glob(filepath\*.bmp)
however I dont know how I could change the pixel colours. If it makes any difference, the images are all 96x96 and i dont care how long the process is. I am using python 3.2.2 so I cant really use PIL (I think)
BMP is a windows file format, so you will need PIL or something like it; or you can roll your own reader/writer. The basic modules won't help as far as I'm aware. You can read PPM and GIF using Tk (PhotoImage()) which is part of the standard distribution and use get() and put() on that image to change pixel values. See references online, because it's not straight-forward - the pixels come from get() as 3-tuple integers, but need to go back to put() as space-separated hex text!
Are your images in indexed mode (8 bit per pixel with a palette),or "truecolor" 32bpp images? If they are in indexed modes, it would not be hard to simply mark the palette entry for that color to be transparent across all files.
Otherwise, you will really have to process all pixel data. It also could be done by writting a Python script for GIMP - but that would require Python-2 nonetheless.

Is there a way to extract text information from a postscript file? (.ps .eps)

I want to extract the text information contained in a postscript image file (the captions to my axis labels).
These images were generated with pgplot. I have tried ps2ascii and ps2txt on Ubuntu but they didn't produce any useful results. Does anyone know of another method?
Thanks
It's likely that pgplot drew the fonts in the text directly with lines rather than using text. Especially since pgplot is designed to output to a huge range of devices including plotters where you would have to do this.
Edit:
If you have enough plots to be worth
the effort than it's a very simple
image processing task. Convert each
page to something like tiff, in mono
chrome Threshold the image to binary,
the text will be max pixel value.
Use a template matching technique.
If you have a limited set of
possible labels then just match the
entire label, you can even start
with a template of the correct size
and rotation. Then just flag each
plot as containing label[1-n], no
need to read the actual text.
If you
don't know the label then you can
still do OCR fairly easily, just
extract the region around the axis,
rotate it for the vertical - and use
Google's free OCR lib
If you have pgplot you can even
build the training set for OCR or
the template images directly rather
than having to harvest them from the
image list

Categories