13

In my code, I have a BufferedImage that was loaded with the ImageIO class like so:

BufferedImage image = ImageIO.read(new File (filePath);

Later on, I want to save it to a byte array, but the ImageIO.write method requires me to pick either a GIF, PNG, or JPG format to write my image as (as described in the tutorial here).

I want to pick the same file type as the original image. If the image was originally a GIF, I don't want the extra overhead of saving it as a PNG. But if the image was originally a PNG, I don't want to lose translucency and such by saving it as a JPG or GIF. Is there a way that I can determine from the BufferedImage what the original file format was?

I'm aware that I could simply parse the file path when I load the image to find the extension and just save it for later, but I'd ideally like a way to do it straight from the BufferedImage.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Thunderforge
  • 19,637
  • 18
  • 83
  • 130
  • Muhaha, enjoy the [alpha channel](http://stackoverflow.com/questions/4386446). – Markus Malkusch Jan 11 '14 at 13:00
  • You can access the image type and create a `BufferedImage` using an `InputStream` and `ImageIO`. Just convert the `File` to an `InputStream` first. See my answer here: http://stackoverflow.com/a/36770963/1625820 – herrtim Apr 21 '16 at 13:26

3 Answers3

12

As @JarrodRoberson says, the BufferedImage has no "format" (i.e. no file format, it does have one of several pixel formats, or pixel "layouts"). I don't know Apache Tika, but I guess his solution would also work.

However, if you prefer using only ImageIO and not adding new dependencies to your project, you could write something like:

ImageInputStream input = ImageIO.createImageInputStream(new File(filePath));

try {
    Iterator<ImageReader> readers = ImageIO.getImageReaders(input);

    if (readers.hasNext()) {
        ImageReader reader = readers.next();

        try {
            reader.setInput(input);

            BufferedImage image = reader.read(0);  // Read the same image as ImageIO.read

            // Do stuff with image...

            // When done, either (1):
            String format = reader.getFormatName(); // Get the format name for use later
            if (!ImageIO.write(image, format, outputFileOrStream)) {
                // ...handle not written
            }
            // (case 1 done)

            // ...or (2):
            ImageWriter writer = ImageIO.getImageWriter(reader); // Get best suitable writer

            try {
                ImageOutputStream output = ImageIO.createImageOutputStream(outputFileOrStream);

                try {
                    writer.setOutput(output);
                    writer.write(image);
                }
                finally {
                    output.close();
                }
            }
            finally {
                writer.dispose();
            }
            // (case 2 done)
        }
        finally {
            reader.dispose();
        }
    }
}
finally {
    input.close();
}
Harald K
  • 26,314
  • 7
  • 65
  • 111
  • 3
    Choosing this one as the asnwer because, although Tika may be more reliable, I don't care to add a 25 MB dependency so this is ultimately a better solution for me and I'm alright with "reliable enough". Thanks! – Thunderforge Jan 16 '14 at 15:19
7

BufferedImage does not have a "format"

Once the bytes have been translated into a BufferedImage the format of the source file is completely lost, the contents represent a raw byte array of the pixel information nothing more.

Solution

You should use the Tika library to determine the format from the original byte stream before the BufferedImage is created and not rely on file extensions which can be inaccurate.

Community
  • 1
  • 1
1

One could encapsulate the BufferedImage and related data in class instance(s) like so:

final public class TGImage
{

  public String naam;
  public String filename;
  public String extension;    
  public int layerIndex;
  public Double scaleX;
  public Double scaleY;
  public Double rotation;
  public String status;
  public boolean excluded;

  public BufferedImage image;


  public ArrayList<String> history = new ArrayList<>(5);

  public TGImage()
  {
    naam = "noname";
    filename = "";
    extension ="";
    image = null;
    scaleX = 0.0;
    scaleY = 0.0;
    rotation = 0.0;
    status = "OK";
    excluded = false;
    layerIndex = 0;
    addHistory("Created");
  }

  final public void addHistory(String str)
  {
    history.add(TGUtil.getCurrentTimeStampAsString() + " " + str);
  }
}

and then use it like this:

public TGImage loadImage()
    {
        TGImage imgdat = new TGImage();

        final JFileChooser fc = new JFileChooser();
        FileNameExtensionFilter filter = new FileNameExtensionFilter("Image Files", "jpg", "png", "gif", "tif");
        fc.setFileFilter(filter);
        fc.setCurrentDirectory(new File(System.getProperty("user.home")));

        int result = fc.showOpenDialog(this);  // show file chooser

        if (result == JFileChooser.APPROVE_OPTION)
        {
            File file = fc.getSelectedFile();
            System.out.println("Selected file extension is " + TGUtil.getFileExtension(file));

            if (TGUtil.isAnImageFile(file))
            {
                //System.out.println("This is an Image File.");

                try
                {
                    imgdat.image = ImageIO.read(file);
                    imgdat.filename = file.getName();
                    imgdat.extension = TGUtil.getFileExtension(file); 

                    info("image has been loaded from file:" + imgdat.filename);

                } catch (IOException ex)
                {
                    Logger.getLogger(TGImgPanel.class.getName()).log(Level.SEVERE, null, ex);
                    imgdat.image = null;
                    info("File not loaded IOexception: img is null");
                }

            } else
            {
                imgdat = null;
                info("File not loaded: The requested file is not an image File.");
            }
        }
        return imgdat;
    }

Then you have everything relevant together in TGImage instance(s). and perhaps use it in an imagelist like so:

ArrayList<TGImage> images = new ArrayList<>(5);
Ted van Gaalen
  • 1,159
  • 8
  • 5