add means for setting image resolution when saving

This commit is contained in:
Ben Fry
2013-05-04 10:08:36 -04:00
parent 006ea4d340
commit 4504b8b277
2 changed files with 83 additions and 20 deletions

View File

@@ -31,6 +31,7 @@ import java.lang.reflect.Method;
import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.metadata.*;
/**
@@ -3089,8 +3090,6 @@ public class PImage implements PConstants, Cloneable {
// JPEG and BMP images that have an alpha channel set get pretty unhappy.
// BMP just doesn't write, and JPEG writes it as a CMYK image.
// http://code.google.com/p/processing/issues/detail?id=415
// String lower = path.toLowerCase();
// if (lower.endsWith("bmp") || lower.endsWith("jpg") || lower.endsWith("jpeg")) {
if (extension.equals("bmp") || extension.equals("jpg") || extension.equals("jpeg")) {
outputFormat = BufferedImage.TYPE_INT_RGB;
}
@@ -3100,31 +3099,36 @@ public class PImage implements PConstants, Cloneable {
File file = new File(path);
ImageWriter writer = null;
ImageWriteParam param = null;
IIOMetadata metadata = null;
if (extension.equals("jpg") || extension.equals("jpeg")) {
ImageWriter writer = null;
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg");
if (iter.hasNext()) {
writer = iter.next();
if ((writer = imageioWriter("jpeg")) != null) {
// Set JPEG quality to 90% with baseline optimization. Setting this
// to 1 was a huge jump (about triple the size), so this seems good.
// Oddly, a smaller file size than Photoshop at 90%, but it's a
// completely different algorithm, I suppose.
ImageWriteParam param = writer.getDefaultWriteParam();
// Oddly, a smaller file size than Photoshop at 90%, but I suppose
// it's a completely different algorithm.
param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.9f);
BufferedOutputStream output =
new BufferedOutputStream(new FileOutputStream(file));
writer.setOutput(ImageIO.createImageOutputStream(output));
writer.write(null, new IIOImage(bimage, null, null), param);
writer.dispose();
output.flush();
output.close();
return true;
}
}
if ((writer = imageioWriter("png")) != null) {
param = writer.getDefaultWriteParam();
metadata = imageioDPI(writer, param, 100);
}
if (writer != null) {
BufferedOutputStream output =
new BufferedOutputStream(PApplet.createOutput(file));
writer.setOutput(ImageIO.createImageOutputStream(output));
// writer.write(null, new IIOImage(bimage, null, null), param);
writer.write(metadata, new IIOImage(bimage, null, metadata), param);
writer.dispose();
output.flush();
output.close();
return true;
}
// If iter.hasNext() somehow fails up top, it falls through to here
return javax.imageio.ImageIO.write(bimage, extension, file);
@@ -3135,6 +3139,52 @@ public class PImage implements PConstants, Cloneable {
}
private ImageWriter imageioWriter(String extension) {
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(extension);
if (iter.hasNext()) {
return iter.next();
}
return null;
}
private IIOMetadata imageioDPI(ImageWriter writer, ImageWriteParam param, double dpi) {
// http://stackoverflow.com/questions/321736/how-to-set-dpi-information-in-an-image
ImageTypeSpecifier typeSpecifier =
ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
IIOMetadata metadata =
writer.getDefaultImageMetadata(typeSpecifier, param);
if (!metadata.isReadOnly() && metadata.isStandardMetadataFormatSupported()) {
// for PNG, it's dots per millimeter
double dotsPerMilli = dpi / 25.4;
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
horiz.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
vert.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
dim.appendChild(horiz);
dim.appendChild(vert);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
root.appendChild(dim);
try {
metadata.mergeTree("javax_imageio_1.0", root);
return metadata;
} catch (IIOInvalidTreeException e) {
System.err.println("Could not set the DPI of the output image");
e.printStackTrace();
}
}
return null;
}
protected String[] saveImageFormats;
/**

View File

@@ -12,6 +12,12 @@ X getFloatContent()
X getContent() or getStringContent()?
X switch to CATEGORY instead of CATEGORICAL
X removed createXML() and createTable()... just use 'new' for these
X implement means for setting dpi in PNG images
X need to add something for API yet
o JAI handles setting image size for png (check javax.imageio?)
o PNGEncodeParam png = PNGEncodeParam.getDefaultEncodeParam(bufImage);
o png.setPhysicalDimension(round(dpi*39.370079), round(dpi*39.370079), 1);
o JAI.create("filestore", bufImage, filename+".png", "PNG");
mouse wheel
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
X http://docs.oracle.com/javase/6/docs/api/java/awt/event/MouseWheelEvent.html#getWheelRotation()
X http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseWheelEvent.html#getWheelRotation()
_ add options for image.save() (or sageImage?)
_ add quality=[0,1] for jpeg images
_ add dpi=[0,n] for for png images
_ PImage.loadPixels() shouldn't be calling out to the renderer
_ setting image.parent = null for it makes it work again for get().save() case
_ PShape should be cached as well
before release
_ "deleted n framebuffer objects"