ImageIO/BufferedImage behaving inconsistently from one day to thenext.

Discussion in 'Java' started by Fred Greer, Jun 20, 2012.

  1. Fred Greer

    Fred Greer Guest

    I have code that used to work perfectly, which processes images in
    certain ways, and today it suddenly was not working. I hadn't changed the
    code at all. I tracked the problem down to spurious
    IllegalArgumentExceptions being thrown by this code:

    public class ImageUtils {

    private static float[] BLUR = {0.1111111, 0.1111111, 0.1111111,
    0.1111111, 0.1111111, 0.1111111,
    0.1111111, 0.1111111, 0.1111111}
    ....
    public static BufferedImage blur (BufferedImage img) {
    Kernel k = new Kernel(3, 3, BLUR);
    ConvolveOp co = new ConvolveOp(k, ConvolveOp.EDGE_NO_OP, null);
    BufferedImage dest = new BufferedImage(img.getWidth(),
    img.getHeight(),img.getType());
    co.filter(img,dest);
    return dest;
    }
    ....
    }

    This code worked yesterday and fails today with

    java.lang.IllegalArgumentException: Unknown image type 0

    and a stack trace pointing to the line creating dest.

    I did some fiddling, and when loading any PNG image with ImageIO.read,
    the result (after being fed through something that uses reflection to try
    to identify bean-like properties in order to "inspect" an object; one of
    my debugging tools) is this:

    java.awt.image.BufferedImage: type = 0 ColorModel: #pixelBits = 32
    numComponents = 4 color space = java.awt.color.ICC_ColorSpace@1bffd0d
    transparency = 3 has alpha = true isAlphaPre = false
    ByteInterleavedRaster: width = 2560 height = 1440 #numDataElements 4
    dataOff[0] = 0

    According to the Javadocs, a type of 0 represents "Custom".

    There are only two conclusions to draw from this:

    1. Overnight, BufferedImage suddenly stopped accepting a type of 0, or
    2. Overnight, ImageIO.read suddenly started setting the image type to 0
    instead of something more specific like TYPE_INT_ARGB when loading and
    decoding PNGs.

    Neither of these makes much sense, because standard library code is not
    supposed to magically change its behavior like that, and it's certainly
    not supposed to make something that used to work no longer work by
    magically changing its behavior overnight.

    Now, when I first wrote the blur method it had had

    BufferedImage dest = co.createCompatibleDestImage(img,
    img.getColorModel());

    instead. The result had been a blank black image output from
    ImageUtils.blur(foo) no matter what the input looked like. I've now tried
    that again, and suddenly it works.

    So, literally overnight and without apparent provocation,

    new BufferedImage(img.getWidth(),img.getHeight(),img.getType())

    magically started throwing exceptions when it used to work with the exact
    same disk file loaded into img in the exact same way, and at the same
    time,

    co.createCompatibleDestImage(img,img.getColorModel());

    magically started *working* when it had previously created destination
    images that didn't actually work with the ConvolveOp in question, despite
    the obvious contract of the method named "createCompatibleDestImage".

    Can anyone explain these occurrences?

    Furthermore, can anyone suggest an implementation of blur that is
    guaranteed not only to work, but to stay working in perpetuity and not
    magically stop working some day? What if the version of blur using
    createCompatibleDestImage suddenly goes back to producing blank images? I
    can restore the other version of the code. Or I can even write

    try {
    ; Blur implementation using constructor and .getType goes here
    } catch (IllegalArgumentException x) {
    ; Blur implementation using createCompatibleDestImage goes here
    }

    and this will presumably work even if it randomly toggles between the two
    observed patterns of behavior every Tuesday and alternate Thursday,
    though it'll be an evil, ugly hack. But what if it suddenly jumps to some
    *third* state where *neither* implementation of blur works and I have to
    try something completely new? And what if it changes to something
    unprecedented again after that, and again, and every week forever?

    Logically, that shouldn't be possible. But by the same logic *what I've
    already observed* shouldn't be possible, so obviously that logic is
    suspect and I can no longer assume that blur needing a completely novel
    implementation every week, or every day, or even every hour cannot
    happen. Doctors needing completently novel antibiotics to treat staph
    infections not only can but has happened, and happened repeatedly, after
    all, so if something in the JVM has started "evolving resistance" to
    blurring images successfully, for some reason, then the same thing could
    happen there.

    So, is there something that is evolving or changing under the hood in how
    ImageIO/AWT operates? And if so, are there any rock-stable guarantees
    regarding the API behavior that I can rely on to implement a blur method
    that will never fail for any valid input image? I'd have thought, from
    reading the javadocs for it, that createCompatibleDestImage was it, but
    that's already been disproved...
    Fred Greer, Jun 20, 2012
    #1
    1. Advertising

  2. Fred Greer

    Fred Greer Guest

    Re: ImageIO/BufferedImage behaving inconsistently from one day tothe next.

    On Tue, 19 Jun 2012 19:38:40 -0700, markspace wrote:

    > On 6/19/2012 7:31 PM, Fred Greer wrote:
    >
    >> So, literally overnight and without apparent provocation, magically
    >> started throwing exceptions

    >
    >> Can anyone explain these occurrences?

    >
    >
    > Can you upload the image someplace where we can access it? And then
    > download it again and verify it's the same as you have on your disc
    > drive, sometimes image services reduce resolution or compress images.
    >
    > We will have a better shot at figuring something out if we have the
    > offending file to inspect.


    I checked and the behavior change seems to affect all .png files
    regardless of origin or what program generated them. I didn't check .jpg
    or other formats.

    Any .png should therefore be substitutable for any other in checking this
    (except that the createCompatibleDestImage issue won't be detectable if
    it's a blank black .png).
    Fred Greer, Jun 20, 2012
    #2
    1. Advertising

  3. Fred Greer

    Fred Greer Guest

    Re: ImageIO/BufferedImage behaving inconsistently from one day tothe next.

    On Tue, 19 Jun 2012 20:38:40 -0700, Patricia Shanahan wrote:

    > On 6/19/2012 7:31 PM, Fred Greer wrote: ...
    >> Neither of these makes much sense, because standard library code is not
    >> supposed to magically change its behavior like that, and it's certainly
    >> not supposed to make something that used to work no longer work by
    >> magically changing its behavior overnight.

    >
    > Is your code multi-threaded?
    >
    > I'm asking because things that transition "magically" between working
    > and not working are often timing dependent, and transition because of a
    > change that affects relative speeds, such as file placement and cache
    > history.
    >
    > Patricia


    It's single-threaded.
    Fred Greer, Jun 20, 2012
    #3
  4. Fred Greer

    Roedy Green Guest

    Re: ImageIO/BufferedImage behaving inconsistently from one day to the next.

    On Wed, 20 Jun 2012 02:31:00 +0000 (UTC), Fred Greer
    <> wrote, quoted or indirectly quoted someone
    who said :

    >(BufferedImage img

    did you put in MediaTracker wait code for this to load? If you
    didn't sometimes you will try to get the size before it loads.
    --
    Roedy Green Canadian Mind Products
    http://mindprod.com
    If you look in a computer programmer's freezer you will find all
    kinds of containers, but none of them labeled. They do the same thing
    creating files without labeling the encoding. You are just supposed to
    know. Ditto with the MIME type, the separator and comment delimiters and
    column names in CSV files. Ditto with the endian convention. Imagine how
    much more civilised life would have been if Martha Stewart were the first
    programmer.
    Roedy Green, Jun 20, 2012
    #4
  5. Fred Greer

    Joerg Meier Guest

    Re: ImageIO/BufferedImage behaving inconsistently from one day to the next.

    On Wed, 20 Jun 2012 01:16:16 -0700, Roedy Green wrote:

    > On Wed, 20 Jun 2012 02:31:00 +0000 (UTC), Fred Greer
    > <> wrote, quoted or indirectly quoted someone
    > who said :
    >>(BufferedImage img

    > did you put in MediaTracker wait code for this to load? If you
    > didn't sometimes you will try to get the size before it loads.


    I'm with Roedy, especially if the situation changed without you doing
    anything to the code, I would suspect it to be a timing issue with the
    image loading. You haven't show the image loading code, so it's hard to
    tell, but try to insert after

    public static BufferedImage blur (BufferedImage img) {

    a line like

    Toolkit.getDefaultToolkit().prepareImage(img, -1, -1, new ImageObserver());

    before you try to use the image.

    I don't recall off hand, and you'll have to do your own research, but I
    think you can just pass null instead of an actual ImageObserver, and of
    course this code should really go to where the image is actually loaded.

    Liebe Gruesse,
    Joerg

    --
    Ich lese meine Emails nicht, replies to Email bleiben also leider
    ungelesen.
    Joerg Meier, Jun 20, 2012
    #5
  6. Re: ImageIO/BufferedImage behaving inconsistently from one day tothe next.

    On 6/19/2012 7:31 PM, Fred Greer wrote:
    > I have code that used to work perfectly, which processes images in
    > certain ways, and today it suddenly was not working. I hadn't changed the
    > code at all. I tracked the problem down to spurious
    > IllegalArgumentExceptions being thrown by this code:
    >
    > public class ImageUtils {
    >
    > private static float[] BLUR = {0.1111111, 0.1111111, 0.1111111,
    > 0.1111111, 0.1111111, 0.1111111,
    > 0.1111111, 0.1111111, 0.1111111}
    > ...
    > public static BufferedImage blur (BufferedImage img) {
    > Kernel k = new Kernel(3, 3, BLUR);
    > ConvolveOp co = new ConvolveOp(k, ConvolveOp.EDGE_NO_OP, null);
    > BufferedImage dest = new BufferedImage(img.getWidth(),
    > img.getHeight(),img.getType());


    Please try just putting BufferedImage.TYPE_INT_ARGB here instead of
    getting the type from the other image and tell us what happens.

    > co.filter(img,dest);
    > return dest;
    > }
    > ...
    > }
    >



    --

    Knute Johnson
    Knute Johnson, Jun 20, 2012
    #6
  7. Re: ImageIO/BufferedImage behaving inconsistently from one day to the next.

    In article <jrrfma$kdq$>, markspace <-@.> wrote:

    > On 6/19/2012 7:31 PM, Fred Greer wrote:
    > > I have code that used to work perfectly, which processes images in
    > > certain ways, and today it suddenly was not working. I hadn't
    > > changed the code at all. I tracked the problem down to spurious
    > > IllegalArgumentExceptions being thrown by this code:
    > >

    > [...]
    > So this is the code you say isn't working? It works for me:
    >
    >
    > package quicktest;
    >
    > import java.awt.image.BufferedImage;
    > import java.awt.image.ConvolveOp;
    > import java.awt.image.Kernel;
    > import javax.imageio.ImageIO;
    >
    > /**
    > *
    > * @author Brenden
    > */
    > public class ConvlPng {
    >
    > public static void main(String[] args)
    > throws Exception
    > {
    > BufferedImage png = ImageIO.read(
    > ConvlPng.class.getResourceAsStream( "conv_test.png" ) );
    > BufferedImage conv = blur( png );
    > System.out.println( conv );
    > }
    >
    >
    > private static float[] BLUR = {0.1111111f, 0.1111111f, 0.1111111f,
    > 0.1111111f, 0.1111111f, 0.1111111f,
    > 0.1111111f, 0.1111111f, 0.1111111f};
    >
    > public static BufferedImage blur (BufferedImage img) {
    > Kernel k = new Kernel(3, 3, BLUR);
    > ConvolveOp co = new ConvolveOp(k, ConvolveOp.EDGE_NO_OP, null);
    > BufferedImage dest = new BufferedImage(img.getWidth(),
    > img.getHeight(),img.getType());
    > co.filter(img,dest);
    > return dest;
    > }
    > }


    I couldn't resist adding a GUI:

    <https://sites.google.com/site/trashgod/convolution>

    and taking a picture:

    <https://sites.google.com/site/trashgod/_/rsrc/1340216139027/convolution/ConvlPng.png>

    --
    John B. Matthews
    trashgod at gmail dot com
    <http://sites.google.com/site/drjohnbmatthews>
    John B. Matthews, Jun 20, 2012
    #7
  8. Fred Greer

    Fred Greer Guest

    Re: ImageIO/BufferedImage behaving inconsistently from one day tothe next.

    On Wed, 20 Jun 2012 01:16:16 -0700, Roedy Green wrote:

    > On Wed, 20 Jun 2012 02:31:00 +0000 (UTC), Fred Greer
    > <> wrote, quoted or indirectly quoted someone who
    > said :
    >
    >>(BufferedImage img

    > did you put in MediaTracker wait code for this to load? If you
    > didn't sometimes you will try to get the size before it loads.


    It's being loaded with ImageIO.read(), which so far as I have been able
    to determine is synchronous. In fact I'm not sure a BufferedImage can
    ever appear to calling code to not be not fully loaded (as opposed to a
    generic Image).
    Fred Greer, Jun 21, 2012
    #8
  9. Fred Greer

    Fred Greer Guest

    Re: ImageIO/BufferedImage behaving inconsistently from one day tothe next.

    On Wed, 20 Jun 2012 08:39:37 -0700, Knute Johnson wrote:

    > On 6/19/2012 7:31 PM, Fred Greer wrote:
    >> I have code that used to work perfectly, which processes images in
    >> certain ways, and today it suddenly was not working. I hadn't changed
    >> the code at all. I tracked the problem down to spurious
    >> IllegalArgumentExceptions being thrown by this code:
    >>
    >> public class ImageUtils {
    >>
    >> private static float[] BLUR = {0.1111111, 0.1111111, 0.1111111,
    >> 0.1111111, 0.1111111, 0.1111111,
    >> 0.1111111, 0.1111111, 0.1111111}
    >> ...
    >> public static BufferedImage blur (BufferedImage img) {
    >> Kernel k = new Kernel(3, 3, BLUR);
    >> ConvolveOp co = new ConvolveOp(k, ConvolveOp.EDGE_NO_OP,
    >> null); BufferedImage dest = new BufferedImage(img.getWidth(),
    >> img.getHeight(),img.getType());

    >
    > Please try just putting BufferedImage.TYPE_INT_ARGB here instead of
    > getting the type from the other image and tell us what happens.


    Are 32-bit PNGs loaded via ImageIO.read guaranteed to be ARGB, or at
    least compatible with ARGB destination images for the purposes of
    ConvolveOp and friends?
    Fred Greer, Jun 21, 2012
    #9
  10. Re: ImageIO/BufferedImage behaving inconsistently from one day tothe next.

    On 6/20/2012 5:23 PM, Fred Greer wrote:
    > On Wed, 20 Jun 2012 08:39:37 -0700, Knute Johnson wrote:
    >
    >> On 6/19/2012 7:31 PM, Fred Greer wrote:
    >>> I have code that used to work perfectly, which processes images in
    >>> certain ways, and today it suddenly was not working. I hadn't changed
    >>> the code at all. I tracked the problem down to spurious
    >>> IllegalArgumentExceptions being thrown by this code:
    >>>
    >>> public class ImageUtils {
    >>>
    >>> private static float[] BLUR = {0.1111111, 0.1111111, 0.1111111,
    >>> 0.1111111, 0.1111111, 0.1111111,
    >>> 0.1111111, 0.1111111, 0.1111111}
    >>> ...
    >>> public static BufferedImage blur (BufferedImage img) {
    >>> Kernel k = new Kernel(3, 3, BLUR);
    >>> ConvolveOp co = new ConvolveOp(k, ConvolveOp.EDGE_NO_OP,
    >>> null); BufferedImage dest = new BufferedImage(img.getWidth(),
    >>> img.getHeight(),img.getType());

    >>
    >> Please try just putting BufferedImage.TYPE_INT_ARGB here instead of
    >> getting the type from the other image and tell us what happens.

    >
    > Are 32-bit PNGs loaded via ImageIO.read guaranteed to be ARGB, or at
    > least compatible with ARGB destination images for the purposes of
    > ConvolveOp and friends?
    >


    I am certainly no expert but I would think that a PNG file would create
    an ARGB image without any problems and I was curious what would happen.

    The other option is to not even create a new image and just convert the
    one you have by putting null destination field.

    --

    Knute Johnson
    Knute Johnson, Jun 21, 2012
    #10
  11. Fred Greer

    Fred Greer Guest

    Re: ImageIO/BufferedImage behaving inconsistently from one day tothe next.

    On Wed, 20 Jun 2012 21:23:35 -0700, Knute Johnson wrote:

    > On 6/20/2012 5:23 PM, Fred Greer wrote:
    >> On Wed, 20 Jun 2012 08:39:37 -0700, Knute Johnson wrote:
    >>
    >>> On 6/19/2012 7:31 PM, Fred Greer wrote:
    >>>> I have code that used to work perfectly, which processes images in
    >>>> certain ways, and today it suddenly was not working. I hadn't changed
    >>>> the code at all. I tracked the problem down to spurious
    >>>> IllegalArgumentExceptions being thrown by this code:
    >>>>
    >>>> public class ImageUtils {
    >>>>
    >>>> private static float[] BLUR = {0.1111111, 0.1111111, 0.1111111,
    >>>> 0.1111111, 0.1111111, 0.1111111,
    >>>> 0.1111111, 0.1111111, 0.1111111}
    >>>> ...
    >>>> public static BufferedImage blur (BufferedImage img) {
    >>>> Kernel k = new Kernel(3, 3, BLUR);
    >>>> ConvolveOp co = new ConvolveOp(k, ConvolveOp.EDGE_NO_OP,
    >>>> null); BufferedImage dest = new
    >>>> BufferedImage(img.getWidth(),
    >>>> img.getHeight(),img.getType());
    >>>
    >>> Please try just putting BufferedImage.TYPE_INT_ARGB here instead of
    >>> getting the type from the other image and tell us what happens.

    >>
    >> Are 32-bit PNGs loaded via ImageIO.read guaranteed to be ARGB, or at
    >> least compatible with ARGB destination images for the purposes of
    >> ConvolveOp and friends?

    >
    > I am certainly no expert but I would think that a PNG file would create
    > an ARGB image without any problems and I was curious what would happen.
    >
    > The other option is to not even create a new image and just convert the
    > one you have by putting null destination field.


    I thought that didn't work, at least for some transformations? At the
    same time, I prefer to minimize mutation and prefer creating new objects.
    There's much less scope for concurrency problems and some other sorts of
    bugs that way, particularly when a single object is used in various
    places and none of them expect it to change because of one of the other
    places.
    Fred Greer, Jun 21, 2012
    #11
  12. Re: ImageIO/BufferedImage behaving inconsistently from one day tothe next.

    On 6/20/2012 9:58 PM, Fred Greer wrote:
    > On Wed, 20 Jun 2012 21:23:35 -0700, Knute Johnson wrote:
    >
    >> On 6/20/2012 5:23 PM, Fred Greer wrote:
    >>> On Wed, 20 Jun 2012 08:39:37 -0700, Knute Johnson wrote:
    >>>
    >>>> On 6/19/2012 7:31 PM, Fred Greer wrote:
    >>>>> I have code that used to work perfectly, which processes images in
    >>>>> certain ways, and today it suddenly was not working. I hadn't changed
    >>>>> the code at all. I tracked the problem down to spurious
    >>>>> IllegalArgumentExceptions being thrown by this code:
    >>>>>
    >>>>> public class ImageUtils {
    >>>>>
    >>>>> private static float[] BLUR = {0.1111111, 0.1111111, 0.1111111,
    >>>>> 0.1111111, 0.1111111, 0.1111111,
    >>>>> 0.1111111, 0.1111111, 0.1111111}
    >>>>> ...
    >>>>> public static BufferedImage blur (BufferedImage img) {
    >>>>> Kernel k = new Kernel(3, 3, BLUR);
    >>>>> ConvolveOp co = new ConvolveOp(k, ConvolveOp.EDGE_NO_OP,
    >>>>> null); BufferedImage dest = new
    >>>>> BufferedImage(img.getWidth(),
    >>>>> img.getHeight(),img.getType());
    >>>>
    >>>> Please try just putting BufferedImage.TYPE_INT_ARGB here instead of
    >>>> getting the type from the other image and tell us what happens.
    >>>
    >>> Are 32-bit PNGs loaded via ImageIO.read guaranteed to be ARGB, or at
    >>> least compatible with ARGB destination images for the purposes of
    >>> ConvolveOp and friends?

    >>
    >> I am certainly no expert but I would think that a PNG file would create
    >> an ARGB image without any problems and I was curious what would happen.
    >>
    >> The other option is to not even create a new image and just convert the
    >> one you have by putting null destination field.

    >
    > I thought that didn't work, at least for some transformations? At the
    > same time, I prefer to minimize mutation and prefer creating new objects.
    > There's much less scope for concurrency problems and some other sorts of
    > bugs that way, particularly when a single object is used in various
    > places and none of them expect it to change because of one of the other
    > places.
    >


    All right then, that's all I've got for you.

    --

    Knute Johnson
    Knute Johnson, Jun 21, 2012
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. F C
    Replies:
    2
    Views:
    5,111
  2. Richard Corfield
    Replies:
    0
    Views:
    3,489
    Richard Corfield
    Mar 4, 2004
  3. Davidski
    Replies:
    0
    Views:
    3,858
    Davidski
    Nov 5, 2004
  4. Andy
    Replies:
    1
    Views:
    668
  5. Zahid
    Replies:
    8
    Views:
    143
    Zahid
    Dec 19, 2005
Loading...

Share This Page