【问题标题】:How do you generate an image of a specific size in Java?如何在 Java 中生成特定大小的图像?
【发布时间】:2019-01-25 11:18:44
【问题描述】:

我需要使用 Java。图片可以是填充背景色的任意形状,对图片内容没有限制。

编辑#1:要创建的图像的大小是可变的,所以我正在寻找一种有效的方式内存方面使用,以便在创建图像时免受 Java heap space 异常的影响。

编辑#2:当我尝试使用 Graphics2D 库生成尺寸为 48000x48000 的图像时,我收到了 java.lang.IllegalArgumentException: Dimensions (width=48000 height=48000) are too large 异常,这是生成大尺寸图像所必需的文件大小。

编辑#3:当尺寸变大时,即使我手动配置了执行此操作的 Java 程序的 -Xmx 参数,我也会遇到 java.lang.OutOfMemoryError: Java heap space 异常。

【问题讨论】:

  • 我也有一个尺寸标准,这是问题的关键部分。
  • 当然,我知道这些参数,但我需要创建各种尺寸的图像。另外,我问最有效的方法创建图像,以防止任何可能的heap size 异常。
  • BufferedImage 仍然是您最好的选择,我之前管理过超过 2,000x2,000 像素的尺寸,但您的要求并不明确且广泛。 “最有效的方法”是确保在使用完所有未使用的资源后将其处理掉
  • 对于您的编辑 2:宽度 * 高度应小于 Integer.MAX_VALUE。 @stackoverflow.com/questions/9089675/creating-huge-bufferedimage

标签: java file image-processing graphics java-io


【解决方案1】:

一种生成灰度图像的方法(宽度:宽度和高度:高度):-

1) 创建一个BufferedImage 对象:-

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);

2) 填充您的 BufferedImage 对象(这里我假设您对存储在名为 img 的二维 int 数组中的图像有正确的输入):-

for (int y = 0; y < image.getHeight(); y++) 
    {
      for (int x = 0; x < image.getWidth(); x++) 
      {

          image.setRGB(x, y, img[y][x]<<16 | img[y][x] << 8 | img[y][x]);
      }

    }

3) 将 BufferedImage 对象写入磁盘:-

ImageIO.write(image, "jpg", new FileOutputStream(new File("SomePath/Name-of-Image.jpg")));

【讨论】:

  • 一切都很好,除了尺寸标准是问题的关键部分。
  • 你具体想做什么?您是否正在读取图像,进行一些处理然后将它们写回?还是别的什么?
  • 需要为学术研究生成各种大小(即10KB、100KB、1MB、10MB等)的不同图像。
  • 我同意 MadProgrammer(请参阅他在您的问题下的评论)。 BufferedImage 仍然是你最好的。我曾经用它以一千种不同的方式处理图像。我所做的是,在进行不同的处理之前,我会先将图像写入磁盘并释放资源。您可以遵循类似的模式。根据您提供的信息,这是我能给您的最佳建议
  • 谢谢@opensam,同意你的看法;它最适合我,但在创建图像时会遇到一些问题,尤其是当我在原帖中提到的图像尺寸越来越大时。
【解决方案2】:

据我所知,这里有一些非常简单的示例代码,应该符合您的要求。该程序应该在几乎没有内存的情况下非常有效地工作,但仍会创建大小高达(大约)2GB 的图像文件(如果您愿意,您也可以轻松地调整它以创建更大的图像)。

假设:

  • 图像格式无关紧要,所以我们将选择PGM format(二进制“P5”模式)
  • 图像可以是任何形状/颜色,所以我们只做最简单的事情,写一行全黑。
  • 重要的是图像文件的大小(下面的代码不会写入这个大小的字节,但可以通过在准确写入之前减去最小文件头的大小来轻松修改)。

输入是文件大小,后跟文件名(您想使用.pgm 作为扩展名)。举个例子:

$ java -cp ... WritePGM 2147483640 foo.pnm

以上将创建我的 JVM 允许回读的最大可能图像,大约 2 GB。

代码:

public class WritePGM {
    public static void main(String[] args) throws IOException {

        int size = Integer.parseInt(args[0]);
        File file = new File(args[1]);

        try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
            // Format P5/binary gray
            out.write("P5\n".getBytes(StandardCharsets.UTF_8));
            // Dimensions (width/height)
            out.write(String.format("%s 1\n", size).getBytes(StandardCharsets.UTF_8));
            // MaxSample
            out.write("255\n".getBytes(StandardCharsets.UTF_8));

            // Just write a single line of 0-bytes
            for (int i = 0; i < size; i++) {
                out.write(0);
            }
        }
    }
}

PS:如果您需要 ImageIO 插件来使用 Java 读取生成的文件,您可以使用 JAI ImageIO 或my own PNM plugin,但是您当然会遇到与尝试使用 Java2D 生成此类图像时相同的内存问题( BufferedImage)。


理论上,您也可以使用类似的技术来创建 JPEG 或 PNG 等格式的文件,但这些格式实现起来要困难得多。此外,它们是压缩的,因此很难预测文件大小。

也许你可以用额外的非图像数据填充最小的 JPEG,比如 XMP 左右。 PNG 确实允许在没有压缩的情况下编写 Deflate 块,这可能是一种选择。或者使用额外的块进行填充。

像 BMP 这样的未压缩格式会更简单。您可以使用与上述相同的技术,只需编写一个固定的、最小的 BMP 标头,设置正确的宽度并几乎像上面一样写入图像数据。 BMP 确实需要行填充,并且不支持灰色数据,所以你需要做一些额外的工作。但肯定是可行的。

【讨论】:

  • 确实是一个高效的解决方案,按预期工作,感谢您的贡献。生成jpgpng等众所周知的图像格式呢?
  • @talha06 在我的答案底部添加了一个关于此的部分。
【解决方案3】:
猜你喜欢
  • 1970-01-01
  • 2014-09-20
  • 2016-07-27
  • 2023-03-21
  • 2014-10-30
  • 2017-12-28
  • 1970-01-01
  • 1970-01-01
  • 2014-05-10
相关资源
最近更新 更多