Thorben Auer
Thorben Auer

Reputation: 51

How to show a 65687x70562 Tif File in Java

I try to show an 500 MB Tif File in an Java GUI.

My problem is: Dimensions (width=65687 height=70562) are too large

I'm already using the JAI Libary (Codec 1.1.3 & Core 1.1.3) to load the file.

static Image load(byte[] data) throws Exception {
    Image image = null;
    SeekableStream stream = new ByteArraySeekableStream(data);
    String[] names = ImageCodec.getDecoderNames(stream);
    ImageDecoder dec = ImageCodec.createImageDecoder(names[0], stream, null);
    RenderedImage im = dec.decodeAsRenderedImage();
    image = PlanarImage.wrapRenderedImage(im).getAsBufferedImage();
    return image;
}

public static void main(String[] args) throws Exception{
    String path;
    if (args.length==0) {
      path = JOptionPane.showInputDialog(null, "Image Path",
      "c:/applications/sidebar.tif");
    }
    else {
      path = args[0];
    }
    FileInputStream in = new FileInputStream(path);
    FileChannel channel = in.getChannel();
    ByteBuffer buffer = ByteBuffer.allocate((int)channel.size());
    channel.read(buffer);
    Image image = load(buffer.array());
    // make sure that the image is not too big
    //  scale with a width of 500 
    Image imageScaled = 
      image.getScaledInstance(500, -1,  Image.SCALE_SMOOTH);
    //
    System.out.println("image: " + path + "\n" + image);
    //
    JOptionPane.showMessageDialog(null, new JLabel(
        new ImageIcon( imageScaled )) );
  }

I just want to see the whole Image in a Frame.

UPDATE

I'm using JAVA 11 now.

But i got an new problem

java.lang.IllegalArgumentException: width*height > Integer.MAX_VALUE! at java.desktop/javax.imageio.ImageReader.getDestination(ImageReader.java:2821) at java.desktop/com.sun.imageio.plugins.tiff.TIFFImageReader.read(TIFFImageReader.java:1141) at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1468) at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1420) at list.ImageView.<init>(ImageView.java:26) at gui.GUI_Cut.<init>(GUI_Cut.java:61) at gui.GUI_Main$3$1.run(GUI_Main.java:139) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

My Code:

image = ImageIO.read(getClass().getResource("/images/" + filename));

I'm loading the large tif image.

Upvotes: 3

Views: 432

Answers (1)

VGR
VGR

Reputation: 44414

ImageIO is able to read some images one rectangular sub-area at a time. Each such rectangle is known as a tile.

I experimented with a few TIFF images, and found that ImageIO was willing to read each of them as tiles. I don’t know whether this is guaranteed to be the case for every TIFF image.

We can create the less memory-hungry scaled image (using the ColorModel and Raster format of the first tile we encounter), then draw each tile directly into that scaled image:

public BufferedImage readLargeImage(File file,
                                    int desiredWidth)
throws IOException {

    BufferedImage scaledImage = null;
    Graphics2D scaledImageGraphics = null;

    ImageReader tiffReader =
        ImageIO.getImageReadersByFormatName("TIFF").next();

    try (ImageInputStream stream = ImageIO.createImageInputStream(file)) {
        tiffReader.setInput(stream);

        int width = tiffReader.getWidth(0);
        int height = tiffReader.getHeight(0);

        int tileWidth = tiffReader.getTileWidth(0);
        int tileHeight = tiffReader.getTileHeight(0);

        int scaledWidth = desiredWidth;
        float scale = (float) scaledWidth / width;

        for (int tileY = 0; tileY * tileHeight < height; tileY++) {
            for (int tileX = 0; tileX * tileWidth < width; tileX++) {
                BufferedImage tile = tiffReader.readTile(0, tileX, tileY);

                if (scaledImage == null) {
                    scaledImage = new BufferedImage(
                        tile.getColorModel(),
                        tile.getRaster().createCompatibleWritableRaster(
                            scaledWidth,
                            (int) (scale * height)),
                        false, new Properties());
                    scaledImageGraphics = scaledImage.createGraphics();

                    // Optional: better scaling
                    scaledImageGraphics.setRenderingHint(
                        RenderingHints.KEY_RENDERING,
                        RenderingHints.VALUE_RENDER_QUALITY);
                    scaledImageGraphics.setRenderingHint(
                        RenderingHints.KEY_INTERPOLATION,
                        RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                }

                scaledImageGraphics.drawImage(tile,
                    (int) (scale * tileX * tileWidth),
                    (int) (scale * tileY * tileHeight), 
                    (int) (scale * tileWidth),
                    (int) (scale * tileHeight),
                    null);
            }
        }
    }

    scaledImageGraphics.dispose();

    return scaledImage;
}

Upvotes: 1

Related Questions