Java ImageIO 正在读取 RGB 而不是 ARGB 数据
Java ImageIO is reading RGB instead of ARGB data
我正在为照片编辑器开发 GUI,但目前我无法从文件中加载 32 位 BMP 图像。一切都进行得很顺利,直到我开始尝试多层并将它们塑造成一个单一的。 (图层成型和图像保存由运行时 class 使用 c++ .exe 文件完成)
我使用 pixelFormer 软件制作了一个简单的 300x300 红色 bmp 图像,单个像素的值为 R:255 G:0 B:0 A:125
我注意到我下面的方法加载了一个 RGB,alpha 通道的默认值为 255,而 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++ reader 加载同一个 BMP 文件并将读取的数据保存到 json 文件时,我可以清楚地看到 alpha 值为 125位于 Java 方法 returns a 255.
Json 部分片段:
You can clearly see that pixels are in fact as they should be.
我可以创建一个 c++ 可执行文件来加载文件并 运行 使用运行时 Java 它 class 但我也不想使用那个 class经常来这里
更新:由于某些原因 System.out.println(img.getType()); returnsTYPE_INT_RGB
更新 2:对于那些可能认为我使用了某些 C++ 库的人,这里没有我的代码基于来自该网站的代码:https://solarianprogrammer.com/2018/11/19/cpp-reading-writing-bmp-images/
图像、图层和像素是我的自定义 classes.
Header 结构:
#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)
实际reader:
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.");
}
}
}
感谢用户@camickr,我发现了这个问题。 API 不理解这种 BMP 格式(最有可能是 header 数据)所以我使用这个网站完成了从 BMP 到 BMP 的转换
https://www.media.io/image-converter.html 结果很好。
我正在为照片编辑器开发 GUI,但目前我无法从文件中加载 32 位 BMP 图像。一切都进行得很顺利,直到我开始尝试多层并将它们塑造成一个单一的。 (图层成型和图像保存由运行时 class 使用 c++ .exe 文件完成)
我使用 pixelFormer 软件制作了一个简单的 300x300 红色 bmp 图像,单个像素的值为 R:255 G:0 B:0 A:125
我注意到我下面的方法加载了一个 RGB,alpha 通道的默认值为 255,而 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++ reader 加载同一个 BMP 文件并将读取的数据保存到 json 文件时,我可以清楚地看到 alpha 值为 125位于 Java 方法 returns a 255.
Json 部分片段: You can clearly see that pixels are in fact as they should be.
我可以创建一个 c++ 可执行文件来加载文件并 运行 使用运行时 Java 它 class 但我也不想使用那个 class经常来这里
更新:由于某些原因 System.out.println(img.getType()); returnsTYPE_INT_RGB
更新 2:对于那些可能认为我使用了某些 C++ 库的人,这里没有我的代码基于来自该网站的代码:https://solarianprogrammer.com/2018/11/19/cpp-reading-writing-bmp-images/ 图像、图层和像素是我的自定义 classes.
Header 结构:
#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)
实际reader:
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.");
}
}
}
感谢用户@camickr,我发现了这个问题。 API 不理解这种 BMP 格式(最有可能是 header 数据)所以我使用这个网站完成了从 BMP 到 BMP 的转换 https://www.media.io/image-converter.html 结果很好。