"Fossies" - the Fresh Open Source Software Archive

Member "littleutils-1.2.5/imageutils/imagdiff.c" (29 Oct 2021, 15091 Bytes) of package /linux/privat/littleutils-1.2.5.tar.lz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "imagdiff.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.4_vs_1.2.5.

    1 /* imagdiff:  Compares two image files and writes differences to a third image
    2    file, using Imlib2 as an I/O and computational engine.
    3 
    4    Copyright (C) 2018-2021 by Brian E. Lindholm.  This file is part of the
    5    littleutils utility set.
    6 
    7    The imagdiff utility is free software; you can redistribute it and/or modify
    8    it under the terms of the GNU General Public License as published by the
    9    Free Software Foundation; either version 3, or (at your option) any later
   10    version.
   11 
   12    The imagdiff utility is distributed in the hope that it will be useful, but
   13    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   15    more details.
   16 
   17    You should have received a copy of the GNU General Public License along with
   18    the littleutils.  If not, see <https://www.gnu.org/licenses/>. */
   19 
   20 
   21 #include <config.h>
   22 
   23 #define X_DISPLAY_MISSING
   24 #ifdef HAVE_STDIO_H
   25 # include <stdio.h>
   26 #endif
   27 #ifdef HAVE_STDLIB_H
   28 # include <stdlib.h>
   29 #endif
   30 
   31 #ifdef HAVE_UNISTD_H
   32 # include <unistd.h>
   33 # define OPTEND -1
   34 #else
   35 # define OPTEND EOF
   36 #endif
   37 #ifdef HAVE_GETOPT_H
   38 # include <getopt.h>
   39 #endif
   40 
   41 #ifdef __MINGW32__
   42 extern int getopt (int argc, char * const *argv, const char *optstring);
   43 extern char *optarg;
   44 extern int optind;
   45 #endif
   46 
   47 #include <Imlib2.h>
   48 
   49 #define MODE_GRAY 1
   50 #define MODE_LIGHT_GRAY 2
   51 #define MODE_DARK_GRAY 3
   52 #define MODE_COLOR 4
   53 #define MODE_STRETCH_COLOR 5
   54 
   55 /* constants copied from pngrtran.c of libpng-1.6; many thanks to GRP et al */
   56 #define R2G 6968
   57 #define G2G 23434
   58 #define B2G 2366
   59 #define GSHIFT 15;
   60 
   61 /* help function */
   62 
   63 static void
   64 help (FILE *where)
   65 {
   66   fprintf (where,
   67     "usage: imagdiff [-f fuzz_dist] [-h(elp)] [-m mode] oldfile newfile deltafile\n"
   68     "       mode 1 = gray, 2 = light gray, 3 = dark gray, 4 = color,\n"
   69     "            5 = color-stretched\n");
   70 }
   71 
   72 
   73 /* main program */
   74 
   75 int
   76 main (int argc, char *argv[])
   77 {
   78   /* define main variables */
   79 
   80   Imlib_Image image_old, image_new, image_diff;
   81   Imlib_Load_Error rc;
   82   DATA32 *array_old, *array_new, *array_diff, data_old, data_new, data_diff,
   83          old_red, new_red, diff_red, old_green, new_green, diff_green,
   84          old_blue, new_blue, diff_blue, old_gray, new_gray, fallback;
   85   char *filename_old, *filename_new, *filename_diff;
   86   int image_width_old, image_width_new, image_width_diff, image_height_old,
   87       image_height_new, image_height_diff;
   88   int c, delta, fuzz, i, j, mode, max_delta;
   89 
   90   /* parse options */
   91 
   92   filename_old = NULL;
   93   filename_new = NULL;
   94   fuzz = 1;
   95   mode = MODE_GRAY;
   96   while ((c = getopt (argc, argv, "f:hm:")) != OPTEND)
   97     switch (c)
   98       {
   99       case 'f':
  100         fuzz = atoi(optarg);
  101         break;
  102       case 'h':
  103         help (stdout);
  104         return (0);
  105       case 'm':
  106         mode = atoi(optarg);
  107         break;
  108       case '?':
  109         help (stderr);
  110         return (1);
  111       }
  112   if ((fuzz < 0) || (fuzz > 255)) {
  113     help (stderr);
  114     return (1);
  115   }
  116   if ((mode < 1) || (mode > 5)) {
  117     help (stderr);
  118     return (1);
  119   }
  120   switch (mode)
  121     {
  122     case MODE_GRAY:
  123       fallback = 0x00FFFFFF;
  124       break;
  125     case MODE_DARK_GRAY:
  126       fallback = 0x00000000;
  127       break;
  128     case MODE_LIGHT_GRAY:
  129       fallback = 0x00FFFFFF;
  130       break;
  131     case MODE_COLOR:
  132       fallback = 0x007F7F7F;
  133       break;
  134     case MODE_STRETCH_COLOR:
  135       fallback = 0x007F7F7F;
  136       break;
  137     default:
  138       fprintf (stderr, "imagdiff error: this should never execute\n");
  139       return (3);
  140     }
  141 
  142   /* ensure that three filenames were given as input */
  143 
  144   if ((argc - optind) != 3)
  145     {
  146       fprintf (stderr, "imagdiff error: missing input filenames\n");
  147       help (stderr);
  148       return (1);
  149     }
  150   filename_old = argv[optind];
  151   filename_new = argv[optind + 1];
  152   filename_diff = argv[optind + 2];
  153 
  154   /* open the input files and determine image sizes */
  155 
  156   image_old = imlib_load_image_immediately_without_cache (filename_old);
  157   image_new = imlib_load_image_immediately_without_cache (filename_new);
  158   if ((image_old == NULL) && (image_new == NULL))
  159     {
  160       fprintf (stderr, "imagdiff error: cannot process oldfile %s or newfile %s\n",
  161         filename_old, filename_new);
  162       return (2);
  163     }
  164   else if (image_old == NULL)
  165     {
  166       fprintf (stderr, "imagdiff warning: could not process oldfile %s; preparing fallback\n", filename_old);
  167       imlib_context_set_image (image_new);
  168       image_width_old = image_width_new = imlib_image_get_width ();
  169       image_height_old = image_height_new = imlib_image_get_height ();
  170       array_old = (DATA32 *) malloc ((image_width_old * image_height_old) * sizeof (DATA32));
  171       for (j = 0; j < image_height_old; j++)
  172         for (i = 0; i < image_width_old; i++)
  173           array_old[j * image_width_old + i] = fallback;
  174       image_old = imlib_create_image_using_data (image_width_old, image_height_old, array_old);
  175       if (image_old == NULL)
  176         {
  177           fprintf (stderr, "imagdiff error: cannot prepare fallback old image\n");
  178           return (2);
  179         }
  180     }
  181   else if (image_new == NULL)
  182     {
  183       fprintf (stderr, "imagdiff warning: could not process newfile %s; preparing fallback\n", filename_new);
  184       imlib_context_set_image (image_old);
  185       image_width_new = image_width_old = imlib_image_get_width ();
  186       image_height_new = image_height_old = imlib_image_get_height ();
  187       array_new = (DATA32 *) malloc ((image_width_new * image_height_new) * sizeof (DATA32));
  188       for (j = 0; j < image_height_new; j++)
  189         for (i = 0; i < image_width_new; i++)
  190           array_new[j * image_width_new + i] = fallback;
  191       image_new = imlib_create_image_using_data (image_width_new, image_height_new, array_new);
  192       if (image_new == NULL)
  193         {
  194           fprintf (stderr, "imagdiff error: cannot prepare fallback new image\n");
  195           return (2);
  196         }
  197     }
  198   else {
  199     imlib_context_set_image (image_old);
  200     image_width_old = imlib_image_get_width ();
  201     image_height_old = imlib_image_get_height ();
  202     imlib_context_set_image (image_new);
  203     image_width_new = imlib_image_get_width ();
  204     image_height_new = imlib_image_get_height ();
  205     if ((image_width_old != image_width_new) || (image_height_old != image_height_new))
  206       fprintf (stderr, "imagdiff warning: %s and %s differ in size; using overlap only\n",
  207         filename_old, filename_new);
  208   }
  209 
  210   /* prep for delta image */
  211 
  212   if (image_width_old < image_width_new)
  213     image_width_diff = image_width_old;
  214   else
  215     image_width_diff = image_width_new;
  216   if (image_height_old < image_height_new)
  217     image_height_diff = image_height_old;
  218   else
  219     image_height_diff = image_height_new;
  220 
  221   imlib_context_set_image (image_old);
  222   array_old = (DATA32 *) imlib_image_get_data();
  223   imlib_context_set_image (image_new);
  224   array_new = (DATA32 *) imlib_image_get_data();
  225   array_diff = (DATA32 *) malloc ((image_width_diff * image_height_diff) * sizeof (DATA32));
  226 
  227   /* create delta image based on requested mode */
  228 
  229   switch (mode)
  230     {
  231     case MODE_GRAY:
  232       for (j = 0; j < image_height_diff; j++)
  233         for (i = 0; i < image_width_diff; i++)
  234           {
  235             data_old = array_old[j * image_width_old + i];
  236             old_red = (data_old >> 16) & 0xff;
  237             old_green = (data_old >> 8) & 0xff;
  238             old_blue = data_old & 0xff;
  239             old_gray = ((old_red * R2G) + (old_green * G2G) + (old_blue * B2G)) >> GSHIFT;
  240             data_new = array_new[j * image_width_new + i];
  241             new_red = (data_new >> 16) & 0xff;
  242             new_green = (data_new >> 8) & 0xff;
  243             new_blue = data_new & 0xff;
  244             new_gray = ((new_red * R2G) + (new_green * G2G) + (new_blue * B2G)) >> GSHIFT;
  245             delta = (int) new_gray - (int) old_gray;
  246             if (delta > fuzz)
  247               {
  248                 diff_red = 255;
  249                 diff_green = diff_blue = old_gray;
  250               }
  251             else if ((-delta) > fuzz)
  252               {
  253                 diff_red = diff_green = new_gray;
  254                 diff_blue = 255;
  255               }
  256             else
  257               diff_red = diff_green = diff_blue = (old_gray + new_gray) >> 1;
  258             data_diff = (diff_red << 16) + (diff_green << 8) + diff_blue;
  259             array_diff[j * image_width_diff + i] = data_diff;
  260           }
  261       break;
  262     case MODE_DARK_GRAY:
  263       for (j = 0; j < image_height_diff; j++)
  264         for (i = 0; i < image_width_diff; i++)
  265           {
  266             data_old = array_old[j * image_width_old + i];
  267             old_red = (data_old >> 16) & 0xff;
  268             old_green = (data_old >> 8) & 0xff;
  269             old_blue = data_old & 0xff;
  270             old_gray = ((old_red * R2G) + (old_green * G2G) + (old_blue * B2G)) >> GSHIFT;
  271             data_new = array_new[j * image_width_new + i];
  272             new_red = (data_new >> 16) & 0xff;
  273             new_green = (data_new >> 8) & 0xff;
  274             new_blue = data_new & 0xff;
  275             new_gray = ((new_red * R2G) + (new_green * G2G) + (new_blue * B2G)) >> GSHIFT;
  276             delta = (int) new_gray - (int) old_gray;
  277             if (delta > fuzz)
  278               {
  279                 diff_red = 255;
  280                 diff_green = diff_blue = old_gray;
  281               }
  282             else if ((-delta) > fuzz)
  283               {
  284                 diff_red = diff_green = new_gray;
  285                 diff_blue = 255;
  286               }
  287             else
  288               diff_red = diff_green = diff_blue = (old_gray + new_gray) >> 2;
  289             data_diff = (diff_red << 16) + (diff_green << 8) + diff_blue;
  290             array_diff[j * image_width_diff + i] = data_diff;
  291           }
  292       break;
  293     case MODE_LIGHT_GRAY:
  294       for (j = 0; j < image_height_diff; j++)
  295         for (i = 0; i < image_width_diff; i++)
  296           {
  297             data_old = array_old[j * image_width_old + i];
  298             old_red = (data_old >> 16) & 0xff;
  299             old_green = (data_old >> 8) & 0xff;
  300             old_blue = data_old & 0xff;
  301             old_gray = ((old_red * R2G) + (old_green * G2G) + (old_blue * B2G)) >> GSHIFT;
  302             data_new = array_new[j * image_width_new + i];
  303             new_red = (data_new >> 16) & 0xff;
  304             new_green = (data_new >> 8) & 0xff;
  305             new_blue = data_new & 0xff;
  306             new_gray = ((new_red * R2G) + (new_green * G2G) + (new_blue * B2G)) >> GSHIFT;
  307             delta = (int) new_gray - (int) old_gray;
  308             if (delta > fuzz)
  309               {
  310                 diff_red = 255;
  311                 diff_green = diff_blue = old_gray;
  312               }
  313             else if ((-delta) > fuzz)
  314               {
  315                 diff_red = diff_green = new_gray;
  316                 diff_blue = 255;
  317               }
  318             else
  319               diff_red = diff_green = diff_blue = (old_gray + new_gray + 512) >> 2;
  320             data_diff = (diff_red << 16) + (diff_green << 8) + diff_blue;
  321             array_diff[j * image_width_diff + i] = data_diff;
  322           }
  323       break;
  324     case MODE_COLOR:
  325       for (j = 0; j < image_height_diff; j++)
  326         for (i = 0; i < image_width_diff; i++)
  327           {
  328             data_old = array_old[j * image_width_old + i];
  329             old_red = (data_old >> 16) & 0xff;
  330             old_green = (data_old >> 8) & 0xff;
  331             old_blue = data_old & 0xff;
  332             data_new = array_new[j * image_width_new + i];
  333             new_red = (data_new >> 16) & 0xff;
  334             new_green = (data_new >> 8) & 0xff;
  335             new_blue = data_new & 0xff;
  336             diff_red = (new_red - old_red + 255) >> 1;
  337             diff_green = (new_green - old_green + 255) >> 1;
  338             diff_blue = (new_blue - old_blue + 255) >> 1;
  339             data_diff = (diff_red << 16) + (diff_green << 8) + diff_blue;
  340             array_diff[j * image_width_diff + i] = data_diff;
  341           }
  342       break;
  343     case MODE_STRETCH_COLOR:
  344       max_delta = 0;
  345       for (j = 0; j < image_height_diff; j++)
  346         for (i = 0; i < image_width_diff; i++)
  347           {
  348             data_old = array_old[j * image_width_old + i];
  349             old_red = (data_old >> 16) & 0xff;
  350             old_green = (data_old >> 8) & 0xff;
  351             old_blue = data_old & 0xff;
  352             data_new = array_new[j * image_width_new + i];
  353             new_red = (data_new >> 16) & 0xff;
  354             new_green = (data_new >> 8) & 0xff;
  355             new_blue = data_new & 0xff;
  356             if (new_red > old_red)
  357               {
  358                 if ((new_red - old_red) > max_delta)
  359                   max_delta = new_red - old_red;
  360               }
  361             else
  362               {
  363                 if ((old_red - new_red) > max_delta)
  364                   max_delta = old_red - new_red;
  365               }
  366             if (new_green > old_green)
  367               {
  368                 if ((new_green - old_green) > max_delta)
  369                   max_delta = new_green - old_green;
  370               }
  371             else
  372               {
  373                 if ((old_green - new_green) > max_delta)
  374                   max_delta = old_green - new_green;
  375               }
  376             if (new_blue > old_blue)
  377               {
  378                 if ((new_blue - old_blue) > max_delta)
  379                   max_delta = new_blue - old_blue;
  380               }
  381             else
  382               {
  383                 if ((old_blue - new_blue) > max_delta)
  384                   max_delta = old_blue - new_blue;
  385               }
  386           }
  387       for (j = 0; j < image_height_diff; j++)
  388         for (i = 0; i < image_width_diff; i++)
  389           {
  390             data_old = array_old[j * image_width_old + i];
  391             old_red = (data_old >> 16) & 0xff;
  392             old_green = (data_old >> 8) & 0xff;
  393             old_blue = data_old & 0xff;
  394             data_new = array_new[j * image_width_new + i];
  395             new_red = (data_new >> 16) & 0xff;
  396             new_green = (data_new >> 8) & 0xff;
  397             new_blue = data_new & 0xff;
  398             diff_red = (255 * (new_red - old_red) / max_delta + 255) >> 1;
  399             diff_green = (255 * (new_green - old_green) / max_delta + 255) >> 1;
  400             diff_blue = (255 * (new_blue - old_blue) / max_delta + 255) >> 1;
  401             data_diff = (diff_red << 16) + (diff_green << 8) + diff_blue;
  402             array_diff[j * image_width_diff + i] = data_diff;
  403           }
  404       break;
  405     default:
  406       fprintf (stderr, "imagdiff error: this should never execute\n");
  407       return (3);
  408     }
  409 
  410   /* write delta image to file */
  411 
  412   image_diff = imlib_create_image_using_data (image_width_diff, image_height_diff, array_diff);
  413   if (image_diff == NULL)
  414     {
  415       fprintf (stderr, "imagdiff error: can't prepare diff image %s\n", filename_diff);
  416       return (2);
  417     }
  418   imlib_context_set_image (image_diff);
  419   imlib_save_image_with_error_return (filename_diff, &rc);
  420   if (rc > 0)
  421     {
  422       fprintf (stderr, "imagdiff error: can't save diff image %s (rc = %d)\n", filename_diff, rc);
  423       return (2);
  424     }
  425 
  426   /* Clean up and quit */
  427 
  428   imlib_context_set_image (image_diff);
  429   imlib_free_image ();
  430   imlib_context_set_image (image_new);
  431   imlib_free_image ();
  432   imlib_context_set_image (image_old);
  433   imlib_free_image ();
  434 
  435   return (0);
  436 }