如何将任何图像转换为 JPG?
How to convert any image to JPG?
我从休息控制器收到一个 MultipartFile
Spring 对象。我正在尝试将任何 inage 文件转换为 JPG
图像 但我只需要字节数组来保存它 on mongoDb
我发现这段代码可以做到这一点
public boolean convertImageToJPG(InputStream attachedFile) {
try {
BufferedImage inputImage = ImageIO.read(attachedFile);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
boolean result = ImageIO.write(inputImage, "jpg", byteArrayOutputStream);
return result;
} catch (IOException e) {
System.err.println("Error " + e);
}
return false;
}
但是 result
作为 false
没有错误,所以 ImageIO.write
不工作
我也发现这样做是一样的,但是使用 File
对象,我不想 create
目录中的文件,我只需要字节数组
public static boolean convertFormat(String inputImagePath,
String outputImagePath, String formatName) throws IOException {
FileInputStream inputStream = new FileInputStream(inputImagePath);
FileOutputStream outputStream = new FileOutputStream(outputImagePath);
// reads input image from file
BufferedImage inputImage = ImageIO.read(inputStream);
// writes to the output image in specified format
boolean result = ImageIO.write(inputImage, formatName, outputStream);
// needs to close the streams
outputStream.close();
inputStream.close();
return result;
}
测试
public class TestImageConverter {
public static void main(String[] args) {
String inputImage = "D:/Photo/Pic1.jpg";
String oututImage = "D:/Photo/Pic1.png";
String formatName = "PNG";
try {
boolean result = ImageConverter.convertFormat(inputImage,
oututImage, formatName);
if (result) {
System.out.println("Image converted successfully.");
} else {
System.out.println("Could not convert image.");
}
} catch (IOException ex) {
System.out.println("Error during converting image.");
ex.printStackTrace();
}
}
}
我该如何解决我的问题?
更新的解决方案(不需要 Raster 和 ColorModel 的替代方案)
我的旧解决方案(见下文)仍然需要 Rasters 和 ColorModels,这确实让我很困扰。我的解决方案受到挑战,所以我花了更多时间寻找替代方案。所以我现在能想到的最好的事情是:
try {
final FileInputStream fileInputStream = new FileInputStream("dice.png");
final BufferedImage image = ImageIO.read(fileInputStream);
fileInputStream.close(); // ImageIO.read does not close the input stream
final BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
convertedImage.createGraphics().drawImage(image, 0, 0, Color.WHITE, null);
final FileOutputStream fileOutputStream = new FileOutputStream("dice-test.jpg");
final boolean canWrite = ImageIO.write(convertedImage, "jpg", fileOutputStream);
fileOutputStream.close(); // ImageIO.write does not close the output stream
if (!canWrite) {
throw new IllegalStateException("Failed to write image.");
}
} catch (IOException e) {
e.printStackTrace();
}
我像以前一样得到了 BufferedImage 的副本。它或多或少做了同样的事情,但实际上您可以更轻松地重用 ColorModel 和 Raster。
drawImage()
似乎可以解决我之前手动完成的大部分工作。而且由于一路都是标准的java库代码,看来确实是一种更好的方式。
请注意,您最终得到了 BufferedImage.TYPE_INT_RGB
类型的图像。虽然它似乎适用于 jpg
、png
和 gif
类型,但我不确定其他文件格式或具有不同存储 ColorModel 的文件会发生什么情况 - 信息可能会丢失(例如 4 个颜色通道到 3 个)。对于上述类型,我们不需要 alpha 通道,即使我们从 gif
或 jpg
转换为 png
(它将是 Color.WHITE)。
旧的解决方案
我对我的第一个设计不满意,而且它也没有达到应有的效果。
因此,我从头开始创建了一个。我最终得到了一个 sRGB
文件的小转换器。您可以从 png
转换为 jpg
,反之亦然(编辑:还添加了 gif
支持)。如果您想处理其他类型,请随意进一步扩展。您可以或多或少地以相同的方式添加它。它也可能适用于其他文件类型,但我还没有测试过它们。幸运的是,sRGB
似乎很常见。
太棒了。我不知道您可以产生多少组合和变体(调色板、精度、质量、b/w 等)或它们共享哪些共同属性。
也许这对你来说已经足够了。也许不吧。至少这对我来说是一个很好的锻炼。
这个解决方案绝不是完美的。结果看起来还不错。文件类型转换有效,文件大小也小于 png
.
try {
final String fileName = "dice.png";
final BufferedImage inputImage = ImageIO.read(new FileInputStream(fileName));
final boolean isSRGB = inputImage.getColorModel().getColorSpace().isCS_sRGB();
final String outputFormat = "gif";
if (!isSRGB) {
throw new IllegalArgumentException("Please provide an image that supports sRGB.");
}
final WritableRaster raster = createRaster(inputImage);
final ColorModel colorModel = createColorModel(inputImage);
final BufferedImage outputImage = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
final String outputFileName = fileName + "-converted." + outputFormat;
final boolean writeResult = ImageIO.write(outputImage, outputFormat, new FileOutputStream(outputFileName));
if (!writeResult) {
throw new IllegalStateException("Could not convert file: " + fileName + " to format: " + outputFormat);
}
System.out.println(">> Created file: " + outputFileName);
} catch (Exception e) {
e.printStackTrace();
}
@NotNull
public static ColorModel createColorModel(@NotNull BufferedImage bufferedImage) {
Objects.requireNonNull(bufferedImage);
final int type = bufferedImage.getType();
boolean isAlphaPremultiplied = false;
int transparency = Transparency.OPAQUE;
if (type == BufferedImage.TYPE_3BYTE_BGR) {
isAlphaPremultiplied = true;
}
return new ComponentColorModel(
ColorModel.getRGBdefault().getColorSpace(),
false, isAlphaPremultiplied, transparency,
bufferedImage.getData().getDataBuffer().getDataType()
);
}
@NotNull
public static WritableRaster createRaster(@NotNull BufferedImage bufferedImage) {
Objects.requireNonNull(bufferedImage);
final int type = bufferedImage.getType();
final int width = bufferedImage.getWidth();
final int height = bufferedImage.getHeight();
final int pixelStride = 3;
int[] offset = new int[]{0, 1, 2};
DataBufferByte dataBufferByte;
if (type == BufferedImage.TYPE_4BYTE_ABGR || type == BufferedImage.TYPE_BYTE_INDEXED) {
int dataIndex = 0;
final byte[] data = new byte[height * width * pixelStride];
final int bitmask = 0xff;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
final int rgb = bufferedImage.getRGB(x, y);
final int blue = bitmask & rgb;
final int green = bitmask & (rgb >> 8);
final int red = bitmask & (rgb >> 16);
if (rgb == 0) {
data[dataIndex++] = (byte) bitmask;
data[dataIndex++] = (byte) bitmask;
data[dataIndex++] = (byte) bitmask;
} else {
data[dataIndex++] = (byte) red;
data[dataIndex++] = (byte) green;
data[dataIndex++] = (byte) blue;
}
}
}
dataBufferByte = new DataBufferByte(data, data.length);
} else if (type == BufferedImage.TYPE_3BYTE_BGR) {
dataBufferByte = (DataBufferByte) bufferedImage.getRaster().getDataBuffer();
offset = new int[]{2, 1, 0};
} else {
throw new IllegalArgumentException("Cannot create raster for unsupported image type.");
}
return Raster.createInterleavedRaster(
dataBufferByte, width, height,
pixelStride * width, pixelStride,
offset,
null
);
}
编辑:添加了对 gif 的支持。
我从休息控制器收到一个 MultipartFile
Spring 对象。我正在尝试将任何 inage 文件转换为 JPG
图像 但我只需要字节数组来保存它 on mongoDb
我发现这段代码可以做到这一点
public boolean convertImageToJPG(InputStream attachedFile) {
try {
BufferedImage inputImage = ImageIO.read(attachedFile);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
boolean result = ImageIO.write(inputImage, "jpg", byteArrayOutputStream);
return result;
} catch (IOException e) {
System.err.println("Error " + e);
}
return false;
}
但是 result
作为 false
没有错误,所以 ImageIO.write
不工作
我也发现这样做是一样的,但是使用 File
对象,我不想 create
目录中的文件,我只需要字节数组
public static boolean convertFormat(String inputImagePath,
String outputImagePath, String formatName) throws IOException {
FileInputStream inputStream = new FileInputStream(inputImagePath);
FileOutputStream outputStream = new FileOutputStream(outputImagePath);
// reads input image from file
BufferedImage inputImage = ImageIO.read(inputStream);
// writes to the output image in specified format
boolean result = ImageIO.write(inputImage, formatName, outputStream);
// needs to close the streams
outputStream.close();
inputStream.close();
return result;
}
测试
public class TestImageConverter {
public static void main(String[] args) {
String inputImage = "D:/Photo/Pic1.jpg";
String oututImage = "D:/Photo/Pic1.png";
String formatName = "PNG";
try {
boolean result = ImageConverter.convertFormat(inputImage,
oututImage, formatName);
if (result) {
System.out.println("Image converted successfully.");
} else {
System.out.println("Could not convert image.");
}
} catch (IOException ex) {
System.out.println("Error during converting image.");
ex.printStackTrace();
}
}
}
我该如何解决我的问题?
更新的解决方案(不需要 Raster 和 ColorModel 的替代方案)
我的旧解决方案(见下文)仍然需要 Rasters 和 ColorModels,这确实让我很困扰。我的解决方案受到挑战,所以我花了更多时间寻找替代方案。所以我现在能想到的最好的事情是:
try {
final FileInputStream fileInputStream = new FileInputStream("dice.png");
final BufferedImage image = ImageIO.read(fileInputStream);
fileInputStream.close(); // ImageIO.read does not close the input stream
final BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
convertedImage.createGraphics().drawImage(image, 0, 0, Color.WHITE, null);
final FileOutputStream fileOutputStream = new FileOutputStream("dice-test.jpg");
final boolean canWrite = ImageIO.write(convertedImage, "jpg", fileOutputStream);
fileOutputStream.close(); // ImageIO.write does not close the output stream
if (!canWrite) {
throw new IllegalStateException("Failed to write image.");
}
} catch (IOException e) {
e.printStackTrace();
}
我像以前一样得到了 BufferedImage 的副本。它或多或少做了同样的事情,但实际上您可以更轻松地重用 ColorModel 和 Raster。
drawImage()
似乎可以解决我之前手动完成的大部分工作。而且由于一路都是标准的java库代码,看来确实是一种更好的方式。
请注意,您最终得到了 BufferedImage.TYPE_INT_RGB
类型的图像。虽然它似乎适用于 jpg
、png
和 gif
类型,但我不确定其他文件格式或具有不同存储 ColorModel 的文件会发生什么情况 - 信息可能会丢失(例如 4 个颜色通道到 3 个)。对于上述类型,我们不需要 alpha 通道,即使我们从 gif
或 jpg
转换为 png
(它将是 Color.WHITE)。
旧的解决方案
我对我的第一个设计不满意,而且它也没有达到应有的效果。
因此,我从头开始创建了一个。我最终得到了一个 sRGB
文件的小转换器。您可以从 png
转换为 jpg
,反之亦然(编辑:还添加了 gif
支持)。如果您想处理其他类型,请随意进一步扩展。您可以或多或少地以相同的方式添加它。它也可能适用于其他文件类型,但我还没有测试过它们。幸运的是,sRGB
似乎很常见。
太棒了。我不知道您可以产生多少组合和变体(调色板、精度、质量、b/w 等)或它们共享哪些共同属性。
也许这对你来说已经足够了。也许不吧。至少这对我来说是一个很好的锻炼。
这个解决方案绝不是完美的。结果看起来还不错。文件类型转换有效,文件大小也小于 png
.
try {
final String fileName = "dice.png";
final BufferedImage inputImage = ImageIO.read(new FileInputStream(fileName));
final boolean isSRGB = inputImage.getColorModel().getColorSpace().isCS_sRGB();
final String outputFormat = "gif";
if (!isSRGB) {
throw new IllegalArgumentException("Please provide an image that supports sRGB.");
}
final WritableRaster raster = createRaster(inputImage);
final ColorModel colorModel = createColorModel(inputImage);
final BufferedImage outputImage = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
final String outputFileName = fileName + "-converted." + outputFormat;
final boolean writeResult = ImageIO.write(outputImage, outputFormat, new FileOutputStream(outputFileName));
if (!writeResult) {
throw new IllegalStateException("Could not convert file: " + fileName + " to format: " + outputFormat);
}
System.out.println(">> Created file: " + outputFileName);
} catch (Exception e) {
e.printStackTrace();
}
@NotNull
public static ColorModel createColorModel(@NotNull BufferedImage bufferedImage) {
Objects.requireNonNull(bufferedImage);
final int type = bufferedImage.getType();
boolean isAlphaPremultiplied = false;
int transparency = Transparency.OPAQUE;
if (type == BufferedImage.TYPE_3BYTE_BGR) {
isAlphaPremultiplied = true;
}
return new ComponentColorModel(
ColorModel.getRGBdefault().getColorSpace(),
false, isAlphaPremultiplied, transparency,
bufferedImage.getData().getDataBuffer().getDataType()
);
}
@NotNull
public static WritableRaster createRaster(@NotNull BufferedImage bufferedImage) {
Objects.requireNonNull(bufferedImage);
final int type = bufferedImage.getType();
final int width = bufferedImage.getWidth();
final int height = bufferedImage.getHeight();
final int pixelStride = 3;
int[] offset = new int[]{0, 1, 2};
DataBufferByte dataBufferByte;
if (type == BufferedImage.TYPE_4BYTE_ABGR || type == BufferedImage.TYPE_BYTE_INDEXED) {
int dataIndex = 0;
final byte[] data = new byte[height * width * pixelStride];
final int bitmask = 0xff;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
final int rgb = bufferedImage.getRGB(x, y);
final int blue = bitmask & rgb;
final int green = bitmask & (rgb >> 8);
final int red = bitmask & (rgb >> 16);
if (rgb == 0) {
data[dataIndex++] = (byte) bitmask;
data[dataIndex++] = (byte) bitmask;
data[dataIndex++] = (byte) bitmask;
} else {
data[dataIndex++] = (byte) red;
data[dataIndex++] = (byte) green;
data[dataIndex++] = (byte) blue;
}
}
}
dataBufferByte = new DataBufferByte(data, data.length);
} else if (type == BufferedImage.TYPE_3BYTE_BGR) {
dataBufferByte = (DataBufferByte) bufferedImage.getRaster().getDataBuffer();
offset = new int[]{2, 1, 0};
} else {
throw new IllegalArgumentException("Cannot create raster for unsupported image type.");
}
return Raster.createInterleavedRaster(
dataBufferByte, width, height,
pixelStride * width, pixelStride,
offset,
null
);
}
编辑:添加了对 gif 的支持。