diff options
| author | Josh Andler <scislac@gmail.com> | 2012-07-23 19:23:23 +0000 |
|---|---|---|
| committer | Josh Andler <scislac@gmail.com> | 2012-07-23 19:23:23 +0000 |
| commit | 377dc932067f9095ca3d940b4cf5be6e07ccb2f1 (patch) | |
| tree | 911ebf771d423330760b0bd09b4ae0c789d6c62a /src/extension/internal/image-resolution.cpp | |
| parent | Bitmap. Fix for Bug #165952 (png resolution not imported) by Daniel Wagenaar. (diff) | |
| download | inkscape-377dc932067f9095ca3d940b4cf5be6e07ccb2f1.tar.gz inkscape-377dc932067f9095ca3d940b4cf5be6e07ccb2f1.zip | |
Add missing files and add Daniel Wagenaar to Authors
(bzr r11568)
Diffstat (limited to 'src/extension/internal/image-resolution.cpp')
| -rw-r--r-- | src/extension/internal/image-resolution.cpp | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/extension/internal/image-resolution.cpp b/src/extension/internal/image-resolution.cpp new file mode 100644 index 000000000..53fcc0fbf --- /dev/null +++ b/src/extension/internal/image-resolution.cpp @@ -0,0 +1,318 @@ +/* + * Authors: + * Daniel Wagenaar <daw@caltech.edu> + * + * Copyright (C) 2012 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "image-resolution.h" + +#define IR_TRY_PNG 1 +#ifdef HAVE_EXIF +#define IR_TRY_EXIF 1 +#endif +#define IR_TRY_EXIV 0 +#ifdef HAVE_JPEG +#define IR_TRY_JFIF 1 +#endif + +namespace Inkscape { +namespace Extension { +namespace Internal { + +ImageResolution::ImageResolution(char const *fn) { + ok_ = false; + + readpng(fn); + if (!ok_) + readexif(fn); + if (!ok_) + readexiv(fn); + if (!ok_) + readjfif(fn); +} + +bool ImageResolution::ok() const { + return ok_; +} + +double ImageResolution::x() const { + return x_; +} + +double ImageResolution::y() const { + return y_; +} + + + +#if IR_TRY_PNG + +#include <png.h> + +static bool haspngheader(FILE *fp) { + unsigned char header[8]; + if (fread(header, 1, 8, fp)!=8) + return false; + + fseek(fp, 0, SEEK_SET); + + if (png_sig_cmp(header, 0, 8)) + return false; + + return true; +} + +// Implementation using libpng +void ImageResolution::readpng(char const *fn) { + FILE *fp = fopen(fn, "rb"); + if (!fp) + return; + + if (!haspngheader(fp)) { + fclose(fp); + return; + } + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png_ptr) + return; + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!png_ptr) { + png_destroy_read_struct(&png_ptr, 0, 0); + return; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, 0); + fclose(fp); + return; + } + + png_init_io(png_ptr, fp); + png_read_info(png_ptr, info_ptr); + + png_uint_32 res_x, res_y; + int unit_type; + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type); + + png_destroy_read_struct(&png_ptr, &info_ptr, 0); + fclose(fp); + + if (unit_type == PNG_RESOLUTION_METER) { + ok_ = true; + x_ = res_x * 2.54/100; + y_ = res_y * 2.54/100; + } +} +#else + +// Dummy implementation +void ImageResolution::readpng(char const *) { +} + +#endif + +#if IR_TRY_EXIF + +#include <math.h> +#include <libexif/exif-data.h> + +static double exifDouble(ExifEntry *entry, ExifByteOrder byte_order) { + switch (entry->format) { + case EXIF_FORMAT_BYTE: + return double(entry->data[0]); + case EXIF_FORMAT_SHORT: + return double(exif_get_short(entry->data, byte_order)); + case EXIF_FORMAT_LONG: + return double(exif_get_long(entry->data, byte_order)); + case EXIF_FORMAT_RATIONAL: { + ExifRational r = exif_get_rational(entry->data, byte_order); + return double(r.numerator)/double(r.denominator); + } + case EXIF_FORMAT_SBYTE: + return double(*(signed char *)entry->data); + case EXIF_FORMAT_SSHORT: + return double(exif_get_sshort(entry->data, byte_order)); + case EXIF_FORMAT_SLONG: + return double(exif_get_slong(entry->data, byte_order)); + case EXIF_FORMAT_SRATIONAL: { + ExifSRational r = exif_get_srational(entry->data, byte_order); + return double(r.numerator)/double(r.denominator); + } + case EXIF_FORMAT_FLOAT: + return double(((float *)entry->data)[0]); + case EXIF_FORMAT_DOUBLE: + return ((double *)entry->data)[0]; + default: + return nan(0); + } +} + +// Implementation using libexif +void ImageResolution::readexif(char const *fn) { + ExifData *ed; + ed = exif_data_new_from_file(fn); + if (!ed) + return; + ExifByteOrder byte_order = exif_data_get_byte_order(ed); + + ExifEntry *xres = exif_content_get_entry(ed->ifd[EXIF_IFD_0], + EXIF_TAG_X_RESOLUTION); + ExifEntry *yres = exif_content_get_entry(ed->ifd[EXIF_IFD_0], + EXIF_TAG_Y_RESOLUTION); + ExifEntry *unit = exif_content_get_entry(ed->ifd[EXIF_IFD_0], + EXIF_TAG_RESOLUTION_UNIT); + if (xres && yres) { + x_ = exifDouble(xres, byte_order); + y_ = exifDouble(yres, byte_order); + if (unit) { + double u = exifDouble(unit, byte_order); + if (u==3) { + x_ *= 2.54; + y_ *= 2.54; + } + } + ok_ = true; + } + exif_data_free(ed); +} + +#else + +// Dummy implementation +void ImageResolution::readexif(char const *) { +} + +#endif + +#if IR_TRY_EXIV + +void ImageResolution::readexiv(char const *fn) { + Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(fn); + if (!image.get()) + return; + + image->readMetadata(); + Exiv2::ExifData &exifData = image->exifData(); + if (exifData.empty()) + return; + + Exiv2::ExifData::const_iterator end = exifData.end(); + bool havex = false; + bool havey = false; + bool haveunit = false; + int unit; + for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) { + if (ok_) + break; + if (i->tag()==0x011a) { + // X Resolution + x_ = i->toFloat(); + havex = true; + } else if (i->tag()==0x011b) { + // Y Resolution + y_ = i->toFloat(); + havey = true; + } else if (i->tag()==0x0128) { + unit = i->toLong(); + } + ok_ = havex && havey && haveunit; + } + if (haveunit) { + if (unit==3) { + x_ *= 2.54; + y_ *= 2.54; + } + } + ok_ = havex && havey; +} + +#else + +// Dummy implementation +void ImageResolution::readexiv(char const *) { +} + +#endif + +#if IR_TRY_JFIF + +#include <jpeglib.h> +#include <setjmp.h> + +static void irjfif_error_exit(j_common_ptr cinfo) { + longjmp(*(jmp_buf*)cinfo->client_data, 1); +} + +static void irjfif_emit_message(j_common_ptr, int) { +} + +static void irjfif_output_message(j_common_ptr) { +} + +static void irjfif_format_message(j_common_ptr, char *) { +} + +static void irjfif_reset(j_common_ptr) { +} + +void ImageResolution::readjfif(char const *fn) { + FILE *ifd = fopen(fn, "rb"); + if (!ifd) + return; + + struct jpeg_decompress_struct cinfo; + jmp_buf jbuf; + struct jpeg_error_mgr jerr; + bool constr = false; + + if (setjmp(jbuf)) { + fclose(ifd); + if (constr) + jpeg_destroy_decompress(&cinfo); + return; + } + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + jerr.error_exit = &irjfif_error_exit; + jerr.emit_message = &irjfif_emit_message; + jerr.output_message = &irjfif_output_message; + jerr.format_message = &irjfif_format_message; + jerr.reset_error_mgr = &irjfif_reset; + cinfo.client_data = (void*)&jbuf; + constr = true; + + jpeg_stdio_src(&cinfo, ifd); + jpeg_read_header(&cinfo, TRUE); + + if (cinfo.density_unit==1) { + x_ = cinfo.X_density; + y_ = cinfo.Y_density; + ok_ = true; + } + + constr = false; + jpeg_destroy_decompress(&cinfo); + fclose(ifd); +} + +#else + +// Dummy implementation +void ImageResolution::readjfif(char const *) { +} + +#endif + +} +} +} |
