trunk/src/tools/pngcmp.c
r0 | r23815 | |
| 1 | /*************************************************************************** |
| 2 | |
| 3 | pngcmp.c |
| 4 | |
| 5 | PNG comparison (based on regrep.c) |
| 6 | |
| 7 | **************************************************************************** |
| 8 | |
| 9 | Copyright Aaron Giles |
| 10 | All rights reserved. |
| 11 | |
| 12 | Redistribution and use in source and binary forms, with or without |
| 13 | modification, are permitted provided that the following conditions are |
| 14 | met: |
| 15 | |
| 16 | * Redistributions of source code must retain the above copyright |
| 17 | notice, this list of conditions and the following disclaimer. |
| 18 | * Redistributions in binary form must reproduce the above copyright |
| 19 | notice, this list of conditions and the following disclaimer in |
| 20 | the documentation and/or other materials provided with the |
| 21 | distribution. |
| 22 | * Neither the name 'MAME' nor the names of its contributors may be |
| 23 | used to endorse or promote products derived from this software |
| 24 | without specific prior written permission. |
| 25 | |
| 26 | THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR |
| 27 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 28 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 29 | DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, |
| 30 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 31 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 33 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 34 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| 35 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 36 | POSSIBILITY OF SUCH DAMAGE. |
| 37 | |
| 38 | ****************************************************************************/ |
| 39 | |
| 40 | #include <stdio.h> |
| 41 | #include <stdlib.h> |
| 42 | #include <string.h> |
| 43 | #include <ctype.h> |
| 44 | #include "osdcore.h" |
| 45 | #include "png.h" |
| 46 | |
| 47 | #include <new> |
| 48 | |
| 49 | /*************************************************************************** |
| 50 | CONSTANTS & DEFINES |
| 51 | ***************************************************************************/ |
| 52 | |
| 53 | #define BITMAP_SPACE 4 |
| 54 | |
| 55 | /*************************************************************************** |
| 56 | PROTOTYPES |
| 57 | ***************************************************************************/ |
| 58 | |
| 59 | static int generate_png_diff(const astring& imgfile1, const astring& imgfile2, const astring& outfilename); |
| 60 | |
| 61 | /*************************************************************************** |
| 62 | MAIN |
| 63 | ***************************************************************************/ |
| 64 | |
| 65 | /*------------------------------------------------- |
| 66 | main - main entry point |
| 67 | -------------------------------------------------*/ |
| 68 | |
| 69 | int main(int argc, char *argv[]) |
| 70 | { |
| 71 | /* first argument is the directory */ |
| 72 | if (argc < 4) |
| 73 | { |
| 74 | fprintf(stderr, "Usage:\npngcmp <image1> <image2> <outfile>\n"); |
| 75 | return 10; |
| 76 | } |
| 77 | astring imgfilename1(argv[1]); |
| 78 | astring imgfilename2(argv[2]); |
| 79 | astring outfilename(argv[3]); |
| 80 | |
| 81 | try { |
| 82 | return generate_png_diff(imgfilename1, imgfilename2, outfilename); |
| 83 | } |
| 84 | catch(...) |
| 85 | { |
| 86 | printf("Exception occured"); |
| 87 | return 1000; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | /*------------------------------------------------- |
| 92 | generate_png_diff - create a new PNG file |
| 93 | that shows multiple differing PNGs side by |
| 94 | side with a third set of differences |
| 95 | -------------------------------------------------*/ |
| 96 | |
| 97 | static int generate_png_diff(const astring& imgfile1, const astring& imgfile2, const astring& outfilename) |
| 98 | { |
| 99 | bitmap_argb32 bitmap1; |
| 100 | bitmap_argb32 bitmap2; |
| 101 | bitmap_argb32 finalbitmap; |
| 102 | int width, height, maxwidth; |
| 103 | core_file *file = NULL; |
| 104 | file_error filerr; |
| 105 | png_error pngerr; |
| 106 | int error = 100; |
| 107 | bool bitmaps_differ; |
| 108 | int x, y; |
| 109 | |
| 110 | /* open the source image */ |
| 111 | filerr = core_fopen(imgfile1, OPEN_FLAG_READ, &file); |
| 112 | if (filerr != FILERR_NONE) |
| 113 | { |
| 114 | printf("Could not open %s (%d)\n", imgfile1.cstr(), filerr); |
| 115 | goto error; |
| 116 | } |
| 117 | |
| 118 | /* load the source image */ |
| 119 | pngerr = png_read_bitmap(file, bitmap1); |
| 120 | core_fclose(file); |
| 121 | if (pngerr != PNGERR_NONE) |
| 122 | { |
| 123 | printf("Could not read %s (%d)\n", imgfile1.cstr(), pngerr); |
| 124 | goto error; |
| 125 | } |
| 126 | |
| 127 | /* open the source image */ |
| 128 | filerr = core_fopen(imgfile2, OPEN_FLAG_READ, &file); |
| 129 | if (filerr != FILERR_NONE) |
| 130 | { |
| 131 | printf("Could not open %s (%d)\n", imgfile2.cstr(), filerr); |
| 132 | goto error; |
| 133 | } |
| 134 | |
| 135 | /* load the source image */ |
| 136 | pngerr = png_read_bitmap(file, bitmap2); |
| 137 | core_fclose(file); |
| 138 | if (pngerr != PNGERR_NONE) |
| 139 | { |
| 140 | printf("Could not read %s (%d)\n", imgfile2.cstr(), pngerr); |
| 141 | goto error; |
| 142 | } |
| 143 | |
| 144 | /* if the sizes are different, we differ; otherwise start off assuming we are the same */ |
| 145 | bitmaps_differ = (bitmap2.width() != bitmap1.width() || bitmap2.height() != bitmap1.height()); |
| 146 | |
| 147 | /* compare scanline by scanline */ |
| 148 | for (y = 0; y < bitmap2.height() && !bitmaps_differ; y++) |
| 149 | { |
| 150 | UINT32 *base = &bitmap1.pix32(y); |
| 151 | UINT32 *curr = &bitmap2.pix32(y); |
| 152 | |
| 153 | /* scan the scanline */ |
| 154 | for (x = 0; x < bitmap2.width(); x++) |
| 155 | if (*base++ != *curr++) |
| 156 | break; |
| 157 | bitmaps_differ = (x != bitmap2.width()); |
| 158 | } |
| 159 | |
| 160 | if (bitmaps_differ) |
| 161 | { |
| 162 | /* determine the size of the final bitmap */ |
| 163 | height = width = 0; |
| 164 | { |
| 165 | /* determine the maximal width */ |
| 166 | maxwidth = MAX(bitmap1.width(), bitmap2.width()); |
| 167 | width = bitmap1.width() + BITMAP_SPACE + maxwidth + BITMAP_SPACE + maxwidth; |
| 168 | |
| 169 | /* add to the height */ |
| 170 | height += MAX(bitmap1.height(), bitmap2.height()); |
| 171 | } |
| 172 | |
| 173 | /* allocate the final bitmap */ |
| 174 | finalbitmap.allocate(width, height); |
| 175 | |
| 176 | /* now copy and compare each set of bitmaps */ |
| 177 | int curheight = MAX(bitmap1.height(), bitmap2.height()); |
| 178 | /* iterate over rows in these bitmaps */ |
| 179 | for (y = 0; y < curheight; y++) |
| 180 | { |
| 181 | UINT32 *src1 = (y < bitmap1.height()) ? &bitmap1.pix32(y) : NULL; |
| 182 | UINT32 *src2 = (y < bitmap2.height()) ? &bitmap2.pix32(y) : NULL; |
| 183 | UINT32 *dst1 = &finalbitmap.pix32(y); |
| 184 | UINT32 *dst2 = &finalbitmap.pix32(y, bitmap1.width() + BITMAP_SPACE); |
| 185 | UINT32 *dstdiff = &finalbitmap.pix32(y, bitmap1.width() + BITMAP_SPACE + maxwidth + BITMAP_SPACE); |
| 186 | |
| 187 | /* now iterate over columns */ |
| 188 | for (x = 0; x < maxwidth; x++) |
| 189 | { |
| 190 | int pix1 = -1, pix2 = -2; |
| 191 | |
| 192 | if (src1 != NULL && x < bitmap1.width()) |
| 193 | pix1 = dst1[x] = src1[x]; |
| 194 | if (src2 != NULL && x < bitmap2.width()) |
| 195 | pix2 = dst2[x] = src2[x]; |
| 196 | dstdiff[x] = (pix1 != pix2) ? 0xffffffff : 0xff000000; |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | /* write the final PNG */ |
| 201 | filerr = core_fopen(outfilename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file); |
| 202 | if (filerr != FILERR_NONE) |
| 203 | { |
| 204 | printf("Could not open %s (%d)\n", outfilename.cstr(), filerr); |
| 205 | goto error; |
| 206 | } |
| 207 | pngerr = png_write_bitmap(file, NULL, finalbitmap, 0, NULL); |
| 208 | core_fclose(file); |
| 209 | if (pngerr != PNGERR_NONE) |
| 210 | { |
| 211 | printf("Could not write %s (%d)\n", outfilename.cstr(), pngerr); |
| 212 | goto error; |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | /* if we get here, we are error free */ |
| 217 | if (bitmaps_differ) |
| 218 | error = 1; |
| 219 | else |
| 220 | error = 0; |
| 221 | |
| 222 | error: |
| 223 | if (error == -1) |
| 224 | osd_rmfile(outfilename); |
| 225 | return error; |
| 226 | } |