JPEG 图像在我的 C 照片查看器中无法正确显示(使用 X11 和 jpeglib)

JPEG image doesn't display properly in my C photo viewer (using X11 and jpeglib)

提问人:Luidéo 提问时间:3/3/2023 更新时间:3/3/2023 访问量:70

问:

我正在为 Linux 制作一个简约且轻量级的 C 图片查看器。我使用库 X11 创建窗口,使用 jpeglib 读取 JPEG 文件。

我面临两个问题:

  • 我的程序没有完全显示图像,它只显示它的左下角。此外,它还显示该图像的多个部分,上面没有颜色。

  • 当图像的宽度大于其高度时,程序的显示方式与我描述的相同,但在左侧旋转 90°。

示例(对不起,质量低下,有些图像太大了,完全从我的程序中显示):

Example with a big tall image

Example with a big wide image

Example with a small wide image

代码如下:

#include    <stdio.h>
#include    <stdlib.h>
#include    <jpeglib.h>
#include    <X11/Xlib.h>
#include    <X11/Xutil.h>

int main(int argc, char** argv){

    // Ouverture du fichier JPEG - Opens the JPEG file
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    if (argc != 2){
        fprintf(stderr, "[ERREUR] Mauvais arguments entres, exemple : %s <fichier image>\n", argv[0]);
        return -1;
    }

    FILE* imgFile = fopen(argv[1], "rb");
    if(imgFile == NULL){
        fprintf(stderr, "[ERREUR] Impossible d'ouvrir le fichier \"%s\".\n", argv[1]);
        return -1;
    }

    printf("Ouverture du fichier \"%s\" reussie.\n", argv[1]);

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, imgFile);
    (void) jpeg_read_header(&cinfo, TRUE);
    (void) jpeg_start_decompress(&cinfo);

    printf("Largeur : %d\n", cinfo.output_width);
    printf("Hauteur : %d\n", cinfo.output_height);
    printf("Nombre de composantes : %d\n", cinfo.output_components);

    printf("Lecture de l'image en cours...\n");

    // Création de la fenêtre - Creates the window
    Display *display = XOpenDisplay(NULL);
    XEvent event;
    int screen = DefaultScreen(display);
    Window root = RootWindow(display, screen);

    if (display == NULL){
        fprintf(stderr, "[ERREUR] Impossible de créer la fenêtre.\n");
        return -1;
    }

    Window window = XCreateSimpleWindow(display, root, 0, 0, cinfo.output_width, cinfo.output_height, 0, 0, 0);

    printf("Creation de la fenetre reussie.\n");

    XMapWindow(display, window);

    // Boucle parcours de l'image - Image browsing loop
    unsigned char *image32 = (unsigned char *)malloc(cinfo.output_width*cinfo.output_height*4);
    unsigned char *p = image32;
    // Pour chaque ligne - for each line
    while (cinfo.output_scanline < cinfo.output_height){
        JSAMPROW buffer[1];
        int row_stride = cinfo.output_width * cinfo.output_components;
        buffer[0] = &image32[cinfo.output_scanline * row_stride];
        jpeg_read_scanlines(&cinfo, buffer, 1);
        // Pour chaque pixel de la ligne - for each pixel of the  line
        for(unsigned int i=0; i<cinfo.output_width; i++){
            *p++ = buffer[0][i * cinfo.output_components + 2]; // B
            *p++ = buffer[0][i * cinfo.output_components + 1]; // G
            *p++ = buffer[0][i * cinfo.output_components];     // R
            *p++ = 0;
        }
    }
    printf("Lecture de l'image terminee.\n");

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    fclose(imgFile);

    printf("Fermeture du fichier reussie.\n");

    XImage* ximage = XCreateImage(display, DefaultVisual(display, 0), DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char*)image32, cinfo.output_width, cinfo.output_height, 32, 0);

    printf("Creation de l'image reussie.\n");

    // Affichage de l'image - Shows the image
    XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, 0, 0, cinfo.output_height, cinfo.output_width);
    XFlush(display);
    printf("Affichage de l'image reussie.\n");

    while(XNextEvent(display, &event) == 0){

    }

    XDestroyImage(ximage);
    XUnmapWindow(display, window);
    XDestroyWindow(display, window);
    XCloseDisplay(display);

    printf("Fermeture de la fenetre reussie.\n");

    return 0;
}

这是我第一次使用这些库,所以我有点迷茫,尽管问题在于通道的数量,因为我尝试的所有图像都没有 alpha 通道,但删除像素循环中的线条对我没有帮助。我还认为图像的深度可能会导致这些问题,但我不知道我是否必须声明深度以及在哪里声明。*p++ = 0;

我应该怎么做才能解决这些问题?

感谢您的帮助。

C Linux JPEG x11

评论


答:

1赞 Mathieu 3/3/2023 #1

您的问题来自jpeg图像读取。

将解码后的行存储在图像缓冲区中,然后尝试写入 图像 () 从哪一点也开始*p++==buffer[0]image32

若要正确读取,应创建一个缓冲区来存储正在读取的行。

更正后的读数为:

// memory to store line
unsigned char *linebuffer = malloc(cinfo.output_width * cinfo.output_components);

while (cinfo.output_scanline < cinfo.output_height){
    JSAMPROW buffer[1];

    buffer[0] =  linebuffer;

    jpeg_read_scanlines(&cinfo, buffer, 1); 

    // Pour chaque pixel de la ligne - for each pixel of the  line
    for(unsigned int i=0; i<cinfo.output_width; i++){
        *p++ = linebuffer[i * cinfo.output_components + 2]; // B
        *p++ = linebuffer[i * cinfo.output_components + 1]; // G
        *p++ = linebuffer[i * cinfo.output_components];     // R
        *p++ = 0;
    }
}
free(linebuffer);

而且,你混合了宽度和高度XPutImage

// corrected call
XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, 0, 0, cinfo.output_width, cinfo.output_height);

评论

0赞 Luidéo 3/3/2023
这很完美,你的解释非常清楚。谢谢Mathieu!