summaryrefslogblamecommitdiffstatshomepage
path: root/src/tools/pngcmp.cpp
blob: 480f9fadb14b3237a43cda7531ad3a59b6b00f5b (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                

                                                                            
            


                                      

                                                                             






                     


                  

              
 



                                                                            
                                 




                                                                            
                                                                                                                       










                                                                            





                                                                                


                                          
 




                                                                                  
                                             









                                                   
                                                                                                                      




                                    
                                  
                                    
                        

                                   
                                                                       
                   
         
                                                                                               



                                   
                                                       
                     
                   
         
                                                                                               



                                   
                                                                       
                   
         
                                                                                               



                                   
                                                       
                     
                   
         
                                                                                               



                                                                                                 
                            


                                                                                                      
                                                                     
         

                                                       

                                       
                      











                                                            
                                                                              


                                                                                                    
                                                                               



                                                    
 
                                                              
                                                                             
                                                        
                                                   
                 




                                                                                                                          

                                                      
                                                          


                                                         
                                                                           
                                                                 
                                                                           





                                                                                      
                                                                                                      
                           
                 
                                                                                                          

                                   
                                                                                         
                             
                           
                 
                                                                                                           











                                               
                                              

                     
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    pngcmp.c

    PNG comparison (based on regrep.c)

****************************************************************************/

#include "corefile.h"
#include "png.h"

#include "osdfile.h"

#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <new>


/***************************************************************************
    CONSTANTS & DEFINES
***************************************************************************/

#define BITMAP_SPACE            4

/***************************************************************************
    PROTOTYPES
***************************************************************************/

static int generate_png_diff(const std::string& imgfile1, const std::string& imgfile2, const std::string& outfilename);

/***************************************************************************
    MAIN
***************************************************************************/

/*-------------------------------------------------
    main - main entry point
-------------------------------------------------*/

int main(int argc, char *argv[])
{
	/* first argument is the directory */
	if (argc < 4)
	{
		fprintf(stderr, "Usage:\npngcmp <image1> <image2> <outfile>\n");
		return 10;
	}
	std::string imgfilename1(argv[1]);
	std::string imgfilename2(argv[2]);
	std::string outfilename(argv[3]);

	try {
		return generate_png_diff(imgfilename1, imgfilename2, outfilename);
	}
	catch(...)
	{
		printf("Exception occurred");
		return 1000;
	}
}

/*-------------------------------------------------
    generate_png_diff - create a new PNG file
    that shows multiple differing PNGs side by
    side with a third set of differences
-------------------------------------------------*/

static int generate_png_diff(const std::string& imgfile1, const std::string& imgfile2, const std::string& outfilename)
{
	bitmap_argb32 bitmap1;
	bitmap_argb32 bitmap2;
	bitmap_argb32 finalbitmap;
	int width, height, maxwidth;
	util::core_file::ptr file;
	std::error_condition filerr;
	int error = 100;

	/* open the source image */
	filerr = util::core_file::open(imgfile1, OPEN_FLAG_READ, file);
	if (filerr)
	{
		printf("Could not open %s (%s)\n", imgfile1.c_str(), filerr.message().c_str());
		goto error;
	}

	/* load the source image */
	filerr = util::png_read_bitmap(*file, bitmap1);
	file.reset();
	if (filerr)
	{
		printf("Could not read %s (%s)\n", imgfile1.c_str(), filerr.message().c_str());
		goto error;
	}

	/* open the source image */
	filerr = util::core_file::open(imgfile2, OPEN_FLAG_READ, file);
	if (filerr)
	{
		printf("Could not open %s (%s)\n", imgfile2.c_str(), filerr.message().c_str());
		goto error;
	}

	/* load the source image */
	filerr = util::png_read_bitmap(*file, bitmap2);
	file.reset();
	if (filerr)
	{
		printf("Could not read %s (%s)\n", imgfile2.c_str(), filerr.message().c_str());
		goto error;
	}

	/* if the sizes are different, we differ; otherwise start off assuming we are the same */
	bool bitmaps_differ;
	bitmaps_differ = (bitmap2.width() != bitmap1.width() || bitmap2.height() != bitmap1.height());

	/* compare scanline by scanline */
	for (int y = 0; y < bitmap2.height() && !bitmaps_differ; y++)
	{
		uint32_t const *base = &bitmap1.pix(y);
		uint32_t const *curr = &bitmap2.pix(y);

		/* scan the scanline */
		int x;
		for (x = 0; x < bitmap2.width(); x++)
			if (*base++ != *curr++)
				break;
		bitmaps_differ = (x != bitmap2.width());
	}

	if (bitmaps_differ)
	{
		/* determine the size of the final bitmap */
		height = width = 0;
		{
			/* determine the maximal width */
			maxwidth = std::max(bitmap1.width(), bitmap2.width());
			width = bitmap1.width() + BITMAP_SPACE + maxwidth + BITMAP_SPACE + maxwidth;

			/* add to the height */
			height += std::max(bitmap1.height(), bitmap2.height());
		}

		/* allocate the final bitmap */
		finalbitmap.allocate(width, height);

		/* now copy and compare each set of bitmaps */
		int curheight = std::max(bitmap1.height(), bitmap2.height());
		/* iterate over rows in these bitmaps */
		for (int y = 0; y < curheight; y++)
		{
			uint32_t const *src1 = (y < bitmap1.height()) ? &bitmap1.pix(y) : nullptr;
			uint32_t const *src2 = (y < bitmap2.height()) ? &bitmap2.pix(y) : nullptr;
			uint32_t *dst1 = &finalbitmap.pix(y);
			uint32_t *dst2 = &finalbitmap.pix(y, bitmap1.width() + BITMAP_SPACE);
			uint32_t *dstdiff = &finalbitmap.pix(y, bitmap1.width() + BITMAP_SPACE + maxwidth + BITMAP_SPACE);

			/* now iterate over columns */
			for (int x = 0; x < maxwidth; x++)
			{
				int pix1 = -1, pix2 = -2;

				if (src1 != nullptr && x < bitmap1.width())
					pix1 = dst1[x] = src1[x];
				if (src2 != nullptr && x < bitmap2.width())
					pix2 = dst2[x] = src2[x];
				dstdiff[x] = (pix1 != pix2) ? 0xffffffff : 0xff000000;
			}
		}

		/* write the final PNG */
		filerr = util::core_file::open(outfilename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
		if (filerr)
		{
			printf("Could not open %s (%s)\n", outfilename.c_str(), filerr.message().c_str());
			goto error;
		}
		filerr = util::png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr);
		file.reset();
		if (filerr)
		{
			printf("Could not write %s (%s)\n", outfilename.c_str(), filerr.message().c_str());
			goto error;
		}
	}

	/* if we get here, we are error free */
	if (bitmaps_differ)
		error = 1;
	else
		error = 0;

error:
	if (error == -1)
		osd_file::remove(outfilename);
	return error;
}