这是相反的:

create BITMAP image from hex String Java

我需要接受一个PNG作为输入,并将其转换为十六进制字符串.十六进制字符串的创建方式规范如下:

根据所附的编码方案,从下到上读取每个像素列,并将四个像素编码成字母/数字(A-F 0-9).

位图代码是为硬件开发的十六进制代码.代码中的每个数字控制显示器上四个虚拟像素的垂直部分.第一个代码字母控制从左下角开始向上的四个像素.第二个编码字母控制第一个编码字母上方的下四个像素,第三个编码字母控制第二个编码字母上方的下四个像素,第四个编码字母控制左数第一列中最上面的四个像素.然后,第五个字母控制第二列的底部四个像素,依此类推.

以下是我try 过的方法,但不起作用:-(

public AppResponse<String> getBitmapCode(MultipartFile pngFile) throws IOException {

        BufferedImage img = ImageIO.read(pngFile.getInputStream());

        int height = img.getHeight();
        int width = img.getWidth();

        StringBuilder bitmapCode = new StringBuilder();

        // Process each column
        for (int x = 0; x < width; x++) {
            int pixelValue = 0;

            // Process each pixel in the column from bottom to top
            for (int y = height - 1; y >= 0; y--) {
                int rgb = img.getRGB(x, y);

                // Check if the pixel is closer to white or black using a threshold
                int bit = (getColorDistance(rgb, Color.WHITE) < getColorDistance(rgb, Color.BLACK)) ? 0 : 1;

                pixelValue = (pixelValue << 1) | bit;

                // Check if 4 pixels have been processed
                if ((height - 1 - y) % 4 == 0) {
                    // Convert the pixel value to the corresponding character
                    char encodedChar = encodePixelValue(pixelValue);
                    bitmapCode.append(encodedChar);
                    pixelValue = 0;
                }
            }
        }

        return AppResponse.responseOk("Success", bitmapCode.toString());
    }

    private static int getColorDistance(int rgb1, Color color2) {
        Color color1 = new Color(rgb1 & 0x00FFFFFF); // Remove alpha channel
        return (int) Math.sqrt(
                Math.pow(color1.getRed() - color2.getRed(), 2) +
                        Math.pow(color1.getGreen() - color2.getGreen(), 2) +
                        Math.pow(color1.getBlue() - color2.getBlue(), 2)
        );
    }

    private static char encodePixelValue(int pixelValue) {
        if (pixelValue >= 0 && pixelValue <= 9) {
            return (char) ('0' + pixelValue);
        } else if (pixelValue >= 10 && pixelValue <= 15) {
            return (char) ('A' + (pixelValue - 10));
        } else {
            throw new IllegalArgumentException("Invalid pixel value: " + pixelValue);
        }
    }

PNG is attached here : enter image description here

图像应生成如下所示的十六进制:

000700070007FFFFFFFF00070007000700000000FFFFFFFFE1C7E1C7E1C7E1C7E00700000000183C787EF0C7E187E187E30F7E1E3C1C00000000000700070007FFFFFFFF00070007000700000000FFFFFFFF00000000FFFFFFFF00FC07E03F00FFFFFFFF000000003FFCFFFEE007E707E7077F3EFF3C0000

Output I get from my code : enter image description here

推荐答案

您的代码基本上是正确的.只有两个小错误.

  1. 您在代码的这一部分中有一个Off-by-One错误:

    if ((height - 1 - y) % 4 == 0) {
        // Convert the pixel value to the corresponding character
        char encodedChar = encodePixelValue(pixelValue);
        bitmapCode.append(encodedChar);
        pixelValue = 0;
    }
    

    将条件更改为(height - y) % 4 == 0).

  2. 当 colored颜色 更接近白色而不是黑色时,需要将bit变量设置为1,而不是0.换句话说,将condition ? 0 : 1改为condition ? 1 : 0.


如果你想看看另一个解决方案,那么这里有一个基本上是从the answer to your previous question开始的一对一的代码反转.

首先,下面是另一个问题的代码,稍作修改.注意,它使用了Java 17中添加的java.util.HexFormat类.

static BufferedImage decode(String hex, int height) {
  if (height % 8 != 0) {
    throw new IllegalArgumentException("height must be multiple of 8");
  }
  var bytes = HexFormat.of().parseHex(hex);
  var image = new BufferedImage(bytes.length / (height / 8), height, TYPE_BYTE_BINARY);
  for (int x = 0; x < image.getWidth(); x++) {
    for (int y = 0; y < height; y++) {
      int pos = height * x + y;
      int bit = (bytes[pos / 8] >> (7 - (pos % 8))) & 1;
      int rgb = bit == 0 ? 0x000000 : 0xFFFFFF;
      image.setRGB(x, height - y - 1, rgb);
    }
  }
  return image;
}

下面的代码做了相反的事情(即,它将位存储在字节中,而不是从字节中提取位).请注意,它还使用了HexFormat.

static String encode(BufferedImage image) {
  if (image.getHeight() % 8 != 0) {
    throw new IllegalArgumentException("image height must be multiple of 8");
  }
  var bytes = new byte[image.getWidth() * (image.getHeight() / 8)];
  for (int x = 0; x < image.getWidth(); x++) {
    for (int y = 0; y < image.getHeight(); y++) {
      int rgb = image.getRGB(x, image.getHeight() - y - 1);
      if (isCloserToWhiteThanBlack(rgb)) {
        int pos = image.getHeight() * x + y;
        bytes[pos / 8] |= 1 << (7 - (pos % 8));
      }
    }
  }
  return HexFormat.of().withUpperCase().formatHex(bytes);
}

其中,isCloserToWhiteThanBlack基本上与您已经在代码中使用的逻辑相同.

Java相关问答推荐

在Java 8之后,HashMap的最坏情况下时间复杂度仍然是O(n)而不是O(log n)?

JPackaged应用程序启动MSI调试,然后启动System. exit()

使用java访问具体子类特定方法的最佳方法是什么?

Character::Emoji不支持带数字的字符吗?

错误:在Liferay7.4中找不到符号导入com.liferay.portal.kernel.uuid.PortalUUID;";

嵌入式ActiveMQ Artemis Web控制台加载错误

DTO到实体,反之亦然,控制器和服务之间的哪一层应该处理转换?

为什么JAVA&S清洁器使用链表而不是并发HashSet?

OpenGL ES 3.0-纹理黑色

我可以在MacOS上使用什么Java函数来在适当的设备上以适当的音量播放适当的alert 声音?

Sack()步骤中的合并运算符未按预期工作

如何将Pane的图像快照保存为BMP?

Android Java:已设置但未读取SharedPreferences

X=x*0.90;产生有损转换误差.X*=0.90;不是.为什么?

try 在两个不同数组的数字之间求平均值

IntelliJ IDEA依赖项工具窗口丢失

在JDK Flight Recorder中只记录单个线程

在应用getCellFormula()时,Excel引用中的文件名始终为";[1]";使用Apache POI()

我的代码是线程安全的吗?[Java、CAS、转账]

当我将JTextField的getText函数与相等的String进行比较时;t返回true