如何在 java 中将 .jpeg 图像转换为 .jif? (EXIF TO JFIF)
How to convert .jpeg image to .jif in java? (Exif TO JFIF)
客户要求我发送 .JIF 格式 (JFIF) 的图像。我有 java 应用程序,但我无法 google 了解如何转换为该图像类型的主题,我什至几乎 google 无法了解“.JIF”格式本身。
已编辑:
有人可以建议如何在 java 中将 Exif 图像转换为 JFIF 吗?以及如何给这个 JFIF 图片添加评论?
(尝试使用 jheader 库不幸以 nullpointer 异常结束,google 上没有更多选择。)
首先您需要读取该图像,然后您必须将该图像写入您想要的尺寸和格式。
您必须使用 ImageIO class 和 BufferedReader 来读取图像
要编写它们,请使用 Graphics2D class
将格式名称替换为 jif
File inputFile = new File(inputImagePath);
BufferedImage inputImage = ImageIO.read(inputFile);
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth,
scaledHeight, inputImage.getType());
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// extracts extension of output file
String formatName = outputImagePath.substring(outputImagePath
.lastIndexOf(".") + 1);
// writes to output file
ImageIO.write(outputImage, formatName, new File(outputImagePath));
编辑:将 Exif JPEG 转换为 JFIF JPEG:
如果您不介意损失一些质量(由于有损 JPEG 重新编码),您可以像这样简单地转换图像:
File inFile = ...;
File outFile = ...; // Feel free to use ".jif" as extension
if (!ImageIO.write(ImageIO.read(inFile), "JPEG", outFile)) {
System.err.println("Could not write JPEG format"); // Should never happen
}
这会起作用,因为默认的 JPEGImageWriter
插件只支持 JFIF 格式。而且因为我们不读取元数据,所以旧的 Exif 信息将丢失。但是,这样做将不允许您添加评论。
要添加评论,您仍然可以使用标准 ImageIO API,但我们必须访问元数据,从而使代码更加冗长。有关元数据格式的更多信息,请参阅 JPEG Metadata Format Specification。如果您需要从 Exif 元数据转换注释,请将您的问题更新为具体说明,因为它需要进一步解析元数据和 ImageIO 当前不支持的额外支持 API。
File inFile = ...;
File outFile = ...; // Feel free to use ".jif" as extension
BufferedImage image = ImageIO.read(inFile);
ImageWriter jpegWriter = ImageIO.getImageWritersByFormatName("JPEG").next(); // Should be a least one
// To write comments, we need to add it to the metadata
ImageWriteParam param = jpegWriter.getDefaultWriteParam();
IIOMetadata metadata = jpegWriter.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), param);
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree("javax_imageio_jpeg_image_1.0");
IIOMetadataNode markerSequence = (IIOMetadataNode) root.getElementsByTagName("markerSequence").item(0); // Should be only one
// Insert a "COM" marker, with our comment
IIOMetadataNode com = new IIOMetadataNode("com");
com.setAttribute("comment", "Hello JFIF!");
markerSequence.appendChild(com);
// Merge edited metadata
metadata.mergeTree("javax_imageio_jpeg_image_1.0", root);
ImageOutputStream output = ImageIO.createImageOutputStream(outFile);
try {
jpegWriter.setOutput(output);
// Write image along with metadata
jpegWriter.write(new IIOImage(image, null, metadata));
}
finally {
output.close();
}
jpegWriter.dispose();
这样,我们仍然以有损 JPEG 格式重新编码图像,但我们将 Exif 转换为 JFIF 并添加注释。
现在,还有另一种选择,可以做到完全无损。但它确实需要对 JIF 段结构以及 Exif 和 JFIF 格式的工作原理有更深入的了解。不幸的是,没有标准 Java API(据我所知)可以做到这一点,因此您将不得不自己动手。随意使用我的 JPEG segment parsing code as a starting point. The JHeader 你链接的项目看起来也很有前途,但我没有使用这个库的任何经验,所以我不能在那里提供任何建议。
基本思路如下:
- Parse/skip标记段直到SOS(扫描开始)段(SOS之后的数据将是压缩图像数据)。
- 写入 SOI 标记 (
0xffd8
)
- 创建一个 APP0/"JFIF" 标记(我想你可以在这里使用默认值,详情请参阅 JFIF segment)。 thumb dimensions 可以写0, 0, 略写thumbnail data.
- 添加您的 COM 段以及您需要的任何注释(可能从 Exif 元数据中提取)
- 按原样从原始流中写入 SOF、DHT、DQT 等标准段(跳过 APP1/"Exif" 和其他 "custom" 段)。
- 从原始流中写入 SOS 标记和图像数据
理论上,这应该可行。您可能有一些小的颜色 space 问题,因为 Exif 数据可能包含不同的颜色 space(通常是 sRGB 或 AdobeRGB1998),而 JFIF doesn't have a defined color space。如果您需要此功能,请添加具有所需配置文件的 APP2/"ICC_PROFILE" 段(在第 3 步之后)。
祝你好运! :-)
注意:这不是一个完整的答案,而是试图澄清为什么您需要与您的客户交谈,并弄清楚您的 JPEG 有什么问题以及他 "JIF" 的实际含义。
首先,JPEG 不是一种文件格式。 JPEG 是静止图像压缩标准。该标准的一部分(通常称为 "Annex B")是对交换格式的描述,有时称为 JIF。该标准还指定了一种称为 SPIFF 的完整文件格式,但这种格式并不是很普遍(我认为这不是你想要的)。
你随处找到的文件,称为 "JPEG files"(我假设这就是你所说的 "Classic JPEG"),通常是基本相同的两种略有不同的风格之一文件格式:
最基本的格式是JFIF。此格式以 SOI 标记开头,紧接着是一个以 "JFIF"(空终止)作为其标识符的 APP0 标记。根据规范的 original JFIF specification "The JPEG File Interchange Format is entirely compatible with the standard JPEG interchange format; the only additional requirement is the mandatory presence of the APP0 marker right after the SOI marker." (this part is left out of the ITU 和 ISO 版本,但仍然适用)。简而言之,JFIF 将 JPEG 数据限制为 1 或 3 个分量,编码为 Y 或 YCbCr,并强烈推荐基线 DCT、霍夫曼编码压缩。
另一种常见格式是Exif。此格式以 SOI 标记开头,紧接着是一个以 "Exif"(空终止)作为其标识符的 APP1 标记。这种格式由数码相机制造商开发,允许在文件中记录更丰富的元数据(以 TIFF 元数据结构的形式)。据我了解,Exif 将 JPEG 数据限制为 3 个分量,编码为 YCbCr,使用基线 DCT,霍夫曼编码压缩(最后一部分可能只是互操作性建议,规范中的语言有点难以阅读。 ..).
这两种格式都包含相同的 "segment" 布局并且图像数据兼容,但它们仍然相互排斥,因为需要将 "their" 标记作为第一个片段流(因此,也存在 "third" 格式,这是一种 JFIF 兼容性,但仍包含用于更丰富元数据的 Exif 段)。
另一个 "JPEG files" 家族缺少 JFIF 和 Exif 标记,但仍然遵循相同的段布局,具有 SOI、APPn 标记、SOF、DHT、DQT、SOS 和 EOI 标记,如 "Annex B" (JIF)。大多数解码器也会对这些图像进行解码。
TL;DR:总而言之,所有 "JPEG" 文件格式的共同点是它们使用 JPEG 压缩,并遵循 JIF 结构。因此,有些人很难理解 "convert classic JPEG to JIF".
的意思
"Classic JPEG" 是 JIF.
客户要求我发送 .JIF 格式 (JFIF) 的图像。我有 java 应用程序,但我无法 google 了解如何转换为该图像类型的主题,我什至几乎 google 无法了解“.JIF”格式本身。
已编辑: 有人可以建议如何在 java 中将 Exif 图像转换为 JFIF 吗?以及如何给这个 JFIF 图片添加评论? (尝试使用 jheader 库不幸以 nullpointer 异常结束,google 上没有更多选择。)
首先您需要读取该图像,然后您必须将该图像写入您想要的尺寸和格式。 您必须使用 ImageIO class 和 BufferedReader 来读取图像 要编写它们,请使用 Graphics2D class 将格式名称替换为 jif
File inputFile = new File(inputImagePath);
BufferedImage inputImage = ImageIO.read(inputFile);
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth,
scaledHeight, inputImage.getType());
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// extracts extension of output file
String formatName = outputImagePath.substring(outputImagePath
.lastIndexOf(".") + 1);
// writes to output file
ImageIO.write(outputImage, formatName, new File(outputImagePath));
编辑:将 Exif JPEG 转换为 JFIF JPEG:
如果您不介意损失一些质量(由于有损 JPEG 重新编码),您可以像这样简单地转换图像:
File inFile = ...;
File outFile = ...; // Feel free to use ".jif" as extension
if (!ImageIO.write(ImageIO.read(inFile), "JPEG", outFile)) {
System.err.println("Could not write JPEG format"); // Should never happen
}
这会起作用,因为默认的 JPEGImageWriter
插件只支持 JFIF 格式。而且因为我们不读取元数据,所以旧的 Exif 信息将丢失。但是,这样做将不允许您添加评论。
要添加评论,您仍然可以使用标准 ImageIO API,但我们必须访问元数据,从而使代码更加冗长。有关元数据格式的更多信息,请参阅 JPEG Metadata Format Specification。如果您需要从 Exif 元数据转换注释,请将您的问题更新为具体说明,因为它需要进一步解析元数据和 ImageIO 当前不支持的额外支持 API。
File inFile = ...;
File outFile = ...; // Feel free to use ".jif" as extension
BufferedImage image = ImageIO.read(inFile);
ImageWriter jpegWriter = ImageIO.getImageWritersByFormatName("JPEG").next(); // Should be a least one
// To write comments, we need to add it to the metadata
ImageWriteParam param = jpegWriter.getDefaultWriteParam();
IIOMetadata metadata = jpegWriter.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), param);
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree("javax_imageio_jpeg_image_1.0");
IIOMetadataNode markerSequence = (IIOMetadataNode) root.getElementsByTagName("markerSequence").item(0); // Should be only one
// Insert a "COM" marker, with our comment
IIOMetadataNode com = new IIOMetadataNode("com");
com.setAttribute("comment", "Hello JFIF!");
markerSequence.appendChild(com);
// Merge edited metadata
metadata.mergeTree("javax_imageio_jpeg_image_1.0", root);
ImageOutputStream output = ImageIO.createImageOutputStream(outFile);
try {
jpegWriter.setOutput(output);
// Write image along with metadata
jpegWriter.write(new IIOImage(image, null, metadata));
}
finally {
output.close();
}
jpegWriter.dispose();
这样,我们仍然以有损 JPEG 格式重新编码图像,但我们将 Exif 转换为 JFIF 并添加注释。
现在,还有另一种选择,可以做到完全无损。但它确实需要对 JIF 段结构以及 Exif 和 JFIF 格式的工作原理有更深入的了解。不幸的是,没有标准 Java API(据我所知)可以做到这一点,因此您将不得不自己动手。随意使用我的 JPEG segment parsing code as a starting point. The JHeader 你链接的项目看起来也很有前途,但我没有使用这个库的任何经验,所以我不能在那里提供任何建议。
基本思路如下:
- Parse/skip标记段直到SOS(扫描开始)段(SOS之后的数据将是压缩图像数据)。
- 写入 SOI 标记 (
0xffd8
) - 创建一个 APP0/"JFIF" 标记(我想你可以在这里使用默认值,详情请参阅 JFIF segment)。 thumb dimensions 可以写0, 0, 略写thumbnail data.
- 添加您的 COM 段以及您需要的任何注释(可能从 Exif 元数据中提取)
- 按原样从原始流中写入 SOF、DHT、DQT 等标准段(跳过 APP1/"Exif" 和其他 "custom" 段)。
- 从原始流中写入 SOS 标记和图像数据
理论上,这应该可行。您可能有一些小的颜色 space 问题,因为 Exif 数据可能包含不同的颜色 space(通常是 sRGB 或 AdobeRGB1998),而 JFIF doesn't have a defined color space。如果您需要此功能,请添加具有所需配置文件的 APP2/"ICC_PROFILE" 段(在第 3 步之后)。
祝你好运! :-)
注意:这不是一个完整的答案,而是试图澄清为什么您需要与您的客户交谈,并弄清楚您的 JPEG 有什么问题以及他 "JIF" 的实际含义。
首先,JPEG 不是一种文件格式。 JPEG 是静止图像压缩标准。该标准的一部分(通常称为 "Annex B")是对交换格式的描述,有时称为 JIF。该标准还指定了一种称为 SPIFF 的完整文件格式,但这种格式并不是很普遍(我认为这不是你想要的)。
你随处找到的文件,称为 "JPEG files"(我假设这就是你所说的 "Classic JPEG"),通常是基本相同的两种略有不同的风格之一文件格式:
最基本的格式是JFIF。此格式以 SOI 标记开头,紧接着是一个以 "JFIF"(空终止)作为其标识符的 APP0 标记。根据规范的 original JFIF specification "The JPEG File Interchange Format is entirely compatible with the standard JPEG interchange format; the only additional requirement is the mandatory presence of the APP0 marker right after the SOI marker." (this part is left out of the ITU 和 ISO 版本,但仍然适用)。简而言之,JFIF 将 JPEG 数据限制为 1 或 3 个分量,编码为 Y 或 YCbCr,并强烈推荐基线 DCT、霍夫曼编码压缩。
另一种常见格式是Exif。此格式以 SOI 标记开头,紧接着是一个以 "Exif"(空终止)作为其标识符的 APP1 标记。这种格式由数码相机制造商开发,允许在文件中记录更丰富的元数据(以 TIFF 元数据结构的形式)。据我了解,Exif 将 JPEG 数据限制为 3 个分量,编码为 YCbCr,使用基线 DCT,霍夫曼编码压缩(最后一部分可能只是互操作性建议,规范中的语言有点难以阅读。 ..).
这两种格式都包含相同的 "segment" 布局并且图像数据兼容,但它们仍然相互排斥,因为需要将 "their" 标记作为第一个片段流(因此,也存在 "third" 格式,这是一种 JFIF 兼容性,但仍包含用于更丰富元数据的 Exif 段)。
另一个 "JPEG files" 家族缺少 JFIF 和 Exif 标记,但仍然遵循相同的段布局,具有 SOI、APPn 标记、SOF、DHT、DQT、SOS 和 EOI 标记,如 "Annex B" (JIF)。大多数解码器也会对这些图像进行解码。
TL;DR:总而言之,所有 "JPEG" 文件格式的共同点是它们使用 JPEG 压缩,并遵循 JIF 结构。因此,有些人很难理解 "convert classic JPEG to JIF".
的意思"Classic JPEG" 是 JIF.