在 C 中操作 PNG 图像导致内存泄漏或图像上出现白色条纹

Manipulating a PNG image in C leading to either memory leaks or white stripes on image

我们应该制作一个处理 PNG 图片的程序。其中一个选项是放大图像,使其大小加倍。我们从老师那里得到了一些函数,用于将图像读取和保存到文件中。

// This function reads an image from the filename source. Will store
// the image in the Pixel 2dim array and allocate the needed space.
void readImage(char *filename, Image *img);

// This function actually writes out the PNG image file. The string 'title' is
// also written into the image file
void writeImage(char* filename, Image *img);

这是一个学校项目,但我对编程真的很陌生,几周来我一直盯着这段代码看,没有任何实际进展,如果有人能指出我正确的方向,我将不胜感激。

这是我们正在使用的两个结构,是老师给的。

typedef struct pixel
{
    uint8_t r;
    uint8_t g;
    uint8_t b;
} Pixel;

typedef struct image
{
    Pixel **pixels;
    unsigned int height;
    unsigned int width;
} Image;

一个版本的代码,其中放大功能有效,但存在内存泄漏。

void imageEnlarge(Image *pic)
{

    temp.height = plain.height;
    temp.width = plain.width;

    temp.pixels = (Pixel**)malloc(sizeof(Pixel*) * temp.height);
    for (unsigned int h = 0; h < plain.height; h++)
    {
        temp.pixels[h] = (Pixel*)malloc(sizeof(Pixel) * temp.width);
        for (unsigned int w = 0; w < plain.width; w++)
        {
            temp.pixels[h][w] = plain.pixels[h][w];
        }
    }

    for (unsigned int h = 0; h < plain.width; h++)
    {
        free(plain.pixels[h]);
    }
    free(plain.pixels);

    plain.height = temp.height * 2;
    plain.width = temp.width * 2;

    plain.pixels = (Pixel**)malloc(sizeof(Pixel*) * plain.height);
    for (unsigned int h = 0; h < plain.height; h++)

   {
        plain.pixels[h] = (Pixel*)malloc(sizeof(Pixel) * plain.width);
        for (unsigned int w = 0; w < plain.width; w++)
        {
            plain.pixels[h][w] = tempP.pixels[h * tempP.height / plain.height][w * tempP.width / plain.width];
        }
    }

    for (unsigned int h = 0; h < temp.width; h++)
    {
        free(temp.pixels[h]);
    }
    free(temp.pixels);
}

另一个版本,其中放大后的图像更大,但整个图像中每两个像素都是白色的,就好像像素的大小增加了一倍但没有完全填满像素。没有内存泄漏!

void imageEnlarge(Image *pic)
{
    temp.height = plain.height * 2;
    temp.width = plain.width * 2;

    temp.pixels = (Pixel**)malloc(sizeof(Pixel*) * temp.height);
    for (unsigned int h = 0; h < temp.height; h++)
    {
        temp.pixels[h] = (Pixel*)malloc(sizeof(Pixel) * temp.width);
}
for (unsigned int h = 0; h < plain.height; h++)
    {
        for (unsigned int w = 0; w < plain.width; w++)
        {
            temp.pixels[h * temp.height / plain.height][w * temp.width / plain.width] = plain.pixels[h][w];
        }
    }
    freePixels(&plain);

    plain = temp;

您的第二次尝试(使用白色像素)非常接近。这里的问题是,对于输入中的每个像素 (plain),输出中有 four 个像素 (temp) 但你只设置了其中之一。

为确保设置输出中的每个像素,循环遍历 temp 而不是 plain 的高度和宽度并设置每个像素temp 的像素到 plain 的对应像素。这样的事情应该有效:

void imageEnlarge(Image *pic)
{
    temp.height = plain.height * 2;
    temp.width = plain.width * 2;

    temp.pixels = (Pixel**)malloc(sizeof(Pixel*) * temp.height);
    for (unsigned int h = 0; h < temp.height; h++)
    {
        temp.pixels[h] = (Pixel*)malloc(sizeof(Pixel) * temp.width);
    }

    for (unsigned int h = 0; h < temp.height; h++)
    {
        for (unsigned int w = 0; w < temp.width; w++)
        {
            temp.pixels[h][w] = plain.pixels[h * plain.height / temp.height][w * plain.width / temp.width];
        }
    }

    freePixels(&plain);
    plain = temp;
}

如果您使用 2 以外的比例因子,这也应该有效。