United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-5028259 : Setting of destination image type for jpeg image increase size of result.

Details
Type:
Bug
Submit Date:
2004-04-07
Status:
Resolved
Updated Date:
2004-09-07
Project Name:
JDK
Resolved Date:
2004-09-07
Component:
client-libs
OS:
generic
Sub-Component:
javax.imageio
CPU:
generic
Priority:
P4
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports

Sub Tasks

Description

Name: abR10136			Date: 04/07/2004


 If we explicitly use the write param with destination type to write image as
 jpeg then the size of the result file is bigger than if same
 destination type is used implicitly.

 Expected result: size of result should not depend on the way of
   selecting destination type. For identical image write params we must get
   identical sizes.

 Testcase from comments section could be used to reproduce the problem
  (note that created files sizes are different.
   For instance for test/javax/imageio/images/VancouverIsland200.jpg
   - sizes are 18156 bytes and 7460 bytes).


======================================================================

                                    

Comments
WORK AROUND



Name: abR10136			Date: 04/13/2004


  Usage of metadata object and explicitly specified destination type
  helps to avoid major increase of size. Result still will be bigger
  than optimal but this is less noticeable.

=================== BEGIN OF WORKAROUND EXAMPLE ======================
import java.awt.image.BufferedImage;
import java.awt.Graphics;
import javax.imageio.ImageIO;
import javax.imageio.IIOImage;
import javax.imageio.ImageWriter;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.event.IIOWriteWarningListener;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.metadata.IIOInvalidTreeException;
import java.io.File;
import java.io.IOException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Workaround implements  IIOWriteWarningListener {
    public static void main(String[] args) throws IOException {
        BufferedImage bi = ImageIO.read(new File(args[0]));

        BufferedImage bi_argb = new BufferedImage(bi.getWidth(),
                                                  bi.getHeight(),
                                                  BufferedImage.TYPE_INT_ARGB);

        Graphics g = bi_argb.createGraphics();
        g.drawImage(bi, 0, 0, null);


        ImageWriter iw =
            (ImageWriter)ImageIO.getImageWritersByFormatName("jpeg").next();
        iw.addIIOWriteWarningListener(new Workaround());

        ImageWriteParam p =  iw.getDefaultWriteParam();
        ImageTypeSpecifier type =
            ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
        p.setDestinationType(type);
        p.setSourceBands(new int[] {0, 1, 2});

        ImageOutputStream ios =
            ImageIO.createImageOutputStream(new File("Workaround.jpeg"));
        iw.setOutput(ios);
        System.out.println("create metadata");
        IIOMetadata meta = iw.getDefaultImageMetadata(type, null);

        meta = addAdobeTransform(meta);

        iw.write(null,
                 new IIOImage(bi.getData(), null, meta),
                 p);
        ios.close();

    }
    public void warningOccurred(ImageWriter source,
                                int imageIndex,
                                String warning) {
        System.out.println("WRITING WARNING: " + warning);
    }

    private static IIOMetadata addAdobeTransform(IIOMetadata meta) throws  IIOInvalidTreeException {
        // add the adobe transformation (transform 1 -> to YCbCr)
        Node root = meta.getAsTree("javax_imageio_jpeg_image_1.0");


        NodeList nlist = root.getChildNodes();
        Node markerSequence = getChildNode(root, "markerSequence");
        if (markerSequence == null) {
            throw new RuntimeException("Invalid metadata!");
        }

        IIOMetadataNode adobeTransform = getChildNode(markerSequence, "app14Adobe");
        if (adobeTransform == null) {
            adobeTransform = new IIOMetadataNode("app14Adobe");
            adobeTransform.setAttribute("transform" , "1"); // convert RGB to YCbCr
            adobeTransform.setAttribute("version", "101");
            adobeTransform.setAttribute("flags0", "0");
            adobeTransform.setAttribute("flags1", "0");

            markerSequence.appendChild(adobeTransform);
        } else {
            adobeTransform.setAttribute("transform" , "1");
        }

        meta.setFromTree("javax_imageio_jpeg_image_1.0", root);
        return meta;
    }

    private static IIOMetadataNode getChildNode(Node p, String name) {
        NodeList nlist = p.getChildNodes();
        for (int i=0; i<nlist.getLength(); i++) {
            Node n = nlist.item(i);
            if (name.equals(n.getNodeName())) {
                return (IIOMetadataNode)n;
            }
        }
        return null;
    }
}
==================== END OF WORKAROUND EXAMPLE =======================
                                     
2004-09-08
EVALUATION



Name: abR10136			Date: 04/08/2004


 The problem has place if destination type is specified but
 corresponding metadata object is not specified.

 By default ImageIO jpeg writer uses only one of Qtables (setting
 QtableSelectors elements to 0 (default value)).
 Default QtableSelectors values updated later using given metadata
 object. If metadata was not specified then  it is created using
 information from buffered image (aka "full image" case).

 At the moment if the destination type is specified it means that
 we use only raster data or some subset of bands from the source
 image. In this case the metadata is not created and we have no way
 to change the default values of QtableSelectors. This causes worse
 level of compression (i.e. bigger result) comparing to case when
 metadata object is created ourselves.

 The idea of the proposed fix is to create the metadata object
 using given destination type in order to build SOF marker object,
 which will be used to change default values of the QtableSelectors
 (similar to how it is done for the "full image" case).

======================================================================
                                     
2004-09-08
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
mustang

FIXED IN:
mustang

INTEGRATED IN:
mustang


                                     
2004-09-08



Hardware and Software, Engineered to Work Together