Writing PNG files in C++

Red Squirrel

No Lifer
May 24, 2003
68,452
12,609
126
www.anyf.ca
I'm writing an easy to use wrapper class for libpng and I'm having trouble with the writing part. There's very little resources online that talk about how to actually write, as most examples just show a png file being read then being written, so it never goes into the details of writing 1 pixel at a time. This is what I got so far as a write command but this does not compile, the trouble is near the end with the actual write loop:

Code:
		// Write image data
		int x, y;
		for (y=0 ; y<m_height ; y++) 
		{
			for (x=0 ; x<m_width ; x++) 
			{
				pngpixel * pixel = GetPixel(x,y);
				
				row[x]=(png_byte)pixel->GetRed();
				row[x+1]=(png_byte)pixel->GetGreen();
				row[x+2]=(png_byte)pixel->GetBlue();
				row[x+3]=(png_byte)pixel->GetAlpha();
			}
			png_write_row(png_ptr, row);
		}

What am I doing wrong and how do I get it to work? Those Get functions return an unsigned char from 0 to 255.

Here is the full function:


Code:
	bool rspng::WriteToFile(string pngfile="")
	{
		if(pngfile=="")pngfile=m_filename;
		
		Debug(1,"Writing to " + pngfile);
		
		
		//init variables/structs:
		int code = 0;
		FILE *fp;
		png_structp png_ptr;
		png_infop info_ptr;
		png_bytep * row=NULL;
		
		Debug(3,"Initializing...");
		
		// Open file for writing: (binary mode)
		fp = fopen(pngfile.c_str(), "wb");
		if (fp == NULL)
		{
			Debug(1, "Could not open file " + pngfile + " for writing");
			return false;
		}
		
		//initialize write structure:		
		png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
		if (png_ptr == NULL) 
		{
			Debug(1,"Could not allocate write struct");
			if (fp != NULL)fclose(fp);
			return false;
		}

		// Initialize info structure:
		info_ptr = png_create_info_struct(png_ptr);
		if (info_ptr == NULL) 
		{
			Debug(1,"Could not allocate info struct");

			if (fp != NULL) fclose(fp);
			if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);			
			return false;
		}		
		
		// Setup Exception handling
		if (setjmp(png_jmpbuf(png_ptr)))
		{
			Debug(0, "Error during png creation");
			
			if (fp != NULL) fclose(fp);
			if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);			
			if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
			return false;
		}
		
		
		png_init_io(png_ptr, fp);

		// Write header (8 bit colour depth)
		png_set_IHDR(png_ptr, info_ptr, m_width, m_height,8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

		// Set title

		//png_text title_text;
		//title_text.compression = PNG_TEXT_COMPRESSION_NONE;
		//title_text.key = "rspng";   //TODO: figure out how to use m_title.c_str();
		//title_text.text = "generated by rspng"; //TODO: figure out how to m_desc.c_str();
		//png_set_text(png_ptr, info_ptr, &title_text, 1);
		

		png_write_info(png_ptr, info_ptr);
		
		Debug(1,"Writing png data");
		
		// Allocate memory for one row (4 bytes per pixel - RGBA)
		//row = (png_bytep) malloc(4 * m_width * sizeof(png_byte));
		
		row = new png_bytep[4 * m_width * sizeof(png_byte)];

		// Write image data
		int x, y;
		for (y=0 ; y<m_height ; y++) 
		{
			for (x=0 ; x<m_width ; x++) 
			{
				pngpixel * pixel = GetPixel(x,y);
				
				row[x]=(png_byte)pixel->GetRed();  //line 474
				row[x+1]=(png_byte)pixel->GetGreen();
				row[x+2]=(png_byte)pixel->GetBlue();
				row[x+3]=(png_byte)pixel->GetAlpha();
			}
			png_write_row(png_ptr, row);  //line 479
		}

		// End write
		png_write_end(png_ptr, NULL);
		
		if (fp != NULL) fclose(fp);
		if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
		if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		if (row != NULL) delete[] row;
   
   
		Debug(1,"Done writing to " + pngfile + ".");
	}

This is the compile error that I get:

Code:
../../rslib/include/rspng/rspng.cpp: In member function &#8216;bool rslib::rspng::WriteToFile(std::string)&#8217;:
../../rslib/include/rspng/rspng.cpp:474: error: invalid conversion from &#8216;unsigned char&#8217; to &#8216;png_byte*&#8217;
../../rslib/include/rspng/rspng.cpp:475: error: invalid conversion from &#8216;unsigned char&#8217; to &#8216;png_byte*&#8217;
../../rslib/include/rspng/rspng.cpp:476: error: invalid conversion from &#8216;unsigned char&#8217; to &#8216;png_byte*&#8217;
../../rslib/include/rspng/rspng.cpp:477: error: invalid conversion from &#8216;unsigned char&#8217; to &#8216;png_byte*&#8217;
../../rslib/include/rspng/rspng.cpp:479: error: cannot convert &#8216;png_byte**&#8217; to &#8216;png_byte*&#8217; for argument &#8216;2&#8217; to &#8216;void png_write_row(png_struct*, png_byte*)&#8217;


Edit: Oh and just realized a logic error in how I'm assigning pixels but that's not the problem right now. It would still "work" just not write the proper data. I fixed that in my code but still need to get this to compile to test it.
 
Last edited:

Red Squirrel

No Lifer
May 24, 2003
68,452
12,609
126
www.anyf.ca
NM I got it! I think....

Had to change

if (png_ptr) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
to
if (png_ptr) png_destroy_write_struct(&png_ptr,&info_ptr);

Time for bed.... Now that I got this working I can do the fun stuff tomorrow like line plotting and stuff.
------------


Ok from just screwing around I almost have it. I think it may turned out it in fact was a logic error in my loop, I had not paid much attention to that since I did not really care what pixels were being written or in what order till I can get it to actually work but think it was trying to read past the end of the array or something. It works, but valgrind still complains about unfreed memory, which is odd, because it's not even a pointer. Here is the function, and the error:

Code:
	bool rspng::WriteToFile(string pngfile="")
	{
		if(pngfile=="")pngfile=m_filename;
		
		Debug(1,"Writing to " + pngfile);
		
		if(m_width<1 || m_height<1 || m_imagedata==NULL || pngfile=="")
		{
			Debug(1,"No data to write or no file name specified");
			return false;
		}
		
		
		
		//init variables/structs:
		int code = 0;
		FILE *fp;
		png_structp png_ptr;
		png_infop info_ptr;
		
		
		Debug(3,"Initializing...");
		
		// Open file for writing: (binary mode)
		fp = fopen(pngfile.c_str(), "wb");
		if (fp == NULL)
		{
			Debug(1, "Could not open file " + pngfile + " for writing");
			return false;
		}
		
		//initialize write structure:		
		png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
		if (!png_ptr) 
		{
			Debug(1,"Could not allocate write struct");
			if (fp != NULL)fclose(fp);
			return false;
		}

		// Initialize info structure:
		info_ptr = png_create_info_struct(png_ptr);  //line 428
		if (!info_ptr) 
		{
			Debug(1,"Could not allocate info struct");

			if (fp != NULL) fclose(fp);
			if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);			
			return false;
		}		
		
		png_byte * row=NULL;
		
		// Setup Exception handling
		if (setjmp(png_jmpbuf(png_ptr)))
		{
			Debug(0, "Error during png creation");
			
			if (fp != NULL) fclose(fp);			
			if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);						
			if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);			
			if (row!=NULL) delete[] row;
			return false;
		}
		
		
		png_init_io(png_ptr, fp);

		// Write header (8 bit colour depth)
		png_set_IHDR(png_ptr, info_ptr, m_width, m_height,8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

		// Set title

		//png_text title_text;
		//title_text.compression = PNG_TEXT_COMPRESSION_NONE;
		//title_text.key = "rspng";   //TODO: figure out how to use m_title.c_str();
		//title_text.text = "generated by rspng"; //TODO: figure out how to m_desc.c_str();
		//png_set_text(png_ptr, info_ptr, &title_text, 1);
		

		png_write_info(png_ptr, info_ptr);
		
		Debug(1,"Writing png data");
		
		// Allocate memory for one row (4 bytes per pixel - RGBA)
		//row = (png_bytep) malloc(4 * m_width * sizeof(png_byte));
		
		row = new png_byte[4 * m_width * sizeof(png_byte)];

		// Write image data
		int x, y;
		int arrayloc=0;
		for (y=0 ; y<m_height ; y++) 
		{
			arrayloc=0;
			for (x=0 ; x<m_width ; x++) 
			{
				pngpixel * pixel = GetPixel(x+1,y+1);
				
				row[(arrayloc*4)]=(png_byte)pixel->GetRed();
				row[(arrayloc*4)+1]=(png_byte)pixel->GetGreen();
				row[(arrayloc*4)+2]=(png_byte)pixel->GetBlue();
				row[(arrayloc*4)+3]=(png_byte)pixel->GetAlpha();
				
				arrayloc++;
			}
			png_write_row(png_ptr, row);
		}

		// End write
		png_write_end(png_ptr, NULL);
		
		if (fp != NULL) fclose(fp);
		if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
		if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		if (row != NULL) delete[] row;
   
   
		Debug(1,"Done writing to " + pngfile + ".");
	}

The error:

Code:
==5584== HEAP SUMMARY:
==5584==     in use at exit: 928 bytes in 2 blocks
==5584==   total heap usage: 12,276 allocs, 12,274 frees, 4,845,509 bytes allocated
==5584== 
==5584== Searching for pointers to 2 not-freed blocks
==5584== Checked 191,304 bytes
==5584== 
==5584== 464 bytes in 1 blocks are definitely lost in loss record 1 of 2
==5584==    at 0x4A06A2E: malloc (vg_replace_malloc.c:270)
==5584==    by 0x3A8EE1BF7F: ??? (in /usr/lib64/libpng12.so.0.49.0)
==5584==    by 0x3A8EE05B22: png_create_info_struct (in /usr/lib64/libpng12.so.0.49.0)
==5584==    by 0x41BB0C: rslib::rspng::WriteToFile(std::string) (rspng.cpp:428)
==5584==    by 0x41CD56: main (pngtest.cpp:25)
==5584== 
==5584== 464 bytes in 1 blocks are definitely lost in loss record 2 of 2
==5584==    at 0x4A06A2E: malloc (vg_replace_malloc.c:270)
==5584==    by 0x3A8EE1BF7F: ??? (in /usr/lib64/libpng12.so.0.49.0)
==5584==    by 0x3A8EE05B22: png_create_info_struct (in /usr/lib64/libpng12.so.0.49.0)
==5584==    by 0x41BB0C: rslib::rspng::WriteToFile(std::string) (rspng.cpp:428)
==5584==    by 0x41CEA2: main (pngtest.cpp:44)
==5584== 
==5584== LEAK SUMMARY:
==5584==    definitely lost: 928 bytes in 2 blocks
==5584==    indirectly lost: 0 bytes in 0 blocks
==5584==      possibly lost: 0 bytes in 0 blocks
==5584==    still reachable: 0 bytes in 0 blocks
==5584==         suppressed: 0 bytes in 0 blocks
==5584== 
==5584== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 523 from 18)
--5584-- 
--5584-- used_suppression:    517 zlib-1.2.x trickyness (1a): See http://www.zlib.net/zlib_faq.html#faq36
--5584-- used_suppression:      4 U1004-ARM-_dl_relocate_object
--5584-- used_suppression:      2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a
==5584== 
==5584== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 523 from 18)


I marked line 428 in the code which is where it's saying memory is not being freed. Why is that? Is there another png cleanup routine I might have to call? Thanks in advance.
 
Last edited:

Red Squirrel

No Lifer
May 24, 2003
68,452
12,609
126
www.anyf.ca
GetPixel returns a pngpixel type (as pointer). The memory for that is already allocated elsewhere in the class so here I just need a pointer which goes out of scope before the memory is deallocated so it's safe. The GetPixel() is just a way to make it easier to get a pixel at specific coords as they are stored in a 2D array so it uses the width and height to figure out where the pixel is.
 
sale-70-410-exam    | Exam-200-125-pdf    | we-sale-70-410-exam    | hot-sale-70-410-exam    | Latest-exam-700-603-Dumps    | Dumps-98-363-exams-date    | Certs-200-125-date    | Dumps-300-075-exams-date    | hot-sale-book-C8010-726-book    | Hot-Sale-200-310-Exam    | Exam-Description-200-310-dumps?    | hot-sale-book-200-125-book    | Latest-Updated-300-209-Exam    | Dumps-210-260-exams-date    | Download-200-125-Exam-PDF    | Exam-Description-300-101-dumps    | Certs-300-101-date    | Hot-Sale-300-075-Exam    | Latest-exam-200-125-Dumps    | Exam-Description-200-125-dumps    | Latest-Updated-300-075-Exam    | hot-sale-book-210-260-book    | Dumps-200-901-exams-date    | Certs-200-901-date    | Latest-exam-1Z0-062-Dumps    | Hot-Sale-1Z0-062-Exam    | Certs-CSSLP-date    | 100%-Pass-70-383-Exams    | Latest-JN0-360-real-exam-questions    | 100%-Pass-4A0-100-Real-Exam-Questions    | Dumps-300-135-exams-date    | Passed-200-105-Tech-Exams    | Latest-Updated-200-310-Exam    | Download-300-070-Exam-PDF    | Hot-Sale-JN0-360-Exam    | 100%-Pass-JN0-360-Exams    | 100%-Pass-JN0-360-Real-Exam-Questions    | Dumps-JN0-360-exams-date    | Exam-Description-1Z0-876-dumps    | Latest-exam-1Z0-876-Dumps    | Dumps-HPE0-Y53-exams-date    | 2017-Latest-HPE0-Y53-Exam    | 100%-Pass-HPE0-Y53-Real-Exam-Questions    | Pass-4A0-100-Exam    | Latest-4A0-100-Questions    | Dumps-98-365-exams-date    | 2017-Latest-98-365-Exam    | 100%-Pass-VCS-254-Exams    | 2017-Latest-VCS-273-Exam    | Dumps-200-355-exams-date    | 2017-Latest-300-320-Exam    | Pass-300-101-Exam    | 100%-Pass-300-115-Exams    |
http://www.portvapes.co.uk/    | http://www.portvapes.co.uk/    |