X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=image.cpp;h=937f486bfbc01cbe3676b54ce67be52f84b1a754;hb=67dfb223601baf074c3ae422dbc5cc070e70c034;hp=ec056d738d8c0b417c159842aa68b5d2717e7167;hpb=20f35e03712f58ec4dd51508f3874b3685738aa9;p=apitrace diff --git a/image.cpp b/image.cpp index ec056d7..937f486 100644 --- a/image.cpp +++ b/image.cpp @@ -24,6 +24,9 @@ **************************************************************************/ +#include + +#include #include #include @@ -66,7 +69,7 @@ struct Pixel { }; -void +bool Image::writeBMP(const char *filename) const { struct FileHeader bmfh; struct InfoHeader bmih; @@ -92,6 +95,9 @@ Image::writeBMP(const char *filename) const { std::ofstream stream(filename, std::ofstream::binary); + if (!stream) + return false; + stream.write((const char *)&bmfh, 14); stream.write((const char *)&bmih, 40); @@ -125,7 +131,184 @@ Image::writeBMP(const char *filename) const { } stream.close(); + + return true; +} + +bool +Image::writePNG(const char *filename) const { + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + + fp = fopen(filename, "wb"); + if (!fp) + goto no_fp; + + 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_init_io(png_ptr, fp); + + 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_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*4); + png_write_rows(png_ptr, &row, 1); + } + } else { + unsigned y = height; + while (y--) { + png_bytep row = (png_bytep)(pixels + y*width*4); + png_write_rows(png_ptr, &row, 1); + } + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(fp); + return true; + +no_png: + fclose(fp); +no_fp: + return false; } +Image * +readPNG(const char *filename) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + png_infop end_info; + Image *image; + + fp = fopen(filename, "rb"); + if (!fp) + goto no_fp; + + png_ptr = png_create_read_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_read_struct(&png_ptr, NULL, NULL); + goto no_png; + } + + end_info = png_create_info_struct(png_ptr); + if (!end_info) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + goto no_png; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + goto no_png; + } + + png_init_io(png_ptr, fp); + + png_read_info(png_ptr, info_ptr); + + png_uint_32 width, height; + int bit_depth, color_type, interlace_type, compression_type, filter_method; + + png_get_IHDR(png_ptr, info_ptr, + &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_method); + + image = new Image(width, height); + if (!image) + goto no_image; + + /* Convert to RGBA8 */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_gray_1_2_4_to_8(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + if (bit_depth == 16) + png_set_strip_16(png_ptr); + + for (unsigned y = 0; y < height; ++y) { + png_bytep row = (png_bytep)(image->pixels + y*width*4); + png_read_row(png_ptr, row, NULL); + } + + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(fp); + return image; + +no_image: + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); +no_png: + fclose(fp); +no_fp: + return NULL; +} + + +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; +} + + + } /* namespace Image */