diff --git a/extras/get_disto.c b/extras/get_disto.c index a834e4d7..4120bfbb 100644 --- a/extras/get_disto.c +++ b/extras/get_disto.c @@ -47,6 +47,35 @@ static size_t ReadPicture(const char* const filename, WebPPicture* const pic, return ok ? data_size : 0; } +// returns the max absolute difference +static int DiffScaleChannel(uint8_t* src1, int stride1, + const uint8_t* src2, int stride2, + int x_stride, int w, int h, int do_scaling) { + int x, y; + uint32_t max = 1; + for (y = 0; y < h; ++y) { + uint8_t* const ptr1 = src1 + y * stride1; + const uint8_t* const ptr2 = src2 + y * stride2; + for (x = 0; x < w * x_stride; x += x_stride) { + const uint32_t diff = abs(ptr1[x] - ptr2[x]); + if (diff > max) max = diff; + ptr1[x] = diff; + } + } + + if (do_scaling) { + const uint32_t factor = (255u << 16) / max; + for (y = 0; y < h; ++y) { + uint8_t* const ptr1 = src1 + y * stride1; + for (x = 0; x < w * x_stride; x += x_stride) { + const uint32_t diff = (ptr1[x] * factor) >> 16; + ptr1[x] = diff; + } + } + } + return max; +} + static void Help(void) { fprintf(stderr, "Usage: get_disto [-ssim][-psnr][-alpha] compressed.webp orig.webp\n" @@ -54,6 +83,8 @@ static void Help(void) { " -psnr ..... print PSNR distortion (default)\n" " -alpha .... preserve alpha plane\n" " -h ........ this message\n" + " -o . save the diff map as a WebP lossless file\n" + " -scale .... scale the difference map to fit [0..255] range\n" " Also handles PNG, JPG and TIFF files, in addition to WebP.\n"); } @@ -66,8 +97,10 @@ int main(int argc, const char *argv[]) { int c; int help = 0; int keep_alpha = 0; + int scale = 0; const char* name1 = NULL; const char* name2 = NULL; + const char* output = NULL; if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) { fprintf(stderr, "Can't init pictures\n"); @@ -81,9 +114,17 @@ int main(int argc, const char *argv[]) { type = 0; } else if (!strcmp(argv[c], "-alpha")) { keep_alpha = 1; + } else if (!strcmp(argv[c], "-scale")) { + scale = 1; } else if (!strcmp(argv[c], "-h")) { help = 1; ret = 0; + } else if (!strcmp(argv[c], "-o")) { + if (++c == argc) { + fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]); + goto End; + } + output = argv[c]; } else if (name1 == NULL) { name1 = argv[c]; } else { @@ -115,6 +156,43 @@ int main(int argc, const char *argv[]) { printf("%u %.2f %.2f %.2f %.2f %.2f\n", (unsigned int)size1, disto[4], disto[0], disto[1], disto[2], disto[3]); + + if (output != NULL) { + uint8_t* data = NULL; + size_t data_size = 0; + if (pic1.use_argb != pic1.use_argb) { + fprintf(stderr, "Pictures are not in the same argb format. " + "Can't save the difference map.\n"); + goto End; + } + if (pic1.use_argb) { + int n; + fprintf(stderr, "max absolute differences per channel: "); + for (n = 0; n < 3; ++n) { // skip the alpha channel + const int range = DiffScaleChannel((uint8_t*)pic1.argb + n, + pic1.argb_stride * 4, + (const uint8_t*)pic2.argb + n, + pic2.argb_stride * 4, + 4, pic1.width, pic1.height, scale); + fprintf(stderr, "[%d]", range); + } + fprintf(stderr, "\n"); + } else { + fprintf(stderr, "Can only compute the difference map in ARGB format.\n"); + goto End; + } + data_size = WebPEncodeLosslessBGRA((const uint8_t*)pic1.argb, + pic1.width, pic1.height, + pic1.argb_stride * 4, + &data); + if (data_size == 0) { + fprintf(stderr, "Error during lossless encoding.\n"); + goto End; + } + ret = ImgIoUtilWriteFile(output, data, data_size) ? 0 : 1; + WebPFree(data); + if (ret) goto End; + } ret = 0; End: