i'm trying for learning purpose to create manually a png file from with OpenGL All other CHUNKS are okk (IHDR, pHY, IEND).
firstly, I read pixels by 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);
then, I created a function of generating scanlines like this: "each scanline is an array of RGB values in one screen line preceded by '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;
}
then, it seem it work, but when I test it my OpenGL program I get this :
[small png output][1]
also, i created a basic bmp File and it work perfectly
i try to find if it's any error, maybe it's in scanlines generation or misunderstanding with the PNG file format.
the invertArray() code :
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; }
SOLUTION I found where the error comes from, accordind to Mark Adler, the scanlines gemeration method was, wrong. Also, file was inverted because Opengl is only compatible with bottom left gormat, but png is a top left format, then we need to invert the pixel buffer before generating scanlines(ehat i tried with invertArray() method).
The last error was that the calling of deflate method and storing the deflated length was also wrong.
the whole deflating code :
// 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;
}
the bottom left to top left pixelbuffer flipping code :
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]: