Edit:
I'm considering hexagonit, and swfTools. Does anyone have any other solutions, or insight?
Edit:
New Question - how to solve this error:
I tried using hexagonit.swfheader however I receive the error:
f = 'out/'+w+"/"+s+"/"+"theSwf/"+s
data = hexagonit.swfheader.parse(f)
File "/Library/Python/2.7/site-packages/hexagonit/swfheader/__init__.py", line 26, in parse
signature = ''.join(struct.unpack('<3c', input.read(3)))
struct.error: unpack requires a string argument of length 3
After tracing through this I found that the error occurs here:
def parse(input):
"""Parses the header information from an SWF file."""
need_close=False
if hasattr(input, 'read'):
input.seek(0)
else:
input = open(input, 'rb')*
need_close=True
* being where the error occurs.
I read: Get dimensions from a flash file (.swf) in pure-Python
I have also tried using PIL and Pillow however I am under the impression that they compare images not swf files. I decompiled the swf file's I'm looking at along but also have the swf file itself.
I would like to know what size the file displays as (dimensions).
My first thought was to try using image size comparison.
My issue with this is that some images that are used as assets in the swf are actually larger than the swf itself, otherwise I would use PIL to simply get the dimensions of the largest image asset (ex the background).
Secondly my other issue is that can equally compare svg and png files.. and Pillow and Pil to my knowledge do not handle svg files.
My second idea was to search the actionscript code for the dimensions.
Some files have in their action script something like 300x300 which denotes the size. Unfortunately after looking at most of the files I am working with do not which means this is largely unhelpful.
My 3rd idea was to ignore the decompiled swf data and rather focus on the swf itself.
I could in theory either try to find the dimensions in the byte code (or use a library that does this (which I need to find one as pip and pillow do not appear to work)) or I need to run the ad and then screenshot it and try to find where the ad starts and stops and calculate the pixels based on that. My problem with screens shotting it is that the image may blend into the background and make it hard if not impossible to get the correct dimensions, but more importantly many swfs cannot be played due to security if they are not played in the right url, etc.
Thus I'm left with a dilemma. I think the best way to go about this would be to use the swf file itself.
Take a look at the official SWF file format spec. The dimension info you are looking for should be right near the beginning of the file. Take a look at the section "The SWF header"
The FrameSize field defines the width and height of the on-screen display. This field is stored as a RECT
structure, meaning that its size may vary according to the number of bits needed to encode the coordinates. The
FrameSize RECT always has Xmin and Ymin value of 0; the Xmax and Ymax members define the width and height
(see Using bit values).
Related
I want to compare two images (.png format) pixel by pixel using selenium in python. Or how could i do it using pillow library.
I have a base image and i get the compare image by taking screenshot of the webpage. I want to compare those two images and assert that they are equal. how can I do it.
Below is what I have tried:
def assert_images_are_equal(base_image, compare_image):
with open(base_image, 'rb') as f1, open(compare_image, 'rb') as f2:
base_image_contents = f1.read()
compare_image_contents = f2.read()
assert base_image_contents == compare_image_contents
But this doesnt work always. I want to compare pixel by pixel. Could someone help me with this using pillow library or any other library apart from PIL? thanks.
It is rather difficult to say whether 2 images are the same or similar, because it depends on your definitions of "same" and "similar".
You can make a solid red image, save it as a PNG and then save the exact same image again and it could be different because the PNG format contains a timestamp in the image header that may have ticked over to the next second in between saves.
You can make a solid red PNG file that is 8-bits deep, and another that is 16-bits deep and you cannot see the difference but the data will be grossly different.
You can make a TIF file in Motorola byte order and the same file in Intel byte order. Visually, and in calculations, they will be indistinguishable, but the files will be grossly different.
You can make a GIF file that is red and it will look no different from a PNG file but the files will differ.
You can make a palette image and a true-colour image and the pixels will be grossly different but they will look identical.
You could make a simple black image with a white rectangle in the middle and write it using one JPEG library and it will come out different from the same image written with a different JPEG library, or even a different release version of the same library.
There are many more cases...
One a more helpful note, you may want to look at Perceptual Hashing which tells you if images look pretty similar. One library that does Perceptual Hashing is ImageMagick and it has a Python binding here and here.
Here is the image I need to detect: http://s13.postimg.org/wt8qxoco3/image.png
Here is the base64 representation: http://pastebin.com/raw.php?i=TZQUieWe
The reason why I'm asking for your help is because this is a complex problem and I am not equipped to solve it. It will probably take me a week to do it by myself.
Some pseudo-code that I thought about:
1) Take screenshot of the app and store it as image object.
2) Convert binary64 representation of my image to image object.
3) Use some sort of algorithm/function to compare both image objects.
By on screen, I mean in an app. I have the app's window name and the PID.
To be 100% clear, I need to essentially detect if image1 is inside image2. image1 is the image I gave in the OP. image2 is a screenshot of a window.
If you break this down into pieces, they're all pretty simple.
First, you need a screenshot of the app's window as a 2D array of pixels. There are a variety of different ways to do this in a platform-specific way, but you didn't mention what platform you're on, so… let's just grab the whole screen, using PIL:
screenshot = ImageGrab.grab()
haystack = screenshot.load()
Now, you need to convert your base64 into an image. Taking a quick look at it, it's clearly just an encoded PNG file. So:
decoded = data.decode('base64')
f = cStringIO.StringIO(decoded)
image = Image.open(f)
needle = image.load()
Now you've got a 2D array of pixels, and you want to see if it exists in another 2D array. There are faster ways to do this—using numpy is probably best—but there's also a dumb brute-force way, which is a lot simpler to understand: just iterate the rows of haystack; for each one, iterate the columns, and see if you find a run of bytes that matches the first row of needle. If so, keep going through the rest of the rows until you either finish all of needle, in which case you return True, or find a mismatch, in which case you continue and just start again on the next row.
this is probably the best place to start:
http://effbot.org/imagingbook/image.htm
if you don't have access to the image's meta data, file name, type, etc, what you're trying to do is very difficult, but your pseudo sounds on-point. essentially, you'll have to create an algorithmic model based on a photo's shapes, lines, size, colors, etc. then you'd have to match that model against models already made and indexed in some database. hope that helps.
It looks like https://python-pillow.org/ is a more updated version of PIL.
I am new to Python, and trying to use PIL to perform a parsing task I need for an Arduino project. This question pertains to the Image.convert() method and the options for color palettes, dithering etc.
I've got some hardware capable of displaying images with only 16 colors at a time (but they can be specified RGB triplets). So, I'd like to automate the task of taking an arbitrary true-color PNG image, choosing an "optimum" 16-color palette to represent it, and converting the image to a palettized one containing ONLY 16 colors.
I want to use dithering. The problem is, the image.convert() method seems to be acting a bit funky. Its arguments aren't completely documented (PIL documentation for Image.convert()) so I don't know if it's my fault or if the method is buggy.
A simple version of my code follows:
import Image
MyImageTrueColor = Image.new('RGB',100,100) # or whatever dimension...
# I paste some images from several other PNG files in using MyImageTrueColor.paste()
MyImageDithered = MyImageTrueColor.convert(mode='P',
colors=16,
dither=1
)
Based on some searches I did (e.g.: How to reduce color palette with PIL) I would think this method should do what I want, but no luck. It dithers the image, but yields an image with more than 16 colors.
Just to make sure, I removed the "dither" argument. Same output.
I re-added the "dither=1" argument and threw in the Image.ADAPTIVE argument (as shown in the link above) just to see what happened. This resulted in an image that contained 16 colors, but NO dithering.
Am I missing something here? Is PIL buggy? The solution I came up with was to perform 2 steps, but that seems sloppy and unnecessary. I want to figure out how to do this right :-) For completeness, here's the version of my code that yields the correct result - but it does it in a sloppy way. (The first step results in a dithered image with >16 colors, and the second results in an image containing only 16 colors.)
MyImage_intermediate = MyImageTrueColor.convert(mode='P',
colors=16
)
MyImageDithered = MyImage_intermediate.convert(mode='P',
colors=16,
dither=1,
palette=Image.ADAPTIVE
)
Thanks!
Well, you're not calling things properly, so it shouldn't be working… but even if we were calling things right, I'm not sure it would work.
First, the "official" free version of the PIL Handbook is both incomplete and out of date; the draft version at http://effbot.org/imagingbook/image.htm is less incomplete and out of date.
im.convert(“P”, **options) ⇒ image
Same, but provides better control when converting an “RGB” image to an
8-bit palette image. Available options are:
dither=. Controls dithering. The default is FLOYDSTEINBERG, which
distributes errors to neighboring pixels. To disable dithering, use
NONE.
palette=. Controls palette generation. The default is WEB, which is
the standard 216-color “web palette”. To use an optimized palette, use
ADAPTIVE.
colors=. Controls the number of colors used for the palette when
palette is ADAPTIVE. Defaults to the maximum value, 256 colors.
So, first, you can't use colors without ADAPTIVE—for obvious reason: the only other choice is WEB, which only handles a fixed 216-color palette.
And second, you can't pass 1 to dither. That might work if it happened to be the value of FLOYDSTEINBERG, but that's 3. So, you're passing an undocumented value; who knows what that will do? Especially since, looking through all of the constants that sound like possible names for dithering algorithms, none of them have the value 1.
So, you could try changing it to dither=Image.FLOYDSTEINBERG (along with palette=Image.ADAPTIVE) and see if that makes a difference.
But, looking at the code, it looks like this isn't going to do any good:
if mode == "P" and palette == ADAPTIVE:
im = self.im.quantize(colors)
return self._new(im)
This happens before we get to the dithering code. So it's exactly the same as calling the (now deprecated/private) method quantize.
Multiple threads suggest that the high-level convert function was only intended to expose "dither to web palette" or "map to nearest N colors". That seems to have changed slightly with 1.1.6 and beyond, but the documentation and implementation are both still incomplete. At http://comments.gmane.org/gmane.comp.python.image/2947 one of the devs recommends reading the PIL/Image.py source.
So, it looks like that's what you need to do. Whatever Image.convert does in Image.WEB mode, you want to do that—but with the palette that would be generated by Image.quantize(colors), not the web palette.
Of course most of the guts of that happens in the C code (under self.im.quantize, self.im.convert, etc.), but you may be able to do something like this pseudocode:
dummy = img.convert(mode='P', paletter='ADAPTIVE', colors=16)
intermediate = img.copy()
intermediate.setpalette(dummy.palette)
dithered = intermediate._new(intermediate.im.convert('P', Image.FLOYDSTEINBERG))
Then again, you may not. You may need to look at the C headers or even source to find out. Or maybe ask on the PIL mailing list.
PS, if you're not familiar with PIL's guts, img.im is the C imaging object underneath the PIL Image object img. From my past experience, this isn't clear the first 3 times you skim through PIL code, and then suddenly everything makes a lot more sense.
I have a program in Python (using pyPDF) that merges a bunch of different PDF documents. Sometimes, the resulting pdf is fine, except for some blank pages in the middle. When I view these documents with Acrobat Reader, I get an error message saying "insufficient data for image". When I view the documents with FoxIT Reader, I get some blank pages and a munged image.
The only odd thing about the PDF that creates the blank pages is that it seems to be PDF Version 1.4, and PyPdf seems to create files with PDF Version 1.3.
1) Does the version thing sound like the root cause of my problem?
2) Is there a way to get PyPdf to handle this correctly?
This might be related to Windows not actually the .pdf file.
http://support.microsoft.com/kb/2506795
Good luck!
I had this problem, and was able to figure it out by looking at the original pdf side by side with the PyPDF one in a hex editor.
The problem seems to be that PyPDF actually leaves off a byte - it looks like probably the first byte in each image stream is missing. When I added the bytes to the PyPDF file, the pdf opened up fine without the error.
I suspect that the image XObject stream is Malformed. Without access to a PDF with the problem, all most folks can do is guess.
For example, if the pdf info says the image is 10 pixels wide, 10 pixels high, and 8 bits per pixel, then the stream should uncompress to 100 bytes. If it uncompressed to less than that, I'd expect an error like the one you're seeing.
The is probably a bug in pypdf regarding whatever image format you happen to be using.
IIRC, there's is no scan-line padding in PDF and no concern for word boundaries, though the last bits are padded out to a byte if need be. Confusion there could easily lead to too many bytes, which isn't the problem here.
It could also be a bad color space. If you've got an indexed color image (gif), and they translate it half way to an RGB image, but use the original indexed color bytes, you'd get a stream that might expect n*3 bits per pixel, but only have n bits per pixel.
It's possible that this is an older bug that's been fixed in pypdf. Are you using the current version?
given a somewhat complex file of unknown specification that among other things contains an uncompressed bitmap file (.BMP), how would you extract it in Python?
Scan for the "BM" tag and see if the following bytes "resemble" a BMP header?
I'd use the Python Imaging Library PIL and have it a go at the data. If it can parse it, then it's a valid image. When it throws an exception, then it isn't.
You need to search for the begining of the image; if you're lucky, the image reader will ignore garbage after the image data. When it doesn't, use a binary search to locate the end of the image.
Yes, about the only thing you can do is search through the file for the 'BM' marker, pull out the following data into a BITMAPFILEHEADER and corresponding BITMAPINFO, and see if the values in it look valid (i.e. that the dimensions are sensible, colour depth is reasonable, etc).
Once you have found something that looks reasonable, pull that data out and pass it to the library mentioned in another answer.