X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=image.cpp;h=1f96c29bb5c60c8d30d657e7a0c6ad7a09f1f3b0;hb=ecf37415b269e6051b01104740cb8f6ae736e8ad;hp=ce37c190c097cff6a624d4870e9dca5a58adfad3;hpb=4cebb746f86d7ff67d816e15a68921885c2958c9;p=apitrace diff --git a/image.cpp b/image.cpp index ce37c19..1f96c29 100644 --- a/image.cpp +++ b/image.cpp @@ -26,7 +26,9 @@ #include +#include #include +#include #include @@ -164,7 +166,7 @@ Image::writePNG(const char *filename) const { png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); + png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); png_write_info(png_ptr, info_ptr); @@ -273,4 +275,150 @@ no_fp: } +double Image::compare(Image &ref) +{ + if (width != ref.width || + height != ref.height) { + return 0.0; + } + + const unsigned char *pSrc = start(); + const unsigned char *pRef = ref.start(); + + unsigned long long error = 0; + for (unsigned y = 0; y < height; ++y) { + for (unsigned x = 0; x < width; ++x) { + // FIXME: Ignore alpha channel until we are able to pick a visual + // that matches the traces + for (unsigned c = 0; c < 3; ++c) { + int delta = pSrc[x*4 + c] - pRef[x*4 + c]; + error += delta*delta; + } + } + + pSrc += stride(); + pRef += ref.stride(); + } + + double numerator = error*2 + 1; + double denominator = height*width*3ULL*255ULL*255ULL*2; + double quotient = numerator/denominator; + + // Precision in bits + double precision = -log(quotient)/log(2.0); + + return precision; +} + +struct png_tmp_buffer +{ + char *buffer; + size_t size; +}; + +static void +pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) +{ + struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_ptr->io_ptr; + size_t nsize = buf->size + length; + + /* allocate or grow buffer */ + if (buf->buffer) + buf->buffer = (char*)realloc(buf->buffer, nsize); + else + buf->buffer = (char*)malloc(nsize); + + if (!buf->buffer) + png_error(png_ptr, "Buffer allocation error"); + + memcpy(buf->buffer + buf->size, data, length); + buf->size += length; +} + +bool writePixelsToBuffer(unsigned char *pixels, + unsigned width, unsigned height, unsigned numChannels, + bool flipped, + char **buffer, + int *size) +{ + struct png_tmp_buffer png_mem; + png_structp png_ptr; + png_infop info_ptr; + int type; + + png_mem.buffer = NULL; + png_mem.size = 0; + + switch (numChannels) { + case 4: + type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case 3: + type = PNG_COLOR_TYPE_RGB; + break; + case 2: + type = PNG_COLOR_TYPE_GRAY_ALPHA; + break; + case 1: + type = PNG_COLOR_TYPE_GRAY; + break; + default: + goto no_png; + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + goto no_png; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, NULL); + goto no_png; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + goto no_png; + } + + png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL); + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, + type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); + + png_write_info(png_ptr, info_ptr); + + if (!flipped) { + for (unsigned y = 0; y < height; ++y) { + png_bytep row = (png_bytep)(pixels + y*width*numChannels); + png_write_rows(png_ptr, &row, 1); + } + } else { + unsigned y = height; + while (y--) { + png_bytep row = (png_bytep)(pixels + y*width*numChannels); + png_write_rows(png_ptr, &row, 1); + } + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + *buffer = png_mem.buffer; + *size = png_mem.size; + + return true; + +no_png: + *buffer = NULL; + *size = 0; + + if (png_mem.buffer) + free(png_mem.buffer); + return false; +} + } /* namespace Image */