opengl 我的PNG IDAT CHUNK数据有什么问题?

b1uwtaje  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(124)

我正在尝试学习的目的,手动创建一个png文件,从与OpenGL所有其他块是ok(IHDR,pHY,IEND)。
首先,用OpenGL读取像素:

int s_width = glutGet(GLUT_SCREEN_WIDTH), s_height = glutGet(GLUT_SCREEN_HEIGHT);       
int pixelArraySize = s_width*s_height*_glColorChannels;
unsigned char *pixelsArrayInfo = (unsigned char*)malloc(pixelArraySize);               

glPixelStorei(GL_PACK_ALIGNMENT, 1);                                                   
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, (unsigned short)s_width, (unsigned short)s_height, GL_RGB, GL_UNSIGNED_BYTE, pixelsArrayInfo);

然后,我创建了一个生成扫描线的函数,像这样:“每条扫描线是一个屏幕行中的RGB值的数组,前面是”0““

unsigned char *generateScanlines(unsigned char *pixels, int s_width, int s_height)
{
    int eachScanlineLength = 1 + s_width*3;
    unsigned char *finalOutput = (unsigned char*)malloc(s_height*eachScanlineLength);
    for(int i=0; i<s_height; i++){
        finalOutput[i*eachScanlineLength] = 0;
        copyElement(finalOutput, pixels, i*eachScanlineLength,  (i+1)*eachScanlineLength, i*eachScanlineLength+1);
    }
    return finalOutput;
}

void copyElement(unsigned char *dest, unsigned char *src, int src_debut, int src_fin, int dest_debut)
{
    for(int i=src_debut, j=dest_debut; i<src_fin; i++, j++){
        dest[j] = src[i];
    }
}

unsigned char *deflateDatas(unsigned char *pixels, int s_width, int s_height, int *deflatedDataLength)
{
    unsigned char *deflated = (unsigned char*)malloc(compressBound(s_height*(1 + s_width*3)));
    unsigned char *scanlines = invertArray(generateScanlines(pixels, s_width, s_height), s_height*(1 + s_width*3));

    z_stream defstream;
    defstream.zalloc = Z_NULL;
    defstream.zfree = Z_NULL;
    defstream.opaque = Z_NULL;
    defstream.avail_in = (uInt)(s_height*(1 + s_width*3));
    defstream.next_in = (Bytef *)scanlines;
    defstream.avail_out = (uInt)(compressBound(s_height*(1 + s_width*3)));
    defstream.next_out = (Bytef *)deflated;

    deflateInit(&defstream, 0);
    deflate(&defstream, Z_FINISH);
    deflateEnd(&defstream);

    *deflatedDataLength = compressBound(s_height*(1 + s_width*3));

    return deflated;
}

然后,它似乎工作了,但是当我用OpenGL程序测试它时,我得到了这个:
[小png输出][1]
另外,我创建了一个基本的BMP文件,它的工作完美
我试着找出它是否有任何错误,也许是在扫描线生成或与PNG文件格式的误解。
invertArray()代码:

unsigned char *invertArray(unsigned char *myArray, int arrayEnd)
{    unsigned char *invertedtableau = (unsigned char*)malloc(arrayEnd*sizeof(unsigned char));    
for(int i=0 ; i<=arrayEnd ; i++)    
{        invertedtableau[i] = myArray[arrayEnd-i];    
}    
return invertedtableau;                           }

解决方案我找到了错误的来源,根据Mark Adler的说法,扫描线生成方法是错误的。此外,文件被反转,因为OpenGL只兼容左下角的格式,而png是左上角的格式,那么我们需要在生成扫描线之前反转像素缓冲区(我尝试过使用invertArray()方法)。

最后一个错误是调用deflate方法和存储收缩长度也是错误的。
整个紧缩代码:

// generating scanline function
unsigned char *generateScanlines(unsigned char *pixels, int s_width, int s_height, int colorChannel)
{
    int eachScanlineLength = 1 + s_width * colorChannel, i = 1, j = 0;                            // one scanline length
    unsigned char *scanlines = (unsigned char *)malloc(s_height * eachScanlineLength); // memory allocation for the scanline output

    memset(scanlines, 0, s_height * eachScanlineLength * sizeof(char)); // we set all the output values to 0

    // then we copy pixels elements in the output, skipping the fisrt output values, that should ever be 0
    for (i = 1, j = 0; i < s_height && j < s_height; i++, j++)
        memcpy(scanlines + 1 + (i - 1) * eachScanlineLength, pixels + j * (eachScanlineLength - 1), eachScanlineLength - 1);

    memcpy(scanlines + 1 + (i - 1) * eachScanlineLength, pixels + j * (eachScanlineLength - 1), eachScanlineLength - 1);

    return scanlines;
}

// deflating IDAT CHUNK data algorithm
unsigned char *deflateDatas(unsigned char *pixels, int s_width, int s_height, int colorChannel, int *deflatedLen)
{
    unsigned long inLen = s_height * (1 + s_width * colorChannel), tmpLen = 0;          // input len of scanlines datas
    unsigned char *scanlines = generateScanlines(pixels, s_width, s_height, colorChannel); // generating scanlines from the pixels

    unsigned char *deflatedDatas = NULL; // setting up the deflated datas output
    int result = 0;

    // initialising zlib
    z_stream defstream;
    defstream.zalloc = Z_NULL;
    defstream.zfree = Z_NULL;
    defstream.opaque = Z_NULL;
    defstream.avail_in = inLen;
    defstream.next_in = (Bytef *)scanlines;
    defstream.avail_out = 0;
    defstream.next_out = (Bytef *)deflatedDatas;

    if ((result = deflateInit(&defstream, Z_DEFAULT_COMPRESSION)) == Z_OK)
    {
        // calculate the actual length and update zlib structure
        unsigned long estimateLen = deflateBound(&defstream, inLen);
        deflatedDatas = (unsigned char *)malloc(estimateLen);
        if (deflatedDatas != NULL)
        {
            // updation zlib configuration
            defstream.avail_out = (uInt)estimateLen;
            defstream.next_out = (Bytef *)deflatedDatas;

            // do the compression
            deflate(&defstream, Z_FINISH);
            tmpLen = (unsigned char *)defstream.next_out - deflatedDatas;
        }
    }
    deflateEnd(&defstream);       // end of deflating algorithm
    *deflatedLen = tmpLen; // copying the defalted data length to the IDAT->length
    free(scanlines);

    return deflatedDatas;
}

左下角到左上角的pixelbuffer翻转代码:

void flipPixels(unsigned char *pixelsArray, int s_width, int s_heigth, int colorChannel)
{
    int totalLength = s_width * s_heigth * colorChannel;
    int oneLineLength = s_width * colorChannel;
    unsigned char *tmp = (unsigned char *)malloc(totalLength * sizeof(unsigned char));
    memcpy(tmp, pixelsArray, totalLength);
    for (int i = 0; i < s_heigth; i++)
        memcpy(pixelsArray + oneLineLength * i, tmp + totalLength - oneLineLength * (i + 1), oneLineLength);
    free(tmp);
}

  [1]:

https://i.stack.imgur.com/5khCg.png

k5ifujac

k5ifujac1#

我们没有看到所有相关的代码,但首先,你似乎故意通过反转字节来破坏图像数据。不要这样做。删除对invertArray()的调用。
第二,返回的不是压缩数据的大小,而是压缩数据的上限估计值。
使用deflateBound()(在调用deflateInit()之后),而不是compressBound()。调用deflateBound()一次(而不是三次),并将答案保存在unsigned long bound中。返回压缩数据的大小,即bound - defstream.avail_out
最后,你没有压缩!deflateInit()的第二个参数应该是Z_DEFAULT_COMPRESSION0以外的其他参数,这意味着没有压缩。
您的示例中IDAT块的CRC不正确,因此在构造该块时没有显示的代码中还有其他错误。
即使我撤消了invertArray()(它本身有另一个错误),我得到的仍然是混乱的图像,似乎每行都删除了一个字节。
除非您提供 * 所有 * 代码,否则我们无法为您提供帮助。有许多错误,您不知道它们在哪里。

相关问题