版权声明:转载时请务必保留以下作者信息和链接
作者:陈维(chenweionline@hotmail.com)作者的网站:http://www.chenwei.mobi
通常我们使用Java 编码输出图像默认的图像分辨率是72dpi(关于图像分辨率可以看我转载的一篇文章《图片分辨率介绍》),PC显示器的设备分辨率一般在60~120dpi之间,而熟悉印刷行业的朋友都知道,印刷一张图像需要的图像分辨率一般是300dpi,就是说这样的图像在显示器上显示可能很细腻但是印刷输出的效果却非常粗糙。那么我们针对印刷或者其他需要高分辨率的应用场合,就需要输出更高分辨率的图像,可是纵观Java SE 中标准的ImageIO 库并没有提供设置DPI值的方法,那么怎么使用Java生成适合印刷或者更高分辨率的图像呢?
幸好,JAI_ImageIO 为我们解决了这个难题,或者只能说部分解决。目前JAI_ImageIO_1.1 对于设置DPI 信息的支持仅限于TIFF格式,我并没有在JAI_ImageIO_1.1 中找到针对其他图像格式(例如常见的JPEG)设置DPI 的方法。
JAI_ImageIO_1.1 中对于的TIFF 格式提供了2种途径(DOM 和 API)可以在图像编码时将DPI 信息设置进Meatadata。下面是一段创建图像并且以300dpi 编码输出的样例程序,它分别就这两种方法都做了实现,可以提供大家学习参考。编译运行需要引用JAI_ImageIO_1.1,可以从https://jai-imageio.dev.java.net/下载。
import com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet;
import com.sun.media.imageio.plugins.tiff.TIFFDirectory;
import com.sun.media.imageio.plugins.tiff.TIFFField;
import com.sun.media.imageio.plugins.tiff.TIFFTag;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.FileImageOutputStream;
/** *//**
* 设置自定义dpi值到TIFF格式图像的样例程序。
* 需要 JAI_ImageIO_1.1 提供支持。
*/
public class SetDPI4TIFF ...{
private static String METADATA_NAME = "com_sun_media_imageio_plugins_tiff_image_1.0";
private static int DPI_X = 300;
private static int DPI_Y = 300;
public static void main(String[] args) throws Throwable ...{
// Create sample image.
RenderedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_3BYTE_BGR);
// Get TIFF writer.
Iterator writers = ImageIO.getImageWritersByFormatName("TIFF");
if (writers == null || !writers.hasNext()) ...{
throw new IllegalStateException("No TIFF writers!");
}
ImageWriter writer = (ImageWriter) writers.next();
// Get the default image metadata.
ImageTypeSpecifier imageType = ImageTypeSpecifier.createFromRenderedImage(image);
IIOMetadata imageMetadata = writer.getDefaultImageMetadata(imageType, null);
// Set DPI.
String fileName;
String methodology;
if (args.length == 0 || args[0].equalsIgnoreCase("DOM")) ...{
fileName = "dpi_dom.tif";
setDPIViaDOM(imageMetadata);
methodology = "DOM";
} else ...{
fileName = "dpi_api.tif";
imageMetadata = setDPIViaAPI(imageMetadata);
methodology = "API";
}
System.out.println(" Writing " + fileName + " using " + methodology + " methodology ");
// Write image.
writer.setOutput(new FileImageOutputStream(new File(fileName)));
writer.write(new IIOImage(image, null, imageMetadata));
}
/** *//**
* Set DPI using DOM nodes.
*/
private static void setDPIViaDOM(IIOMetadata imageMetadata) throws IIOInvalidTreeException ...{
// Get the DOM tree.
IIOMetadataNode root = (IIOMetadataNode) imageMetadata.getAsTree(METADATA_NAME);
// Get the IFD.
IIOMetadataNode ifd = (IIOMetadataNode) root.getElementsByTagName("TIFFIFD").item(0);
// Get {X,Y}Resolution tags.
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
TIFFTag tagXRes = base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION);
TIFFTag tagYRes = base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
// Create {X,Y}Resolution nodes.
IIOMetadataNode nodeXRes = createRationalNode(tagXRes.getName(), tagXRes.getNumber(), DPI_X, 1);
IIOMetadataNode nodeYRes = createRationalNode(tagYRes.getName(), tagYRes.getNumber(), DPI_Y, 1);
// Append {X,Y}Resolution nodes to IFD node.
ifd.appendChild(nodeXRes);
ifd.appendChild(nodeYRes);
// Set metadata from tree.
imageMetadata.setFromTree(METADATA_NAME, root);
}
/** *//**
* Creates a node of TIFF data type RATIONAL.
*/
private static IIOMetadataNode createRationalNode(String tagName, int tagNumber, int numerator, int denominator) ...{
// Create the field node with tag name and number.
IIOMetadataNode field = new IIOMetadataNode("TIFFField");
field.setAttribute("name", tagName);
field.setAttribute("number", "" + tagNumber);
// Create the RATIONAL node.
IIOMetadataNode rational = new IIOMetadataNode("TIFFRational");
rational.setAttribute("value", numerator + "/" + denominator);
// Create the RATIONAL node and append RATIONAL node.
IIOMetadataNode rationals = new IIOMetadataNode("TIFFRationals");
rationals.appendChild(rational);
// Append RATIONALS node to field node.
field.appendChild(rationals);
return field;
}
/** *//**
* Set DPI using API.
*/
private static IIOMetadata setDPIViaAPI(IIOMetadata imageMetadata) throws IIOInvalidTreeException ...{
// Derive the TIFFDirectory from the metadata.
TIFFDirectory dir = TIFFDirectory.createFromMetadata(imageMetadata);
// Get {X,Y}Resolution tags.
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
TIFFTag tagXRes = base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION);
TIFFTag tagYRes = base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
// Create {X,Y}Resolution fields.
TIFFField fieldXRes = new TIFFField(tagXRes, TIFFTag.TIFF_RATIONAL, 1, new long[][]...{...{DPI_X, 1}});
TIFFField fieldYRes = new TIFFField(tagYRes, TIFFTag.TIFF_RATIONAL, 1, new long[][]...{...{DPI_Y, 1}});
// Append {X,Y}Resolution fields to directory.
dir.addTIFFField(fieldXRes);
dir.addTIFFField(fieldYRes);
// Convert to metadata object and return.
return dir.getAsMetadata();
}
}
import com.sun.media.imageio.plugins.tiff.TIFFDirectory;
import com.sun.media.imageio.plugins.tiff.TIFFField;
import com.sun.media.imageio.plugins.tiff.TIFFTag;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.FileImageOutputStream;
/** *//**
* 设置自定义dpi值到TIFF格式图像的样例程序。
* 需要 JAI_ImageIO_1.1 提供支持。
*/
public class SetDPI4TIFF ...{
private static String METADATA_NAME = "com_sun_media_imageio_plugins_tiff_image_1.0";
private static int DPI_X = 300;
private static int DPI_Y = 300;
public static void main(String[] args) throws Throwable ...{
// Create sample image.
RenderedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_3BYTE_BGR);
// Get TIFF writer.
Iterator writers = ImageIO.getImageWritersByFormatName("TIFF");
if (writers == null || !writers.hasNext()) ...{
throw new IllegalStateException("No TIFF writers!");
}
ImageWriter writer = (ImageWriter) writers.next();
// Get the default image metadata.
ImageTypeSpecifier imageType = ImageTypeSpecifier.createFromRenderedImage(image);
IIOMetadata imageMetadata = writer.getDefaultImageMetadata(imageType, null);
// Set DPI.
String fileName;
String methodology;
if (args.length == 0 || args[0].equalsIgnoreCase("DOM")) ...{
fileName = "dpi_dom.tif";
setDPIViaDOM(imageMetadata);
methodology = "DOM";
} else ...{
fileName = "dpi_api.tif";
imageMetadata = setDPIViaAPI(imageMetadata);
methodology = "API";
}
System.out.println(" Writing " + fileName + " using " + methodology + " methodology ");
// Write image.
writer.setOutput(new FileImageOutputStream(new File(fileName)));
writer.write(new IIOImage(image, null, imageMetadata));
}
/** *//**
* Set DPI using DOM nodes.
*/
private static void setDPIViaDOM(IIOMetadata imageMetadata) throws IIOInvalidTreeException ...{
// Get the DOM tree.
IIOMetadataNode root = (IIOMetadataNode) imageMetadata.getAsTree(METADATA_NAME);
// Get the IFD.
IIOMetadataNode ifd = (IIOMetadataNode) root.getElementsByTagName("TIFFIFD").item(0);
// Get {X,Y}Resolution tags.
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
TIFFTag tagXRes = base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION);
TIFFTag tagYRes = base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
// Create {X,Y}Resolution nodes.
IIOMetadataNode nodeXRes = createRationalNode(tagXRes.getName(), tagXRes.getNumber(), DPI_X, 1);
IIOMetadataNode nodeYRes = createRationalNode(tagYRes.getName(), tagYRes.getNumber(), DPI_Y, 1);
// Append {X,Y}Resolution nodes to IFD node.
ifd.appendChild(nodeXRes);
ifd.appendChild(nodeYRes);
// Set metadata from tree.
imageMetadata.setFromTree(METADATA_NAME, root);
}
/** *//**
* Creates a node of TIFF data type RATIONAL.
*/
private static IIOMetadataNode createRationalNode(String tagName, int tagNumber, int numerator, int denominator) ...{
// Create the field node with tag name and number.
IIOMetadataNode field = new IIOMetadataNode("TIFFField");
field.setAttribute("name", tagName);
field.setAttribute("number", "" + tagNumber);
// Create the RATIONAL node.
IIOMetadataNode rational = new IIOMetadataNode("TIFFRational");
rational.setAttribute("value", numerator + "/" + denominator);
// Create the RATIONAL node and append RATIONAL node.
IIOMetadataNode rationals = new IIOMetadataNode("TIFFRationals");
rationals.appendChild(rational);
// Append RATIONALS node to field node.
field.appendChild(rationals);
return field;
}
/** *//**
* Set DPI using API.
*/
private static IIOMetadata setDPIViaAPI(IIOMetadata imageMetadata) throws IIOInvalidTreeException ...{
// Derive the TIFFDirectory from the metadata.
TIFFDirectory dir = TIFFDirectory.createFromMetadata(imageMetadata);
// Get {X,Y}Resolution tags.
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
TIFFTag tagXRes = base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION);
TIFFTag tagYRes = base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
// Create {X,Y}Resolution fields.
TIFFField fieldXRes = new TIFFField(tagXRes, TIFFTag.TIFF_RATIONAL, 1, new long[][]...{...{DPI_X, 1}});
TIFFField fieldYRes = new TIFFField(tagYRes, TIFFTag.TIFF_RATIONAL, 1, new long[][]...{...{DPI_Y, 1}});
// Append {X,Y}Resolution fields to directory.
dir.addTIFFField(fieldXRes);
dir.addTIFFField(fieldYRes);
// Convert to metadata object and return.
return dir.getAsMetadata();
}
}