jimp icon indicating copy to clipboard operation
jimp copied to clipboard

[Bug] Weird BMP load bug

Open elderapo opened this issue 6 years ago • 9 comments

Expected Behavior

The copied bmp file should be exactly the same as the original one.

Current Behavior

For some reason for this bmp file content gets moved/shifted. It does not happen for all the bmp files.

Failure Information (for bugs)

Steps to Reproduce

I've created minial reproducible repo:

git [email protected]:elderapo/jimp-bmp-bug.git
cd ./jimp-bmp-bug
yarn
yarn start

Screenshots from.bmp to.bmp

Context

  • Jimp Version: ^0.8.4
  • Operating System: Ubuntu 14.04
  • Node version: v11.10.0, v12.10.0

Failure Logs

The loading system for bmp files seems to be broken. Exact same thing happens when reading bmp file from disk, buffer. Even when file is saved to a different format it still gets shifted.

elderapo avatar Oct 05 '19 22:10 elderapo

I've been trying to run down an issue with bmp-js (which I believe jimp uses to read bmp files). AFAICT bmp-js does not use the offset value to the actual bitmap data contained in the header info of a bmp file. It just assumes that the bitmap follows on from the header.

I discovered this as I found that bmp files saved from GIMP have extra information in them that bmp files saved from both MSPaint and paint.net don't put in (see https://stackoverflow.com/questions/30505928/gimp-how-to-export-an-image-to-bmp-without-the-color-space-information-using-a for some information on this extra information )

Anyway - I ended up here and tried your from.bmp file out - and it has extra bytes between the header and the actual bitmap as well and I can replicate your fault in my code.

If I open from.bmp in Win MSPaint.exe and resave it as frompaint.bmp - the extra data is removed and reading the file works perfectly in jimp

I don't know how to resolve the issue since bmp-js doesn't seem to be maintained anymore

cymplecy avatar Oct 15 '19 21:10 cymplecy

FTAOD - I'm confidant I can fix the code (at least for 24bit bmp files) but I don't know how to get any code changes back up to jimp

cymplecy avatar Oct 15 '19 21:10 cymplecy

I have a fork of bmp-ts I plan to integrate at some point. If you can find and fix the bug there I'll merge the changes into jimp

https://github.com/hipstersmoothie/bmp-ts

hipstersmoothie avatar Oct 15 '19 22:10 hipstersmoothie

Looking at your .ts code, it seems to check the header size and make appropriate adjustments so its prob already fixed.

cymplecy avatar Oct 16 '19 07:10 cymplecy

Can confirm. This bug is no longer the case after switching to bmp-ts.

elderapo avatar Oct 24 '19 21:10 elderapo

Is there anything I can do to help get this merged?

elderapo avatar Nov 02 '19 15:11 elderapo

Any update on this issue? It is still there in the lastet version (0.22.8).

sxwei123 avatar Jul 20 '23 02:07 sxwei123

The GIMP wrote bugs, but I can't registe a gimp gitlab account to open an issue, can anyone do it for me and all those people?

They website is: https://gitlab.gnome.org/GNOME/gimp/-/issues


My bug example is two picture and a python function to read bmp file: dnf hero2_simplified_quick_mode


If you convert the first original image from png to bmp by using GIMP, you get a broken image.

I read that bmp file by using following python code:

#pybmp/__init__.py

from struct import unpack


class BMP:
    # author: rocketeerLi, https://blog.csdn.net/rocketeerLi/article/details/84929516
    def __init__(self, filePath) :
        file = open(filePath, "rb")
        # 读取 bmp 文件的文件头    14 字节
        self.bfType = unpack("<h", file.read(2))[0]       # 0x4d42 对应BM 表示这是Windows支持的位图格式
        self.bfSize = unpack("<i", file.read(4))[0]       # 位图文件大小
        self.bfReserved1 = unpack("<h", file.read(2))[0]  # 保留字段 必须设为 0 
        self.bfReserved2 = unpack("<h", file.read(2))[0]  # 保留字段 必须设为 0 
        self.bfOffBits = unpack("<i", file.read(4))[0]    # 偏移量 从文件头到位图数据需偏移多少字节(位图信息头、调色板长度等不是固定的,这时就需要这个参数了)
        # 读取 bmp 文件的位图信息头 40 字节
        self.biSize = unpack("<i", file.read(4))[0]       # 所需要的字节数
        self.biWidth = unpack("<i", file.read(4))[0]      # 图像的宽度 单位 像素
        self.biHeight = unpack("<i", file.read(4))[0]     # 图像的高度 单位 像素
        self.biPlanes = unpack("<h", file.read(2))[0]     # 说明颜色平面数 总设为 1
        self.biBitCount = unpack("<h", file.read(2))[0]   # 说明比特数

        self.biCompression = unpack("<i", file.read(4))[0]  # 图像压缩的数据类型
        self.biSizeImage = unpack("<i", file.read(4))[0]    # 图像大小
        self.biXPelsPerMeter = unpack("<i", file.read(4))[0]# 水平分辨率
        self.biYPelsPerMeter = unpack("<i", file.read(4))[0]# 垂直分辨率
        self.biClrUsed = unpack("<i", file.read(4))[0]      # 实际使用的彩色表中的颜色索引数
        self.biClrImportant = unpack("<i", file.read(4))[0] # 对图像显示有重要影响的颜色索引的数目
        self.bmp_data = []

        if self.biBitCount != 24 :
            raise Exception("(we need 24bit rgb bmp) 输入的图片比特值为 :" + str(self.biBitCount) + "\t 与程序不匹配")

        for height in range(self.biHeight) :
            bmp_data_row = []
            # 四字节填充位检测
            count = 0
            for width in range(self.biWidth) :
                bmp_data_row.append([unpack("<B", file.read(1))[0], unpack("<B", file.read(1))[0], unpack("<B", file.read(1))[0]])
                count = count + 3
            # bmp 四字节对齐原则
            while count % 4 != 0 :
                file.read(1)
                count = count + 1
            self.bmp_data.append(bmp_data_row)
        self.bmp_data.reverse()
        file.close()

        self.rgb_data = [None] * self.biHeight
        for row in range(self.biHeight) :
            one_row = [None] * self.biWidth
            for col in range(self.biWidth) :
                b = self.bmp_data[row][col][0]
                g = self.bmp_data[row][col][1]
                r = self.bmp_data[row][col][2]
                one_row[col] = [r,g,b,255]
            self.rgb_data[row] = one_row


def read_bmp_from_file(path):
    """
    return (height, width, raw_data)

    The newest GIMP or online png to bmp converter, they have used a bug version of bmp c++ library, so the bmp image you get from those sources will be broken in columns. If you use oldest ffmpeg to convert mp4 to bmp images, it would work fine.
    """
    img = BMP(path)

    height, width = img.biHeight, img.biWidth
    data = img.rgb_data

    return height, width, data


__all__ = [
    "BMP",
    "read_bmp_from_file",
]

yingshaoxo avatar Jul 18 '24 00:07 yingshaoxo

According to an issue, you can also solve this bug by using:

The issue arises when an image is exported as BMP using GIMP and color space information is written to it.

To avoid this issue, select "Do not write color space information" under "Compatibility Options" when exporting as BMP.

https://github.com/jimp-dev/jimp/issues/626#issuecomment-426049082

yingshaoxo avatar Jul 18 '24 00:07 yingshaoxo