【问题标题】:Java - Image BMP headerJava - 图像 BMP 标头
【发布时间】:2016-11-08 23:00:06
【问题描述】:

如果有人可以帮助我,我会遇到一个小问题,我会很高兴。 我正在尝试进行下一步操作

  1. 读取 BMP 图像
  2. 将图像转换为字节[]
  3. 将图像旋转 90 度(字节数组)
  4. 并在某个文件夹中写入新图像

我的问题是......在我尝试编写新图像的那一刻,我的 BMP 标头出现了一些问题,我不知道为什么。如果有人知道答案,请给我一些建议。

将图片转换成字节[]

private static byte[] convertAnImageToPixelsArray(File file) throws FileNotFoundException {
    FileInputStream fis = new FileInputStream(file);

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] buf = new byte[1024];
    try {
        for (int readNum; (readNum = fis.read(buf)) != -1; ) {
            bos.write(buf, 0, readNum);
        }
    } catch (IOException ex) {
        Logger.getLogger(ConvertImage.class.getName()).log(Level.SEVERE, null, ex);
    }
    return bos.toByteArray();
}

旋转

private static byte[] rotate(double angle, byte[] pixels, int width, int height) {
    final double radians = Math.toRadians(angle), cos = Math.cos(radians), sin = Math.sin(radians);
    final byte[] pixels2 = new byte[pixels.length];
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
            final int
                    centerx = width / 2,
                    centery = height / 2,
                    m = x - centerx,
                    n = y - centery,
                    j = ((int) (m * cos + n * sin)) + centerx,
                    k = ((int) (n * cos - m * sin)) + centery;
            if (j >= 0 && j < width && k >= 0 && k < height)
                pixels2[(y * width + x)] = pixels[(k * width + j)];
        }
    }
    arraycopy(pixels2, 0, pixels, 0, pixels.length);
    return pixels2;
}

将字节[]转换为图片

private static void convertArrayPixelsIntoImage(byte[] bytes) throws IOException {
    ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
    Iterator<?> readers = ImageIO.getImageReadersByFormatName("bmp");

    ImageReader reader = (ImageReader) readers.next();
    Object source = bis;
    ImageInputStream iis = ImageIO.createImageInputStream(source);
    reader.setInput(iis, true);
    ImageReadParam param = reader.getDefaultReadParam();

    Image image = reader.read(0, param);
    BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);

    Graphics2D g2 = bufferedImage.createGraphics();
    g2.drawImage(image, null, null);

    File imageFile = new File("Images/Output.bmp");
    ImageIO.write(bufferedImage, "bmp", imageFile);
}

主要:

public static void main(String[] args) throws IOException {
    File file = new File("Images/Input-1.bmp");
    Image img = ImageIO.read(file);
    convertArrayPixelsIntoImage(rotate(90,convertAnImageToPixelsArray(file),img.getWidth(null),img.getHeight(null)));
}

这是错误消息:

线程“main”javax.imageio.IIOException 中的异常:无法读取图像头。

有什么建议吗?

【问题讨论】:

  • 你如何调用这些方法?请显示您调用它们的方法。
  • 我已经添加了main函数。
  • 您正在旋转整个图像文件的内容,包括标题,因此您正在破坏标题。但是为什么还要读两遍呢?您使用ImageIO.readconvertAnImageToPixelsArray 读取图像 - 这是多余的。

标签: java arrays image image-processing bmp


【解决方案1】:

问题是您在旋转图像时没有考虑 BMP 文件的结构。

您只是从文件中读取byte[],就像您可以从任何文件中读取一样 - 它只是一个字节流。

但在您的 rotate 方法中,您假设像素值为:

  • 每像素 1 个字节;
  • 从数组的开头开始。

事实并非如此。除了每个像素几乎肯定会被多个字节编码这一事实之外,BMP file format 以标头和其他元数据开头。

虽然您显然可以弄清楚如何正确解码数据,但我强烈反对这样做。您已经在使用 ImageIO (Image img = ImageIO.read(file);) 读取图像,因此您无需重新发明轮子:只需使用 Java 现有的图像处理功能即可。

【讨论】:

  • 问题是……我需要重新设计轮子,因为我需要一些速度。在正常情况下,您可以 BufferedImage 旋转此图像,但这种方法会变慢...我需要更快的东西,您知道吗?
  • 您需要了解 BMP 文件格式,了解其结构,并调整您的代码以正确处理它。但是你几乎肯定会做错,错过边缘情况,效率低下等等,因此最终浪费了大量时间。查找现有实现。
【解决方案2】:

您错过了 BMP 图像具有与任何其他格式一样的标题。当您尝试旋转图像时,您正在更改字节顺序,因此标题会在其他地方丢失,而不是开始。尝试将前 54 个字节提取到另一个数组,旋转其他字节,然后首先写入文件头,然后再写入其他字节

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 2019-07-11
    • 1970-01-01
    • 2021-10-16
    • 2017-03-11
    • 2013-09-15
    • 2016-12-14
    相关资源
    最近更新 更多