Skip to content

Commit d112922

Browse files
committed
add means for setting image resolution when saving
1 parent 8a74cb2 commit d112922

2 files changed

Lines changed: 83 additions & 20 deletions

File tree

core/src/processing/core/PImage.java

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.Iterator;
3232

3333
import 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
/**

core/todo.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ X getFloatContent()
1212
X getContent() or getStringContent()?
1313
X switch to CATEGORY instead of CATEGORICAL
1414
X removed createXML() and createTable()... just use 'new' for these
15+
X implement means for setting dpi in PNG images
16+
X need to add something for API yet
17+
o JAI handles setting image size for png (check javax.imageio?)
18+
o PNGEncodeParam png = PNGEncodeParam.getDefaultEncodeParam(bufImage);
19+
o png.setPhysicalDimension(round(dpi*39.370079), round(dpi*39.370079), 1);
20+
o JAI.create("filestore", bufImage, filename+".png", "PNG");
1521

1622
mouse wheel
1723
X add mouse wheel support to 2.0 event system
@@ -44,6 +50,13 @@ X ref: "negative values if the mouse wheel was rotated up or away from the use
4450
X http://docs.oracle.com/javase/6/docs/api/java/awt/event/MouseWheelEvent.html#getWheelRotation()
4551
X http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseWheelEvent.html#getWheelRotation()
4652

53+
_ add options for image.save() (or sageImage?)
54+
_ add quality=[0,1] for jpeg images
55+
_ add dpi=[0,n] for for png images
56+
57+
_ PImage.loadPixels() shouldn't be calling out to the renderer
58+
_ setting image.parent = null for it makes it work again for get().save() case
59+
_ PShape should be cached as well
4760

4861
before release
4962
_ "deleted n framebuffer objects"

0 commit comments

Comments
 (0)