使用imageio-jpeg写入CMYK图像时元数据被忽略的问题咨询
解决imageio-jpeg写入CMYK图像时保留DPI的问题
由于com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageWriter#writeCMYK方法会忽略传入的元数据,转而使用delegate的默认元数据,你可以通过以下两种方式解决:
方法一:直接使用底层Delegate Writer
twelvemonkeys的JPEGImageWriter包装了JDK默认的JPEGImageWriter,直接操作这个delegate可以确保元数据被正确应用:
// 获取twelvemonkeys writer对应的底层delegate JPEGImageWriter delegate = (JPEGImageWriter) writer.getOriginatingProvider().createWriterInstance(); delegate.setOutput(output); // 从原图元数据中提取包含DPI的标记序列 IIOMetadataNode originalRoot = (IIOMetadataNode) imageMetadata.getAsTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0); IIOMetadataNode markerSequence = (IIOMetadataNode) originalRoot.getElementsByTagName("markerSequence").item(0); // 构造目标元数据并合并原图的标记序列(包含DPI) IIOMetadata metadata = delegate.getDefaultImageMetadata(new ImageTypeSpecifier(image), param); metadata.mergeTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0, originalRoot); try { // 直接调用delegate的write方法写入CMYK图像 delegate.write(null, new IIOImage(im, null, metadata), param); } finally { delegate.dispose(); output.flush(); }
方法二:手动构造包含DPI的元数据树
如果不想直接操作delegate,可以手动构造包含DPI信息的APP1(Exif)标记,合并到元数据中:
// 构造包含DPI的Exif APP1标记节点 IIOMetadataNode app1Marker = new IIOMetadataNode("app1Marker"); // 生成包含300DPI的Exif字节数据(需实现createExifWithDPI方法) byte[] exifData = createExifWithDPI(300, 300); app1Marker.setAttribute("data", Base64.getEncoder().encodeToString(exifData)); // 构建完整的元数据树 IIOMetadataNode root = new IIOMetadataNode(JAVAX_IMAGEIO_JPEG_IMAGE_1_0); root.appendChild(new IIOMetadataNode("JPEGVariety")); IIOMetadataNode markerSeq = new IIOMetadataNode("markerSequence"); markerSeq.appendChild(app1Marker); root.appendChild(markerSeq); // 合并到writer的元数据中 IIOMetadata metadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(image), param); metadata.mergeTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0, root); writer.setOutput(output); try { writer.write(null, new IIOImage(im, null, metadata), param); } finally { writer.dispose(); output.flush(); } // 辅助方法:生成包含指定DPI的Exif数据(可借助metadata-extractor库简化实现) private static byte[] createExifWithDPI(int dpiX, int dpiY) throws IOException { ExifWriter exifWriter = new ExifWriter(); exifWriter.setTag(ExifDirectoryBase.TAG_X_RESOLUTION, new Rational(dpiX, 1)); exifWriter.setTag(ExifDirectoryBase.TAG_Y_RESOLUTION, new Rational(dpiY, 1)); exifWriter.setTag(ExifDirectoryBase.TAG_RESOLUTION_UNIT, 2); // 单位为英寸 ByteArrayOutputStream baos = new ByteArrayOutputStream(); exifWriter.write(baos); return baos.toByteArray(); }
说明
- 方法一更简洁,直接绕开twelvemonkeys的writeCMYK方法的元数据忽略逻辑;
- 方法二需要处理Exif字节流的构造,若不想引入第三方库,也可以手动拼接符合Exif规范的字节数组,但实现较繁琐。
内容的提问来源于stack exchange,提问作者david
相关产品推荐
相关产品推荐

