From 60a8bf70228ce3783e32793e61ddfa3b495dfce1 Mon Sep 17 00:00:00 2001 From: Jason Summers Date: Mon, 2 Nov 2020 14:06:45 -0500 Subject: [PATCH] tiff: Support Orientation tag --- modules/tiff.c | 34 +++++++++---- src/deark-bitmap.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/deark-private.h | 2 + 3 files changed, 156 insertions(+), 15 deletions(-) diff --git a/modules/tiff.c b/modules/tiff.c index e894c957..2eceecb2 100644 --- a/modules/tiff.c +++ b/modules/tiff.c @@ -152,7 +152,7 @@ struct page_ctx { u32 predictor; u32 sample_format; u32 resolution_unit; - double density_x, density_y; + double density_ImageWidth, density_ImageLength; i64 imagewidth, imagelength; // Raw tag values, before considering Orientation i64 jpegoffset; i64 jpeglength; @@ -1697,10 +1697,10 @@ static void handler_resolution(deark *c, lctx *d, const struct taginfo *tg, cons read_numeric_value(c, d, tg, 0, &nv, NULL); if(!nv.isvalid) return; if(tg->tagnum==TAG_XRESOLUTION) { - tg->pg->density_x = nv.val_double; + tg->pg->density_ImageWidth = nv.val_double; } else if(tg->tagnum==TAG_YRESOLUTION) { - tg->pg->density_y = nv.val_double; + tg->pg->density_ImageLength = nv.val_double; } } @@ -2863,9 +2863,15 @@ static void set_image_density(deark *c, lctx *d, struct page_ctx *pg, de_finfo * { if(pg->resolution_unit<1) return; - // TODO: Respect orientation - fi->density.xdens = pg->density_x; - fi->density.ydens = pg->density_y; + if(pg->orientation>=5 && pg->orientation<=8) { + // For some orientations, the x dimension is the ImageLength dimension. + fi->density.xdens = pg->density_ImageLength; + fi->density.ydens = pg->density_ImageWidth; + } + else { + fi->density.xdens = pg->density_ImageWidth; + fi->density.ydens = pg->density_ImageLength; + } if(pg->resolution_unit==1) { fi->density.code = DE_DENSITY_UNK_UNITS; } @@ -3083,6 +3089,18 @@ static void do_process_ifd_image(deark *c, lctx *d, struct page_ctx *pg) partial_failure: fi = de_finfo_create(c); + + if(pg->orientation>=5 && pg->orientation<=8) { + de_bitmap_transpose(img); + } + if(pg->orientation==2 || pg->orientation==3 || pg->orientation==6 || pg->orientation==7) { + de_bitmap_mirror(img); + } + if(pg->orientation==3 || pg->orientation==4 || pg->orientation==7 || pg->orientation==8) { + // Could use DE_CREATEFLAG_FLIP_IMAGE instead. + de_bitmap_flip(img); + } + set_image_density(c, d, pg, fi); de_bitmap_write_to_file_finfo(img, fi, 0); @@ -3115,8 +3133,8 @@ static void process_ifd(deark *c, lctx *d, i64 ifd_idx1, i64 ifdpos1, int ifdtyp static const struct tagnuminfo default_tni = { 0, 0x00, "?", NULL, NULL }; pg = de_malloc(c, sizeof(struct page_ctx)); - pg->density_x = 0.0; - pg->density_y = 0.0; + pg->density_ImageWidth = 0.0; + pg->density_ImageLength = 0.0; pg->ifd_idx = ifd_idx1; pg->ifdpos = ifdpos1; pg->ifdtype = ifdtype1; diff --git a/src/deark-bitmap.c b/src/deark-bitmap.c index 6441f67c..83e0b7c9 100644 --- a/src/deark-bitmap.c +++ b/src/deark-bitmap.c @@ -63,11 +63,23 @@ int de_is_grayscale_palette(const de_color *pal, i64 num_entries) return 1; } +static void de_bitmap_free_pixels(de_bitmap *b) +{ + if(b) { + deark *c = b->c; + + if(b->bitmap) { + de_free(c, b->bitmap); + b->bitmap = NULL; + } + b->bitmap_size = 0; + } +} + static void de_bitmap_alloc_pixels(de_bitmap *img) { if(img->bitmap) { - de_free(img->c, img->bitmap); - img->bitmap = NULL; + de_bitmap_free_pixels(img); } if(!de_good_image_dimensions(img->c, img->width, img->height)) { @@ -145,11 +157,23 @@ static de_bitmap *de_bitmap_clone_noalloc(de_bitmap *img1) img2 = de_bitmap_create_noinit(img1->c); de_memcpy(img2, img1, sizeof(de_bitmap)); - img2->bitmap = 0; + img2->bitmap = NULL; img2->bitmap_size = 0; return img2; } +static de_bitmap *de_bitmap_clone(de_bitmap *img1) +{ + de_bitmap *img2; + i64 nbytes_to_copy; + + img2 = de_bitmap_clone_noalloc(img1); + de_bitmap_alloc_pixels(img2); + nbytes_to_copy = de_min_int(img2->bitmap_size, img1->bitmap_size); + de_memcpy(img2->bitmap, img1->bitmap, nbytes_to_copy); + return img2; +} + // Returns NULL if there's no need to optimize the image static de_bitmap *get_optimized_image(de_bitmap *img1) { @@ -406,7 +430,8 @@ void de_bitmap_destroy(de_bitmap *b) { if(b) { deark *c = b->c; - if(b->bitmap) de_free(c, b->bitmap); + + de_bitmap_free_pixels(b); de_free(c, b); } } @@ -619,12 +644,73 @@ void de_convert_image_rgb(dbuf *f, i64 fpos, } } -// Transpose (flip over the line y=x) a square bitmap. -void de_bitmap_transpose(de_bitmap *img) +// Turn padding pixels into real pixels. +static void de_bitmap_apply_padding(de_bitmap *img) +{ + if(img->unpadded_width != img->width) { + img->unpadded_width = img->width; + } +} + +// TODO: This function could be made more efficient. +void de_bitmap_flip(de_bitmap *img) { i64 i, j; + i64 nr; + + nr = img->height/2; + + for(j=0; jheight-1-j; + + for(i=0; iwidth; i++) { + de_color tmp1, tmp2; - if(img->height != img->width) return; + tmp1 = de_bitmap_getpixel(img, i, row1); + tmp2 = de_bitmap_getpixel(img, i, row2); + if(tmp1==tmp2) continue; + de_bitmap_setpixel_rgba(img, i, row2, tmp1); + de_bitmap_setpixel_rgba(img, i, row1, tmp2); + } + } +} + +// Not recommended for use with padded bitmaps (e.g. those created with +// de_bitmap_create2()). We don't support padding pixels on the left, so we can't +// truly mirror such an image. Current behavior is to turn padding pixels into +// real pixels. +void de_bitmap_mirror(de_bitmap *img) +{ + i64 i, j; + i64 nc; + + de_bitmap_apply_padding(img); + nc = img->width/2; + + for(j=0; jheight; j++) { + for(i=0; iwidth-1-i; + + tmp1 = de_bitmap_getpixel(img, col1, j); + tmp2 = de_bitmap_getpixel(img, col2, j); + if(tmp1==tmp2) continue; + de_bitmap_setpixel_rgba(img, col2, j, tmp1); + de_bitmap_setpixel_rgba(img, col1, j, tmp2); + } + } +} + +// Transpose (flip over the line y=x) a square bitmap. +static void bitmap_transpose_square(de_bitmap *img) +{ + i64 i, j; for(j=0; jheight; j++) { for(i=0; iwidth == img->height) { + bitmap_transpose_square(img); + goto done; + } + + imgtmp = de_bitmap_clone(img); + + de_bitmap_free_pixels(img); + img->width = imgtmp->height; + img->unpadded_width = imgtmp->height; + img->height = imgtmp->width; + + for(j=0; jheight; j++) { + for(i=0; iwidth; i++) { + de_color tmp1; + + tmp1 = de_bitmap_getpixel(imgtmp, j, i); + de_bitmap_setpixel_rgba(img, i, j, tmp1); + } + } + +done: + if(imgtmp) de_bitmap_destroy(imgtmp); +} + // Paint a solid, solid-color rectangle onto an image. // (Pixels will be replaced, not merged.) void de_bitmap_rect(de_bitmap *img, diff --git a/src/deark-private.h b/src/deark-private.h index ec9f11aa..d81179ff 100644 --- a/src/deark-private.h +++ b/src/deark-private.h @@ -902,6 +902,8 @@ int de_is_grayscale_palette(const de_color *pal, i64 num_entries); #define DE_BITMAPFLAG_WHITEISTRNS 0x1 #define DE_BITMAPFLAG_MERGE 0x2 +void de_bitmap_flip(de_bitmap *img); +void de_bitmap_mirror(de_bitmap *img); void de_bitmap_transpose(de_bitmap *img); void de_bitmap_rect(de_bitmap *img, i64 xpos, i64 ypos, i64 width, i64 height, -- 2.11.4.GIT