在 LCD (ARGB) 显示器上显示裁剪的 JPEG 时出现错误

Error hit when show a cropped JPEG on LCD (ARGB) display

提问人:wangt13 提问时间:6/21/2023 更新时间:6/25/2023 访问量:60

问:

我正在尝试裁剪一张大的 JPEG 照片并将其显示在 Linux 中的 LCD 显示屏上。

我正在使用 libjpeg 解码照片,并将 RGB 转换为 ARGB 以将裁剪的部分显示在 LCD 上。

但是裁剪后的部分在LCD中显示时颜色不正确,使用以下代码进行解码,裁剪,ARGB转换并将其显示在帧缓冲中。

    unsigned char* output_buffer = (unsigned char*)malloc(sizeof(unsigned char) * varinfo.xres * varinfo.yres * 4);

    int row_stride = cinfo.output_width * cinfo.output_components;

    unsigned long rgb_size;
    unsigned char *rgb_data;
    rgb_size = row_stride * cinfo.output_height;
    rgb_data = (unsigned char *)calloc(1, rgb_size);

    jpeg_skip_scanlines(&cinfo, y_offset);

    int last_line = cinfo.output_scanline + varinfo.yres;
    last_line = (last_line > cinfo.output_height) ? cinfo.output_height : last_line;

    unsigned char* output_ptr = output_buffer;
    int count = 0;
    while (cinfo.output_scanline < last_line) {
        unsigned char *buffer_array[1];
        buffer_array[0] = rgb_data + (count++) * row_stride;
        jpeg_read_scanlines(&cinfo, buffer_array, 1);
    }

    for (int y = 0; y < varinfo.yres; y++) {
        unsigned char* row_ptr = rgb_data + y * row_stride + (3 * x_offset);
        for (int x = 0; x < varinfo.xres; x++) {
            *output_ptr++ = *row_ptr++;  // Red
            *output_ptr++ = *row_ptr++;  // Green
            *output_ptr++ = *row_ptr++;  // Blue
            *output_ptr++ = 0xFF;  // Alpha
        }
    }

    memcpy(fb_mem, output_buffer, (sizeof(uint32_t) * varinfo.xres * varinfo.yres));


    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    free(output_buffer);
    free(rgb_data);

该代码可以裁剪照片,但是当裁剪的部分显示在LCD(帧缓冲)中时,颜色不正确。

执行官在调用时还会报告以下错误jpeg_finish_decompress(&cinfo);

Application transferred too few scanlines

我不知道上面的代码有什么问题。

Linux JPEG 帧缓冲 libjpeg

评论


答:

1赞 Bpwnz 6/23/2023 #1

我遇到了类似的问题,当我没有阅读整个传输的图像,而只阅读其中的一部分时,它就被调用了。因此,output_scanline场没有获取图像的高度,并且jpeg_finish_decompress函数导致了此错误。要做出决定,最好阅读整个图像,然后,在侧面的某个地方,将其裁剪为所需的大小。如果此选项不适合您,则可以将图像高度的值分配给output_scanline字段,但这是一个糟糕的选择。

评论

0赞 wangt13 6/25/2023
你是对的!如果我在调用之前将output_scanline硬编码为output_height,则警告会消失。我试图在打电话之前跳过剩余的扫描线,警告也消失了。所以现在最大的问题是裁剪JPEG图片的一部分后图片颜色错误。jpeg_finish_decompressjpeg_skip_scanlinesjpeg_finish_decompress
1赞 wangt13 6/25/2023 #2

颜色的问题来自代码。

for (int y = 0; y < varinfo.yres; y++) {
        unsigned char* row_ptr = rgb_data + y * row_stride + (3 * x_offset);
        for (int x = 0; x < varinfo.xres; x++) {
            *output_ptr++ = *row_ptr++;  // Red
            *output_ptr++ = *row_ptr++;  // Green
            *output_ptr++ = *row_ptr++;  // Blue
            *output_ptr++ = 0xFF;  // Alpha
        }
    }

要在 ARGB 中显示图片,32 位 ARGB 数据应为 0xAARRGGBB,但上述代码将像素生成为 0xAABBGGRR。所以正确的应该是这样的,

    for (int y = 0; y < varinfo.yres; y++) {
        unsigned char* row_ptr = rgb_data + y * row_stride + (cinfo.output_components * x_offset);
        for (int x = 0; x < varinfo.xres; x++) {
            int r = *row_ptr++;
            int g = *row_ptr++;
            int b = *row_ptr++;
            *output_ptr++ = b;
            *output_ptr++ = g;
            *output_ptr++ = r;
            *output_ptr++ = 0xFF;  // Alpha
        }
    }