GNOME Bugzilla – Bug 494667
gdkpixloader jpeg loader problems with some files
Last modified: 2010-07-10 04:07:46 UTC
Please describe the problem: I get this error with some jpeg files: "Error interpreting JPEG image file (Application transferred too few scanlines)". It happens only when I use GdkPixbufLoader but not with gdk_pixbuf_new_from_file(). Steps to reproduce: Compile and run the test program that I will attach with several jpeg files (try to use a variety of files from different sources, not always from the same one). Actual results: The error "Error interpreting JPEG image file (Application transferred too few scanlines)" is generated though other programs had no problem with those jpeg files and GTK 2.10 didn't had problems too. Expected results: No errors at all. Does this happen every time? Yes, when you find the jpeg files that cannot be loaded, it happens everytime. Other information:
Created attachment 98725 [details] Test program showing the failure
Created attachment 98726 [details] Test program showing that gdk_pixbuf_from_file() doesn't fail.
I found that the commit 17567 to io-jpeg.c is the culprit. Reverting this specific part "... and it pulls the check for infinite looping out of an else branch in load_increment() so it runs unconditionally ..." fixes the problem. So here is a reverting patch but I don't know what other effects it has (except that it fixes the problem I see), but I guess Tim Janik knows better and now could fix this the right way. --- io-jpeg.c (revision 17567) +++ io-jpeg.c (working copy) @@ -689,7 +689,7 @@ src->pub.bytes_in_buffer += num_copy; bufhd += num_copy; num_left -= num_copy; - } + } else { /* did anything change from last pass, if not return */ if (first) { @@ -699,6 +699,7 @@ spinguard++; else last_bytes_left = src->pub.bytes_in_buffer; + } /* should not go through twice and not pull bytes out of buf */ if (spinguard > 2) Thanks!
The issue is that the spinguard fails to consider the case where the caller buffer is larger than 65536 bytes. Instrumenting with: /* did anything change from last pass, if not return */ if (first) { last_bytes_left = src->pub.bytes_in_buffer; first = FALSE; } else if (src->pub.bytes_in_buffer == last_bytes_left) { spinguard++; g_message("spinguard %d: src->pub.bytes_in_buffer (%d) == last_bytes_left (%d)", spinguard, src->pub.bytes_in_buffer, last_bytes_left); } else last_bytes_left = src->pub.bytes_in_buffer; /* should not go through twice and not pull bytes out of buf */ if (spinguard > 2) return TRUE; gives: GdkPixbuf-Message: spinguard 1: src->pub.bytes_in_buffer (0) == last_bytes_left (0) GdkPixbuf-Message: spinguard 2: src->pub.bytes_in_buffer (0) == last_bytes_left (0) GdkPixbuf-Message: spinguard 3: src->pub.bytes_in_buffer (0) == last_bytes_left (0) GdkPixbuf-Message: spinguard 1: src->pub.bytes_in_buffer (65536) == last_bytes_left (65536) GdkPixbuf-Message: spinguard 2: src->pub.bytes_in_buffer (65536) == last_bytes_left (65536) GdkPixbuf-Message: spinguard 3: src->pub.bytes_in_buffer (65536) == last_bytes_left (65536) The fix should be to base the spinguard on num_left as well.
Created attachment 100069 [details] [review] gdk-pixbuf-jpeg-spinguard.patch Patch.
Seems to be a whole load of duplicates and derived bugs: bug 477860, bug 495703, bug 500785, bug 494667. Agree with Ivan that http://svn.gnome.org/viewvc/gtk%2B/trunk/gdk-pixbuf/io-jpeg.c?view=log#rev17567 is the cuplrit - blame Maemo.
Great work, Ed. Your patch unbreaks the pan newsreader (two of the bugs you listed above) so lots of people will be happy again thanks to you. Can your patch be committed now, or does it need more testing?
Looks ok to me. Please commit to the gtk-2-12 branch, too, if you can.
*** Bug 500785 has been marked as a duplicate of this bug. ***
I notice that Ed's patch has not been committed yet. Ed is not identified as a 'developer', so perhaps he can't commit the patch himself? I don't know. It would be great if someone could do it, though. Thanks!
2007-12-09 Matthias Clasen <mclasen@redhat.com> * io-jpeg.c: Fix the spinguard logic for big buffers. (#494667, Ed Catmur)
As pointed out by #491063, the workaround is to write the data in chunks. This fast python implementation for PyGTK, inspired by http://docs.python.org/lib/itertools-functions.html, might save somebody a few minutes pain: ========================================================================= from itertools import izip, chain, repeat size = 50000 for chunk in izip(*[chain(imagedata, repeat('', size-1))] * size): myPixbufLoader.write(''.join(chunk))