diffimg.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at http://www.graphviz.org/
  9. *************************************************************************/
  10. /*
  11. * This program generates an image where each pixel is the
  12. * difference between the corresponding pixel in each of the
  13. * two source images. Thus, if the source images are the same
  14. * the resulting image will be black, otherwise it will have
  15. * regions of non-black where the images differ.
  16. *
  17. * Currently supports: .png, .gif, .jpg, and .ps by using ghostscript
  18. *
  19. * John Ellson <[email protected]>
  20. */
  21. #include "config.h"
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #ifdef _WIN32
  28. #define EX_USAGE 64
  29. #define EX_DATAERR 65
  30. #define EX_NOINPUT 66
  31. #define EX_UNAVAILABLE 69
  32. #define EX_OSERR 71
  33. #else
  34. #include <sysexits.h>
  35. #endif
  36. #include <gd.h>
  37. #include <stdbool.h>
  38. #include <util/agxbuf.h>
  39. #include <util/alloc.h>
  40. #include <util/exit.h>
  41. static char *pstopng="gs -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=- -q -";
  42. static gdImagePtr imageLoad (char *filename)
  43. {
  44. FILE *f;
  45. char *ext;
  46. gdImagePtr im;
  47. int rc;
  48. struct stat statbuf;
  49. ext = strrchr(filename, '.');
  50. if (!ext) {
  51. fprintf(stderr, "Filename \"%s\" has no file extension.\n", filename);
  52. graphviz_exit(EX_USAGE);
  53. }
  54. rc = stat(filename, &statbuf);
  55. if (rc) {
  56. fprintf(stderr, "Failed to stat \"%s\"\n", filename);
  57. graphviz_exit(EX_NOINPUT);
  58. }
  59. if (strcasecmp(ext, ".ps") == 0) {
  60. ext = ".png";
  61. agxbuf fname = {0};
  62. agxbprint(&fname, "%s%s", filename, ext);
  63. const char *tmp = agxbuse(&fname);
  64. agxbuf cmd = {0};
  65. agxbprint(&cmd, "%s <%s >%s", pstopng, filename, tmp);
  66. rc = system(agxbuse(&cmd));
  67. agxbfree(&cmd);
  68. f = fopen(tmp, "rb");
  69. agxbfree(&fname);
  70. if (!f) {
  71. fprintf(stderr, "Failed to open converted \"%s%s\"\n", filename, ext);
  72. graphviz_exit(EX_NOINPUT);
  73. }
  74. }
  75. else {
  76. f = fopen(filename, "rb");
  77. if (!f) {
  78. fprintf(stderr, "Failed to open \"%s\"\n", filename);
  79. graphviz_exit(EX_NOINPUT);
  80. }
  81. }
  82. im = 0;
  83. if (strcasecmp(ext, ".png") == 0) {
  84. #ifdef HAVE_GD_PNG
  85. im = gdImageCreateFromPng(f);
  86. #else
  87. fprintf(stderr, "PNG support is not available\n");
  88. graphviz_exit(EX_UNAVAILABLE);
  89. #endif
  90. }
  91. else if (strcasecmp(ext, ".gif") == 0) {
  92. #ifdef HAVE_GD_GIF
  93. im = gdImageCreateFromGif(f);
  94. #else
  95. fprintf(stderr, "GIF support is not available\n");
  96. graphviz_exit(EX_UNAVAILABLE);
  97. #endif
  98. }
  99. else if (strcasecmp(ext, ".jpg") == 0) {
  100. #ifdef HAVE_GD_JPEG
  101. im = gdImageCreateFromJpeg(f);
  102. #else
  103. fprintf(stderr, "JPEG support is not available\n");
  104. graphviz_exit(EX_UNAVAILABLE);
  105. #endif
  106. }
  107. fclose(f);
  108. if (!im) {
  109. fprintf(stderr, "Loading image from file \"%s\" failed!\n", filename);
  110. graphviz_exit(EX_DATAERR);
  111. }
  112. return im;
  113. }
  114. static bool imageDiff (gdImagePtr A, gdImagePtr B, gdImagePtr C,
  115. int w, int h,
  116. int black, int white)
  117. {
  118. int x, y;
  119. bool d, rc;
  120. rc = false;
  121. for (y = 0; y < h; y++) {
  122. for (x = 0; x < w; x++) {
  123. d = (bool)( gdImageGetTrueColorPixel(B,x,y)
  124. - gdImageGetTrueColorPixel(A,x,y));
  125. gdImageSetPixel (C, x, y, (d ? white : black));
  126. rc |= d;
  127. }
  128. }
  129. return rc;
  130. }
  131. int main(int argc, char **argv)
  132. {
  133. gdImagePtr A, B, C;
  134. int black, white;
  135. int minSX, minSY, maxSX, maxSY;
  136. bool rc;
  137. #ifdef HAVE_GD_PNG
  138. FILE *f;
  139. #endif
  140. if (argc == 2 && strcmp(argv[1], "-?") == 0) {
  141. fprintf(stderr, "Usage: diffimg image1 image2 [outimage]\n");
  142. graphviz_exit(0);
  143. }
  144. if (argc < 3) {
  145. fprintf(stderr, "Usage: diffimg image1 image2 [outimage]\n");
  146. graphviz_exit(EX_USAGE);
  147. }
  148. A = imageLoad(argv[1]);
  149. B = imageLoad(argv[2]);
  150. minSX = (gdImageSX(A) < gdImageSX(B)) ? gdImageSX(A) : gdImageSX(B);
  151. minSY = (gdImageSY(A) < gdImageSY(B)) ? gdImageSY(A) : gdImageSY(B);
  152. maxSX = (gdImageSX(A) > gdImageSX(B)) ? gdImageSX(A) : gdImageSX(B);
  153. maxSY = (gdImageSY(A) > gdImageSY(B)) ? gdImageSY(A) : gdImageSY(B);
  154. C = gdImageCreatePalette (maxSX, maxSY);
  155. white = gdImageColorAllocate(C, gdRedMax, gdGreenMax, gdBlueMax);
  156. black = gdImageColorAllocate(C, 0, 0, 0);
  157. if (maxSX > minSX && maxSY > minSY)
  158. gdImageFilledRectangle(C, minSX, minSY, maxSX-1, maxSY-1, black);
  159. rc = imageDiff (A, B, C, minSX, minSY, black, white);
  160. #ifdef HAVE_GD_PNG
  161. if ((argc > 3) && ((f = fopen(argv[3], "wb")))) {
  162. gdImagePng (C, f);
  163. fclose(f);
  164. }
  165. else
  166. gdImagePng (C, stdout);
  167. #else
  168. fprintf(stderr, "PNG output support is not available\n");
  169. #endif
  170. gdImageDestroy(A);
  171. gdImageDestroy(B);
  172. gdImageDestroy(C);
  173. graphviz_exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
  174. }