3131import java .util .Iterator ;
3232
3333import javax .imageio .*;
34+ import javax .imageio .metadata .*;
3435
3536
3637/**
@@ -3089,8 +3090,6 @@ protected boolean saveImageIO(String path) throws IOException {
30893090 // JPEG and BMP images that have an alpha channel set get pretty unhappy.
30903091 // BMP just doesn't write, and JPEG writes it as a CMYK image.
30913092 // http://code.google.com/p/processing/issues/detail?id=415
3092- // String lower = path.toLowerCase();
3093- // if (lower.endsWith("bmp") || lower.endsWith("jpg") || lower.endsWith("jpeg")) {
30943093 if (extension .equals ("bmp" ) || extension .equals ("jpg" ) || extension .equals ("jpeg" )) {
30953094 outputFormat = BufferedImage .TYPE_INT_RGB ;
30963095 }
@@ -3100,31 +3099,36 @@ protected boolean saveImageIO(String path) throws IOException {
31003099
31013100 File file = new File (path );
31023101
3102+ ImageWriter writer = null ;
3103+ ImageWriteParam param = null ;
3104+ IIOMetadata metadata = null ;
31033105 if (extension .equals ("jpg" ) || extension .equals ("jpeg" )) {
3104- ImageWriter writer = null ;
3105- Iterator <ImageWriter > iter = ImageIO .getImageWritersByFormatName ("jpeg" );
3106- if (iter .hasNext ()) {
3107- writer = iter .next ();
3108-
3106+ if ((writer = imageioWriter ("jpeg" )) != null ) {
31093107 // Set JPEG quality to 90% with baseline optimization. Setting this
31103108 // to 1 was a huge jump (about triple the size), so this seems good.
3111- // Oddly, a smaller file size than Photoshop at 90%, but it's a
3112- // completely different algorithm, I suppose .
3113- ImageWriteParam param = writer .getDefaultWriteParam ();
3109+ // Oddly, a smaller file size than Photoshop at 90%, but I suppose
3110+ // it's a completely different algorithm.
3111+ param = writer .getDefaultWriteParam ();
31143112 param .setCompressionMode (ImageWriteParam .MODE_EXPLICIT );
31153113 param .setCompressionQuality (0.9f );
3116-
3117- BufferedOutputStream output =
3118- new BufferedOutputStream (new FileOutputStream (file ));
3119- writer .setOutput (ImageIO .createImageOutputStream (output ));
3120- writer .write (null , new IIOImage (bimage , null , null ), param );
3121- writer .dispose ();
3122-
3123- output .flush ();
3124- output .close ();
3125- return true ;
31263114 }
31273115 }
3116+ if ((writer = imageioWriter ("png" )) != null ) {
3117+ param = writer .getDefaultWriteParam ();
3118+ metadata = imageioDPI (writer , param , 100 );
3119+ }
3120+ if (writer != null ) {
3121+ BufferedOutputStream output =
3122+ new BufferedOutputStream (PApplet .createOutput (file ));
3123+ writer .setOutput (ImageIO .createImageOutputStream (output ));
3124+ // writer.write(null, new IIOImage(bimage, null, null), param);
3125+ writer .write (metadata , new IIOImage (bimage , null , metadata ), param );
3126+ writer .dispose ();
3127+
3128+ output .flush ();
3129+ output .close ();
3130+ return true ;
3131+ }
31283132 // If iter.hasNext() somehow fails up top, it falls through to here
31293133 return javax .imageio .ImageIO .write (bimage , extension , file );
31303134
@@ -3135,6 +3139,52 @@ protected boolean saveImageIO(String path) throws IOException {
31353139 }
31363140
31373141
3142+ private ImageWriter imageioWriter (String extension ) {
3143+ Iterator <ImageWriter > iter = ImageIO .getImageWritersByFormatName (extension );
3144+ if (iter .hasNext ()) {
3145+ return iter .next ();
3146+ }
3147+ return null ;
3148+ }
3149+
3150+
3151+ private IIOMetadata imageioDPI (ImageWriter writer , ImageWriteParam param , double dpi ) {
3152+ // http://stackoverflow.com/questions/321736/how-to-set-dpi-information-in-an-image
3153+ ImageTypeSpecifier typeSpecifier =
3154+ ImageTypeSpecifier .createFromBufferedImageType (BufferedImage .TYPE_INT_RGB );
3155+ IIOMetadata metadata =
3156+ writer .getDefaultImageMetadata (typeSpecifier , param );
3157+
3158+ if (!metadata .isReadOnly () && metadata .isStandardMetadataFormatSupported ()) {
3159+ // for PNG, it's dots per millimeter
3160+ double dotsPerMilli = dpi / 25.4 ;
3161+
3162+ IIOMetadataNode horiz = new IIOMetadataNode ("HorizontalPixelSize" );
3163+ horiz .setAttribute ("value" , Double .toString (dotsPerMilli ));
3164+
3165+ IIOMetadataNode vert = new IIOMetadataNode ("VerticalPixelSize" );
3166+ vert .setAttribute ("value" , Double .toString (dotsPerMilli ));
3167+
3168+ IIOMetadataNode dim = new IIOMetadataNode ("Dimension" );
3169+ dim .appendChild (horiz );
3170+ dim .appendChild (vert );
3171+
3172+ IIOMetadataNode root = new IIOMetadataNode ("javax_imageio_1.0" );
3173+ root .appendChild (dim );
3174+
3175+ try {
3176+ metadata .mergeTree ("javax_imageio_1.0" , root );
3177+ return metadata ;
3178+
3179+ } catch (IIOInvalidTreeException e ) {
3180+ System .err .println ("Could not set the DPI of the output image" );
3181+ e .printStackTrace ();
3182+ }
3183+ }
3184+ return null ;
3185+ }
3186+
3187+
31383188 protected String [] saveImageFormats ;
31393189
31403190 /**
0 commit comments