【问题标题】:Java ImageIO is reading RGB instead of ARGB dataJava ImageIO 正在读取 RGB 而不是 ARGB 数据
【发布时间】:2020-12-04 00:39:19
【问题描述】:

我正在为照片编辑器开发图形用户界面,目前我无法从文件中加载 32 位 BMP 图像。一切都很顺利,直到我开始尝试多层并将它们塑造成一个单一的。 (图层成型和图像保存由Runtime类使用c++ .exe文件完成)

我使用 pixelFormer 软件制作了一个简单的 300x300 红色 bmp 图像,其中单个像素的值为 R:255 G:0 B:0 A:125

我注意到的是,我下面的方法为 alpha 通道加载了一个默认值为 255 的 RGB,而 alpha 通道应该是 125。这里是:

public void readFile(String sourceFileName, Image image) throws IOException {

    ArrayList<Short> pixels = new ArrayList<>();
    try {

       BufferedImage img = ImageIO.read(getClass().getResource(sourceFileName));
       System.out.println(img.getType());

        for (int i =0;i<img.getHeight();i++)
            for (int j =0;j<img.getWidth();j++)
            {
                Color c = new Color(img.getRGB(j,i),true);
                pixels.add((short)(c.getRed()));
                pixels.add((short)(c.getGreen()));
                pixels.add((short)(c.getBlue()));
                pixels.add((short)(c.getAlpha()));
                System.out.println("argb: " + c.getAlpha() + ", " + c.getRed() + ", " + c.getGreen() + ", " + c.getBlue());
                

            }


      image.loadLayer(new Layer(img.getHeight(),img.getWidth(),pixels));

    } catch (IOException e)
    {
        //
    }

但是,当我使用之前编写的 c++ 阅读器加载同一个 BMP 文件并将读取的数据保存到 json 文件中时,我可以清楚地看到 125 的 alpha 值位于 Java 方法返回 255 的位置。

Json 部分 sn-p: You can clearly see that pixels are in fact as they should be.

我可以创建一个 c++ 可执行文件来加载文件并使用 Runtime 类从 Java 运行它,但我不想在这里经常使用该类。

更新:出于某种原因 System.out.println(img.getType());返回 TYPE_INT_RGB

更新 2:对于那些可能认为我使用了一些 c++ 库的人,这里不是我基于此网站代码的代码:https://solarianprogrammer.com/2018/11/19/cpp-reading-writing-bmp-images/ Image、Layer 和 Pixel 是我的自定义类。

标题结构:

    #define BMPID 0x4D42
#pragma pack(push, 1)
struct BMPFileHeader {
    uint16_t fileType = BMPID; 
    uint32_t fileSize = 0; //in bytes
    uint16_t unused1 = 0;
    uint16_t unused2 = 0;
    uint32_t data_offset = 0;           // Start position of pixel data (bytes from the beginning of the file)
};

struct BMPInfoHeader {
    uint32_t headerSize = 0; 
    int32_t width = 0; 
    int32_t height = 0; 

    uint16_t planes = 1; //
    uint16_t bitsPerPixel = 0;
    uint32_t compression = 0;
    uint32_t image_size = 0;
    int32_t x_pixels_per_meter = 0;
    int32_t y_pixels_per_meter = 0;
    uint32_t colors_used = 0;
    uint32_t colors_important = 0;    // No. of colors used for displaying the bitmap. If 0 all colors are required
};

struct BMPColorHeader {
    uint32_t red_mask = 0x00ff0000;         
    uint32_t green_mask = 0x0000ff00;      
    uint32_t blue_mask = 0x000000ff;        
    uint32_t alpha_mask = 0xff000000;       
    uint32_t color_space_type = 0x73524742;
    uint32_t unused[12] = { 0 };       // Unused data for sRGB color space
};
#pragma pack(pop)

实际读者:

    void BMPFormater::read(std::string sourceFileName)
{
    {
        std::ifstream input{ sourceFileName, std::ios_base::binary };
        if (input)
        {
           

            BMPFileHeader fileHeader; // struct instance
            BMPInfoHeader infoHeader; // struct instance
            BMPColorHeader colorHeader; // struct instance

            uint32_t row_stride{ 0 };

            input.read((char*)&fileHeader, sizeof(fileHeader));
            if (fileHeader.fileType != BMPID) {
                throw std::runtime_error("Error! Unrecognized file format.");
            }

            input.read((char*)&infoHeader, sizeof(infoHeader));

            this->bitsPerPixel= infoHeader.bitsPerPixel;
           this->height=infoHeader.height;
           this->width=infoHeader.width;

            if (infoHeader.height < 0)
                throw std::runtime_error("The program can treat only BMP images with the origin in the bottom left corner!");

            // Jump to the pixel data location
            input.seekg(fileHeader.data_offset, input.beg);


           this->pixels.resize(this->width * this->height * this->bitsPerPixel / 8);

            // Here we check if there is a need to take into account row padding
            if (infoHeader.width % 4 == 0)
                input.read((char*)this->pixels.data(), this->pixels.size());

            else {
                row_stride = infoHeader.width * infoHeader.bitsPerPixel / 8;

               // uint32_t new_stride = 0;
                uint32_t new_stride = row_stride;
                    while (new_stride % 4 != 0)
                        new_stride++;
                

                std::vector<uint8_t> padding_row(new_stride - row_stride);

                for (int y = 0; y < infoHeader.height; ++y) { //cita red po red i svaki red peduje
                    input.read((char*)(this->pixels.data() + row_stride * y), row_stride);
                    input.read((char*)padding_row.data(), padding_row.size());
                }

            }



            //zamena crvenog i plavog piksela BGR(A) -> RGB(A)
            if (infoHeader.bitsPerPixel == 32)
            {
                
                for (int i = 0; i < infoHeader.width * infoHeader.height * infoHeader.bitsPerPixel / 8; i += 4)
                {
                    uint8_t temp = this->pixels[i];
                    this->pixels[i] = this->pixels[i + 2];
                    this->pixels[i + 2] = temp;
                }

               
            }
            else if (infoHeader.bitsPerPixel == 24)
            {
                
                for (int i = 0; i < infoHeader.width * infoHeader.height * infoHeader.bitsPerPixel / 8; i += 3)
                {
                    uint8_t temp = this->pixels[i];
                    this->pixels[i] = this->pixels[i + 2];
                    this->pixels[i + 2] = temp;
                }
                
            }
            
            Layer newLayer(this->height,this->width,this->bitsPerPixel,this->pixels);

            if (image->numberOfLayers != 0)
           
                image->resizeLayers(newLayer);

            image->layers.push_back(newLayer);
            image->numberOfLayers++;

            input.close();
        }
        else {
            throw std::runtime_error("Unable to open the input image file.");
        }
    }
}

【问题讨论】:

  • C++ 的参与是切线的,所以我删除了标签。这是java 问题,而不是c++ 问题。
  • 但是,当我用 c++ 阅读器加载同一个 BMP 文件时 -- 即使 C++ 标记仍然存在,这也不是足够的信息。您需要提及 C++ 用于读取图像的库,因为标准 C++ 中没有“C++ 图像阅读器”类。也许从那里开始,看看您使用的库是否具有库存 ImageIO 所没有的功能。
  • @PaulMcKenzie 这不是一个库,而是我自己编写的一个类。它本质上是读取整个 BMP,首先是标题,然后是实际像素值。
  • 见:stackoverflow.com/questions/8220567/…。没有给出解决方案,但给出了一个可能的解释为什么它不起作用。
  • @kosingas ...库存 ImageIO 没有的功能。 -- 查看上面的链接。与您链接的 C++ 代码的区别在于它是低级的并且可以控制一切,而 ImageIO 您依赖于 API 来支持您尝试读取的格式。

标签: java image pixel bmp


【解决方案1】:

感谢@camickr 用户,我找到了问题所在。 API 不理解这种 BMP 格式(很可能是标题数据),所以我使用这个网站完成了从 BMP 到 BMP 的转换 https://www.media.io/image-converter.html 效果很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-31
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多