8

When I save this image:

Holiday Doodle

with this method:

private final static Path ROOT_PATH = Paths.getPath("C:/images");

private static void saveImageFromWebSimple(final String url) {
    URL u = null;
    try {
        u = new URL(url);
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    String file = url.substring(url.indexOf("//") + 2);
    Path filePath = ROOT_PATH.resolve(file);
    try {
        Files.createDirectories(filePath.getParent());
        BufferedImage img = ImageIO.read(u);
        ImageIO.write(img, "jpg", filePath.toFile());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

this is my result:

Result

This doesn't happen with all pictures though.

Can you tell me why?

Franz Ebner
  • 4,951
  • 3
  • 39
  • 57
  • 1) `ImageIO.write(img, "jpg", filePath.toFile());` JPEG is not guaranteed to preserve the *exact* colors, but I think that goes beyond what it usually alters them. 2) If downloading it, just save it 'byte for byte' rather than using `ImageIO` (for either read *or* write). – Andrew Thompson Dec 26 '13 at 17:58
  • 1
    If loading that image using `ImageIO` & displaying it directly (without any saving to disk involved), we can see the same result. I've seen this before, but have forgotten the reason and therefore am having trouble finding for the answer.. – Andrew Thompson Dec 26 '13 at 18:05
  • Seems so. I've done a research before asking this Q but have not found that. I linked to this Q from the original to get more attention because it's not really closed imho. – Franz Ebner Dec 26 '13 at 18:23
  • *"it's not really imho."* It's not really what? – Andrew Thompson Dec 26 '13 at 18:26

1 Answers1

9

According to @uckelman's comment on this post, Java's decoder makes a different assumption about the format of the image than most other renders when the image is missing the JFIF header:

I believe the answer to your question of how to detect the bad JPEGs is found here and here. What you have is a JPEG with no JFIF marker. All other image loaders assume that the data is YCbCr in that case, except for ImageIO, which assumes that it is RGB when channels 1 and 2 are not subsampled. So, check whether the first 4 bytes are FF D8 FF E1, and if so, whether channels 1 and 2 are subsampled. That's the case where you need to convert.

Community
  • 1
  • 1
antiduh
  • 11,853
  • 4
  • 43
  • 66
  • Thanks antiduh but PLEASE vote up @uckleman 's comment as well! – Franz Ebner Dec 26 '13 at 18:38
  • 3
    I added this to the other answer, but in case somebody stumbles across it here: I was running into this issue, and I actually found a third party library that handled this for me. https://github.com/haraldk/TwelveMonkeys Literally all I had to do was include this in my maven dependencies and the jpegs that were coming out in weird colors started getting read in normally. I didn't even have to change a line of code. – James Fiala Feb 18 '16 at 18:48
  • I'd heartily second @JamesFiala's comment - after reading that I gave it a go in my Clojure project and it fixed my issue a treat. A very straightforward solution. Thanks James! – Rob Murphy Feb 17 '17 at 13:12