Skip to content

Latest commit

 

History

History
9142 lines (8389 loc) · 294 KB

tiffcrop.c

File metadata and controls

9142 lines (8389 loc) · 294 KB
 
Nov 10, 2019
Nov 10, 2019
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* $Id: tiffcrop.c,v 1.20 2010-12-14 02:03:24 faxguy Exp $ */
/* tiffcrop.c -- a port of tiffcp.c extended to include manipulations of
* the image data through additional options listed below
*
* Original code:
* Copyright (c) 1988-1997 Sam Leffler
* Copyright (c) 1991-1997 Silicon Graphics, Inc.
* Additions (c) Richard Nolde 2006-2010
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that (i) the above copyright notices and this permission notice appear in
* all copies of the software and related documentation, and (ii) the names of
* Sam Leffler and Silicon Graphics may not be used in any advertising or
* publicity relating to the software without the specific, prior written
* permission of Sam Leffler and Silicon Graphics.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS OR ANY OTHER COPYRIGHT
* HOLDERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
* ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
* OR PERFORMANCE OF THIS SOFTWARE.
*
* Some portions of the current code are derived from tiffcp, primarly in
* the areas of lowlevel reading and writing of TAGS, scanlines and tiles though
* some of the original functions have been extended to support arbitrary bit
* depths. These functions are presented at the top of this file.
*
* Add support for the options below to extract sections of image(s)
* and to modify the whole image or selected portions of each image by
* rotations, mirroring, and colorscale/colormap inversion of selected
* types of TIFF images when appropriate. Some color model dependent
* functions are restricted to bilevel or 8 bit per sample data.
* See the man page for the full explanations.
*
* New Options:
* -h Display the syntax guide.
* -v Report the version and last build date for tiffcrop and libtiff.
* -z x1,y1,x2,y2:x3,y3,x4,y4:..xN,yN,xN + 1, yN + 1
* Specify a series of coordinates to define rectangular
* regions by the top left and lower right corners.
* -e c|d|i|m|s export mode for images and selections from input images
* combined All images and selections are written to a single file (default)
* with multiple selections from one image combined into a single image
* divided All images and selections are written to a single file
* with each selection from one image written to a new image
* image Each input image is written to a new file (numeric filename sequence)
* with multiple selections from the image combined into one image
* multiple Each input image is written to a new file (numeric filename sequence)
* with each selection from the image written to a new image
* separated Individual selections from each image are written to separate files
* -U units [in, cm, px ] inches, centimeters or pixels
* -H # Set horizontal resolution of output images to #
* -V # Set vertical resolution of output images to #
* -J # Horizontal margin of output page to # expressed in current
* units when sectioning image into columns x rows
* using the -S cols:rows option.
* -K # Vertical margin of output page to # expressed in current
* units when sectioning image into columns x rows
* using the -S cols:rows option.
* -X # Horizontal dimension of region to extract expressed in current
* units
* -Y # Vertical dimension of region to extract expressed in current
* units
* -O orient Orientation for output image, portrait, landscape, auto
* -P page Page size for output image segments, eg letter, legal, tabloid,
* etc.
* -S cols:rows Divide the image into equal sized segments using cols across
* and rows down
* -E t|l|r|b Edge to use as origin
* -m #,#,#,# Margins from edges for selection: top, left, bottom, right
* (commas separated)
* -Z #:#,#:# Zones of the image designated as zone X of Y,
* eg 1:3 would be first of three equal portions measured
* from reference edge
* -N odd|even|#,#-#,#|last
* Select sequences and/or ranges of images within file
* to process. The words odd or even may be used to specify
* all odd or even numbered images the word last may be used
* in place of a number in the sequence to indicate the final
* image in the file without knowing how many images there are.
* -R # Rotate image or crop selection by 90,180,or 270 degrees
* clockwise
* -F h|v Flip (mirror) image or crop selection horizontally
* or vertically
* -I [black|white|data|both]
* Invert color space, eg dark to light for bilevel and grayscale images
* If argument is white or black, set the PHOTOMETRIC_INTERPRETATION
* tag to MinIsBlack or MinIsWhite without altering the image data
* If the argument is data or both, the image data are modified:
* both inverts the data and the PHOTOMETRIC_INTERPRETATION tag,
* data inverts the data but not the PHOTOMETRIC_INTERPRETATION tag
* -D input:<filename1>,output:<filename2>,format:<raw|txt>,level:N,debug:N
* Dump raw data for input and/or output images to individual files
* in raw (binary) format or text (ASCII) representing binary data
* as strings of 1s and 0s. The filename arguments are used as stems
* from which individual files are created for each image. Text format
* includes annotations for image parameters and scanline info. Level
* selects which functions dump data, with higher numbers selecting
* lower level, scanline level routines. Debug reports a limited set
* of messages to monitor progess without enabling dump logs.
*/
static char tiffcrop_version_id[] = "2.4";
static char tiffcrop_rev_date[] = "12-13-2010";
#include "tif_config.h"
#include "tiffiop.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <limits.h>
#include <sys/stat.h>
#include <assert.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifndef HAVE_GETOPT
extern int getopt(int, char**, char*);
#endif
#ifdef NEED_LIBPORT
# include "libport.h"
#endif
#include "tiffio.h"
#if defined(VMS)
# define unlink delete
#endif
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
#define TRUE 1
#define FALSE 0
#ifndef TIFFhowmany
#define TIFFhowmany(x, y) ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y)))
#define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
#endif
/*
* Definitions and data structures required to support cropping and image
* manipulations.
*/
#define EDGE_TOP 1
#define EDGE_LEFT 2
#define EDGE_BOTTOM 3
#define EDGE_RIGHT 4
#define EDGE_CENTER 5
#define MIRROR_HORIZ 1
#define MIRROR_VERT 2
#define MIRROR_BOTH 3
#define ROTATECW_90 8
#define ROTATECW_180 16
#define ROTATECW_270 32
#define ROTATE_ANY ROTATECW_90 || ROTATECW_180 || ROTATECW_270
#define CROP_NONE 0
#define CROP_MARGINS 1
#define CROP_WIDTH 2
#define CROP_LENGTH 4
#define CROP_ZONES 8
#define CROP_REGIONS 16
#define CROP_ROTATE 32
#define CROP_MIRROR 64
#define CROP_INVERT 128
/* Modes for writing out images and selections */
#define ONE_FILE_COMPOSITE 0 /* One file, sections combined sections */
#define ONE_FILE_SEPARATED 1 /* One file, sections to new IFDs */
#define FILE_PER_IMAGE_COMPOSITE 2 /* One file per image, combined sections */
#define FILE_PER_IMAGE_SEPARATED 3 /* One file per input image */
#define FILE_PER_SELECTION 4 /* One file per selection */
#define COMPOSITE_IMAGES 0 /* Selections combined into one image */
#define SEPARATED_IMAGES 1 /* Selections saved to separate images */
#define STRIP 1
#define TILE 2
#define MAX_REGIONS 8 /* number of regions to extract from a single page */
#define MAX_OUTBUFFS 8 /* must match larger of zones or regions */
#define MAX_SECTIONS 32 /* number of sections per page to write to output */
#define MAX_IMAGES 2048 /* number of images in descrete list, not in the file */
#define MAX_SAMPLES 8 /* maximum number of samples per pixel supported */
#define MAX_BITS_PER_SAMPLE 64 /* maximum bit depth supported */
#define MAX_EXPORT_PAGES 999999 /* maximum number of export pages per file */
#define DUMP_NONE 0
#define DUMP_TEXT 1
#define DUMP_RAW 2
/* Offsets into buffer for margins and fixed width and length segments */
struct offset {
uint32 tmargin;
uint32 lmargin;
uint32 bmargin;
uint32 rmargin;
uint32 crop_width;
uint32 crop_length;
uint32 startx;
uint32 endx;
uint32 starty;
uint32 endy;
};
/* Description of a zone within the image. Position 1 of 3 zones would be
* the first third of the image. These are computed after margins and
* width/length requests are applied so that you can extract multiple
* zones from within a larger region for OCR or barcode recognition.
*/
struct buffinfo {
uint32 size; /* size of this buffer */
unsigned char *buffer; /* address of the allocated buffer */
};
struct zone {
int position; /* ordinal of segment to be extracted */
int total; /* total equal sized divisions of crop area */
};
struct pageseg {
uint32 x1; /* index of left edge */
uint32 x2; /* index of right edge */
uint32 y1; /* index of top edge */
uint32 y2; /* index of bottom edge */
int position; /* ordinal of segment to be extracted */
int total; /* total equal sized divisions of crop area */
uint32 buffsize; /* size of buffer needed to hold the cropped zone */
};
struct coordpairs {
double X1; /* index of left edge in current units */
double X2; /* index of right edge in current units */
double Y1; /* index of top edge in current units */
double Y2; /* index of bottom edge in current units */
};
struct region {
uint32 x1; /* pixel offset of left edge */
uint32 x2; /* pixel offset of right edge */
uint32 y1; /* pixel offset of top edge */
uint32 y2; /* picel offset of bottom edge */
uint32 width; /* width in pixels */
uint32 length; /* length in pixels */
uint32 buffsize; /* size of buffer needed to hold the cropped region */
unsigned char *buffptr; /* address of start of the region */
};
/* Cropping parameters from command line and image data
* Note: This should be renamed to proc_opts and expanded to include all current globals
* if possible, but each function that accesses global variables will have to be redone.
*/
struct crop_mask {
double width; /* Selection width for master crop region in requested units */
double length; /* Selection length for master crop region in requesed units */
double margins[4]; /* Top, left, bottom, right margins */
float xres; /* Horizontal resolution read from image*/
float yres; /* Vertical resolution read from image */
uint32 combined_width; /* Width of combined cropped zones */
uint32 combined_length; /* Length of combined cropped zones */
uint32 bufftotal; /* Size of buffer needed to hold all the cropped region */
uint16 img_mode; /* Composite or separate images created from zones or regions */
uint16 exp_mode; /* Export input images or selections to one or more files */
uint16 crop_mode; /* Crop options to be applied */
uint16 res_unit; /* Resolution unit for margins and selections */
uint16 edge_ref; /* Reference edge for sections extraction and combination */
uint16 rotation; /* Clockwise rotation of the extracted region or image */
uint16 mirror; /* Mirror extracted region or image horizontally or vertically */
uint16 invert; /* Invert the color map of image or region */
uint16 photometric; /* Status of photometric interpretation for inverted image */
uint16 selections; /* Number of regions or zones selected */
uint16 regions; /* Number of regions delimited by corner coordinates */
struct region regionlist[MAX_REGIONS]; /* Regions within page or master crop region */
uint16 zones; /* Number of zones delimited by Ordinal:Total requested */
struct zone zonelist[MAX_REGIONS]; /* Zones indices to define a region */
struct coordpairs corners[MAX_REGIONS]; /* Coordinates of upper left and lower right corner */
};
#define MAX_PAPERNAMES 49
#define MAX_PAPERNAME_LENGTH 15
#define DEFAULT_RESUNIT RESUNIT_INCH
#define DEFAULT_PAGE_HEIGHT 14.0
#define DEFAULT_PAGE_WIDTH 8.5
#define DEFAULT_RESOLUTION 300
#define DEFAULT_PAPER_SIZE "legal"
#define ORIENTATION_NONE 0
#define ORIENTATION_PORTRAIT 1
#define ORIENTATION_LANDSCAPE 2
#define ORIENTATION_SEASCAPE 4
#define ORIENTATION_AUTO 16
#define PAGE_MODE_NONE 0
#define PAGE_MODE_RESOLUTION 1
#define PAGE_MODE_PAPERSIZE 2
#define PAGE_MODE_MARGINS 4
#define PAGE_MODE_ROWSCOLS 8
#define INVERT_DATA_ONLY 10
#define INVERT_DATA_AND_TAG 11
struct paperdef {
char name[MAX_PAPERNAME_LENGTH];
double width;
double length;
double asratio;
};
/* European page sizes corrected from update sent by
* thomas . jarosch @ intra2net . com on 5/7/2010
* Paper Size Width Length Aspect Ratio */
struct paperdef PaperTable[MAX_PAPERNAMES] = {
{"default", 8.500, 14.000, 0.607},
{"pa4", 8.264, 11.000, 0.751},
{"letter", 8.500, 11.000, 0.773},
{"legal", 8.500, 14.000, 0.607},
{"half-letter", 8.500, 5.514, 1.542},
{"executive", 7.264, 10.528, 0.690},
{"tabloid", 11.000, 17.000, 0.647},
{"11x17", 11.000, 17.000, 0.647},
{"ledger", 17.000, 11.000, 1.545},
{"archa", 9.000, 12.000, 0.750},
{"archb", 12.000, 18.000, 0.667},
{"archc", 18.000, 24.000, 0.750},
{"archd", 24.000, 36.000, 0.667},
{"arche", 36.000, 48.000, 0.750},
{"csheet", 17.000, 22.000, 0.773},
{"dsheet", 22.000, 34.000, 0.647},
{"esheet", 34.000, 44.000, 0.773},
{"superb", 11.708, 17.042, 0.687},
{"commercial", 4.139, 9.528, 0.434},
{"monarch", 3.889, 7.528, 0.517},
{"envelope-dl", 4.333, 8.681, 0.499},
{"envelope-c5", 6.389, 9.028, 0.708},
{"europostcard", 4.139, 5.833, 0.710},
{"a0", 33.110, 46.811, 0.707},
{"a1", 23.386, 33.110, 0.706},
{"a2", 16.535, 23.386, 0.707},
{"a3", 11.693, 16.535, 0.707},
{"a4", 8.268, 11.693, 0.707},
{"a5", 5.827, 8.268, 0.705},
{"a6", 4.134, 5.827, 0.709},
{"a7", 2.913, 4.134, 0.705},
{"a8", 2.047, 2.913, 0.703},
{"a9", 1.457, 2.047, 0.712},
{"a10", 1.024, 1.457, 0.703},
{"b0", 39.370, 55.669, 0.707},
{"b1", 27.835, 39.370, 0.707},
{"b2", 19.685, 27.835, 0.707},
{"b3", 13.898, 19.685, 0.706},
{"b4", 9.843, 13.898, 0.708},
{"b5", 6.929, 9.843, 0.704},
{"b6", 4.921, 6.929, 0.710},
{"c0", 36.102, 51.063, 0.707},
{"c1", 25.512, 36.102, 0.707},
{"c2", 18.031, 25.512, 0.707},
{"c3", 12.756, 18.031, 0.707},
{"c4", 9.016, 12.756, 0.707},
{"c5", 6.378, 9.016, 0.707},
{"c6", 4.488, 6.378, 0.704},
{"", 0.000, 0.000, 1.000}
};
/* Structure to define input image parameters */
struct image_data {
float xres;
float yres;
uint32 width;
uint32 length;
uint16 res_unit;
uint16 bps;
uint16 spp;
uint16 planar;
uint16 photometric;
uint16 orientation;
uint16 compression;
uint16 adjustments;
};
/* Structure to define the output image modifiers */
struct pagedef {
char name[16];
double width; /* width in pixels */
double length; /* length in pixels */
double hmargin; /* margins to subtract from width of sections */
double vmargin; /* margins to subtract from height of sections */
double hres; /* horizontal resolution for output */
double vres; /* vertical resolution for output */
uint32 mode; /* bitmask of modifiers to page format */
uint16 res_unit; /* resolution unit for output image */
unsigned int rows; /* number of section rows */
unsigned int cols; /* number of section cols */
unsigned int orient; /* portrait, landscape, seascape, auto */
};
struct dump_opts {
int debug;
int format;
int level;
char mode[4];
char infilename[PATH_MAX + 1];
char outfilename[PATH_MAX + 1];
FILE *infile;
FILE *outfile;
};
/* globals */
static int outtiled = -1;
static uint32 tilewidth = 0;
static uint32 tilelength = 0;
static uint16 config = 0;
static uint16 compression = 0;
static uint16 predictor = 0;
static uint16 fillorder = 0;
static uint32 rowsperstrip = 0;
static uint32 g3opts = 0;
static int ignore = FALSE; /* if true, ignore read errors */
static uint32 defg3opts = (uint32) -1;
static int quality = 100; /* JPEG quality */
/* static int jpegcolormode = -1; was JPEGCOLORMODE_RGB; */
static int jpegcolormode = JPEGCOLORMODE_RGB;
static uint16 defcompression = (uint16) -1;
static uint16 defpredictor = (uint16) -1;
static int pageNum = 0;
static int little_endian = 1;
/* Functions adapted from tiffcp with additions or significant modifications */
static int readContigStripsIntoBuffer (TIFF*, uint8*);
static int readSeparateStripsIntoBuffer (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
static int readContigTilesIntoBuffer (TIFF*, uint8*, uint32, uint32, uint32, uint32, tsample_t, uint16);
static int readSeparateTilesIntoBuffer (TIFF*, uint8*, uint32, uint32, uint32, uint32, tsample_t, uint16);
static int writeBufferToContigStrips (TIFF*, uint8*, uint32);
static int writeBufferToContigTiles (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
static int writeBufferToSeparateStrips (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
static int writeBufferToSeparateTiles (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
static int extractContigSamplesToBuffer (uint8 *, uint8 *, uint32, uint32, tsample_t,
uint16, uint16, struct dump_opts *);
static int processCompressOptions(char*);
static void usage(void);
/* All other functions by Richard Nolde, not found in tiffcp */
static void initImageData (struct image_data *);
static void initCropMasks (struct crop_mask *);
static void initPageSetup (struct pagedef *, struct pageseg *, struct buffinfo []);
static void initDumpOptions(struct dump_opts *);
/* Command line and file naming functions */
void process_command_opts (int, char *[], char *, char *, uint32 *,
uint16 *, uint16 *, uint32 *, uint32 *, uint32 *,
struct crop_mask *, struct pagedef *,
struct dump_opts *,
unsigned int *, unsigned int *);
static int update_output_file (TIFF **, char *, int, char *, unsigned int *);
/* * High level functions for whole image manipulation */
static int get_page_geometry (char *, struct pagedef*);
static int computeInputPixelOffsets(struct crop_mask *, struct image_data *,
struct offset *);
static int computeOutputPixelOffsets (struct crop_mask *, struct image_data *,
struct pagedef *, struct pageseg *,
struct dump_opts *);
static int loadImage(TIFF *, struct image_data *, struct dump_opts *, unsigned char **);
static int correct_orientation(struct image_data *, unsigned char **);
static int getCropOffsets(struct image_data *, struct crop_mask *, struct dump_opts *);
static int processCropSelections(struct image_data *, struct crop_mask *,
unsigned char **, struct buffinfo []);
static int writeSelections(TIFF *, TIFF **, struct crop_mask *, struct image_data *,
struct dump_opts *, struct buffinfo [],
char *, char *, unsigned int*, unsigned int);
/* Section functions */
static int createImageSection(uint32, unsigned char **);
static int extractImageSection(struct image_data *, struct pageseg *,
unsigned char *, unsigned char *);
static int writeSingleSection(TIFF *, TIFF *, struct image_data *,
struct dump_opts *, uint32, uint32,
double, double, unsigned char *);
static int writeImageSections(TIFF *, TIFF *, struct image_data *,
struct pagedef *, struct pageseg *,
struct dump_opts *, unsigned char *,
unsigned char **);
/* Whole image functions */
static int createCroppedImage(struct image_data *, struct crop_mask *,
unsigned char **, unsigned char **);
static int writeCroppedImage(TIFF *, TIFF *, struct image_data *image,
struct dump_opts * dump,
uint32, uint32, unsigned char *, int, int);
/* Image manipulation functions */
static int rotateContigSamples8bits(uint16, uint16, uint16, uint32,
uint32, uint32, uint8 *, uint8 *);
static int rotateContigSamples16bits(uint16, uint16, uint16, uint32,
uint32, uint32, uint8 *, uint8 *);
static int rotateContigSamples24bits(uint16, uint16, uint16, uint32,
uint32, uint32, uint8 *, uint8 *);
static int rotateContigSamples32bits(uint16, uint16, uint16, uint32,
uint32, uint32, uint8 *, uint8 *);
static int rotateImage(uint16, struct image_data *, uint32 *, uint32 *,
unsigned char **);
static int mirrorImage(uint16, uint16, uint16, uint32, uint32,
unsigned char *);
static int invertImage(uint16, uint16, uint16, uint32, uint32,
unsigned char *);
/* Functions to reverse the sequence of samples in a scanline */
static int reverseSamples8bits (uint16, uint16, uint32, uint8 *, uint8 *);
static int reverseSamples16bits (uint16, uint16, uint32, uint8 *, uint8 *);
static int reverseSamples24bits (uint16, uint16, uint32, uint8 *, uint8 *);
static int reverseSamples32bits (uint16, uint16, uint32, uint8 *, uint8 *);
static int reverseSamplesBytes (uint16, uint16, uint32, uint8 *, uint8 *);
/* Functions for manipulating individual samples in an image */
static int extractSeparateRegion(struct image_data *, struct crop_mask *,
unsigned char *, unsigned char *, int);
static int extractCompositeRegions(struct image_data *, struct crop_mask *,
unsigned char *, unsigned char *);
static int extractContigSamples8bits (uint8 *, uint8 *, uint32,
tsample_t, uint16, uint16,
tsample_t, uint32, uint32);
static int extractContigSamples16bits (uint8 *, uint8 *, uint32,
tsample_t, uint16, uint16,
tsample_t, uint32, uint32);
static int extractContigSamples24bits (uint8 *, uint8 *, uint32,
tsample_t, uint16, uint16,
tsample_t, uint32, uint32);
static int extractContigSamples32bits (uint8 *, uint8 *, uint32,
tsample_t, uint16, uint16,
tsample_t, uint32, uint32);
static int extractContigSamplesBytes (uint8 *, uint8 *, uint32,
tsample_t, uint16, uint16,
tsample_t, uint32, uint32);
static int extractContigSamplesShifted8bits (uint8 *, uint8 *, uint32,
tsample_t, uint16, uint16,
tsample_t, uint32, uint32,
int);
static int extractContigSamplesShifted16bits (uint8 *, uint8 *, uint32,
tsample_t, uint16, uint16,
tsample_t, uint32, uint32,
int);
static int extractContigSamplesShifted24bits (uint8 *, uint8 *, uint32,
tsample_t, uint16, uint16,
tsample_t, uint32, uint32,
int);
static int extractContigSamplesShifted32bits (uint8 *, uint8 *, uint32,
tsample_t, uint16, uint16,
tsample_t, uint32, uint32,
int);
static int extractContigSamplesToTileBuffer(uint8 *, uint8 *, uint32, uint32,
uint32, uint32, tsample_t, uint16,
uint16, uint16, struct dump_opts *);
/* Functions to combine separate planes into interleaved planes */
static int combineSeparateSamples8bits (uint8 *[], uint8 *, uint32, uint32,
uint16, uint16, FILE *, int, int);
static int combineSeparateSamples16bits (uint8 *[], uint8 *, uint32, uint32,
uint16, uint16, FILE *, int, int);
static int combineSeparateSamples24bits (uint8 *[], uint8 *, uint32, uint32,
uint16, uint16, FILE *, int, int);
static int combineSeparateSamples32bits (uint8 *[], uint8 *, uint32, uint32,
uint16, uint16, FILE *, int, int);
static int combineSeparateSamplesBytes (unsigned char *[], unsigned char *,
uint32, uint32, tsample_t, uint16,
FILE *, int, int);
static int combineSeparateTileSamples8bits (uint8 *[], uint8 *, uint32, uint32,
uint32, uint32, uint16, uint16,
FILE *, int, int);
static int combineSeparateTileSamples16bits (uint8 *[], uint8 *, uint32, uint32,
uint32, uint32, uint16, uint16,
FILE *, int, int);
static int combineSeparateTileSamples24bits (uint8 *[], uint8 *, uint32, uint32,
uint32, uint32, uint16, uint16,
FILE *, int, int);
static int combineSeparateTileSamples32bits (uint8 *[], uint8 *, uint32, uint32,
uint32, uint32, uint16, uint16,
FILE *, int, int);
static int combineSeparateTileSamplesBytes (unsigned char *[], unsigned char *,
uint32, uint32, uint32, uint32,
tsample_t, uint16, FILE *, int, int);
/* Dump functions for debugging */
static void dump_info (FILE *, int, char *, char *, ...);
static int dump_data (FILE *, int, char *, unsigned char *, uint32);
static int dump_byte (FILE *, int, char *, unsigned char);
static int dump_short (FILE *, int, char *, uint16);
static int dump_long (FILE *, int, char *, uint32);
static int dump_wide (FILE *, int, char *, uint64);
static int dump_buffer (FILE *, int, uint32, uint32, uint32, unsigned char *);
/* End function declarations */
/* Functions derived in whole or in part from tiffcp */
/* The following functions are taken largely intact from tiffcp */
static char* usage_info[] = {
"usage: tiffcrop [options] source1 ... sourceN destination",
"where options are:",
" -h Print this syntax listing",
" -v Print tiffcrop version identifier and last revision date",
" ",
" -a Append to output instead of overwriting",
" -d offset Set initial directory offset, counting first image as one, not zero",
" -p contig Pack samples contiguously (e.g. RGBRGB...)",
" -p separate Store samples separately (e.g. RRR...GGG...BBB...)",
" -s Write output in strips",
" -t Write output in tiles",
" -i Ignore read errors",
" ",
" -r # Make each strip have no more than # rows",
" -w # Set output tile width (pixels)",
" -l # Set output tile length (pixels)",
" ",
" -f lsb2msb Force lsb-to-msb FillOrder for output",
" -f msb2lsb Force msb-to-lsb FillOrder for output",
"",
" -c lzw[:opts] Compress output with Lempel-Ziv & Welch encoding",
" -c zip[:opts] Compress output with deflate encoding",
" -c jpeg[:opts] Compress output with JPEG encoding",
" -c packbits Compress output with packbits encoding",
" -c g3[:opts] Compress output with CCITT Group 3 encoding",
" -c g4 Compress output with CCITT Group 4 encoding",
" -c none Use no compression algorithm on output",
" ",
"Group 3 options:",
" 1d Use default CCITT Group 3 1D-encoding",
" 2d Use optional CCITT Group 3 2D-encoding",
" fill Byte-align EOL codes",
"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
" ",
"JPEG options:",
" # Set compression quality level (0-100, default 100)",
" raw Output color image as raw YCbCr",
" rgb Output color image as RGB",
"For example, -c jpeg:rgb:50 to get JPEG-encoded RGB data with 50% comp. quality",
" ",
"LZW and deflate options:",
" # Set predictor value",
"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
" ",
"Page and selection options:",
" -N odd|even|#,#-#,#|last sequences and ranges of images within file to process",
" The words odd or even may be used to specify all odd or even numbered images.",
" The word last may be used in place of a number in the sequence to indicate.",
" The final image in the file without knowing how many images there are.",
" Numbers are counted from one even though TIFF IFDs are counted from zero.",
" ",
" -E t|l|r|b edge to use as origin for width and length of crop region",
" -U units [in, cm, px ] inches, centimeters or pixels",
" ",
" -m #,#,#,# margins from edges for selection: top, left, bottom, right separated by commas",
" -X # horizontal dimension of region to extract expressed in current units",
" -Y # vertical dimension of region to extract expressed in current units",
" -Z #:#,#:# zones of the image designated as position X of Y,",
" eg 1:3 would be first of three equal portions measured from reference edge",
" -z x1,y1,x2,y2:...:xN,yN,xN+1,yN+1",
" regions of the image designated by upper left and lower right coordinates",
"",
"Export grouping options:",
" -e c|d|i|m|s export mode for images and selections from input images.",
" When exporting a composite image from multiple zones or regions",
" (combined and image modes), the selections must have equal sizes",
" for the axis perpendicular to the edge specified with -E.",
" c|combined All images and selections are written to a single file (default).",
" with multiple selections from one image combined into a single image.",
" d|divided All images and selections are written to a single file",
" with each selection from one image written to a new image.",
" i|image Each input image is written to a new file (numeric filename sequence)",
" with multiple selections from the image combined into one image.",
" m|multiple Each input image is written to a new file (numeric filename sequence)",
" with each selection from the image written to a new image.",
" s|separated Individual selections from each image are written to separate files.",
"",
"Output options:",
" -H # Set horizontal resolution of output images to #",
" -V # Set vertical resolution of output images to #",
" -J # Set horizontal margin of output page to # expressed in current units",
" when sectioning image into columns x rows using the -S cols:rows option",
" -K # Set verticalal margin of output page to # expressed in current units",
" when sectioning image into columns x rows using the -S cols:rows option",
" ",
" -O orient orientation for output image, portrait, landscape, auto",
" -P page page size for output image segments, eg letter, legal, tabloid, etc",
" use #.#x#.# to specify a custom page size in the currently defined units",
" where #.# represents the width and length",
" -S cols:rows Divide the image into equal sized segments using cols across and rows down.",
" ",
" -F hor|vert|both",
" flip (mirror) image or region horizontally, vertically, or both",
" -R # [90,180,or 270] degrees clockwise rotation of image or extracted region",
" -I [black|white|data|both]",
" invert color space, eg dark to light for bilevel and grayscale images",
" If argument is white or black, set the PHOTOMETRIC_INTERPRETATION ",
" tag to MinIsBlack or MinIsWhite without altering the image data",
" If the argument is data or both, the image data are modified:",
" both inverts the data and the PHOTOMETRIC_INTERPRETATION tag,",
" data inverts the data but not the PHOTOMETRIC_INTERPRETATION tag",
" ",
"-D opt1:value1,opt2:value2,opt3:value3:opt4:value4",
" Debug/dump program progress and/or data to non-TIFF files.",
" Options include the following and must be joined as a comma",
" separate list. The use of this option is generally limited to",
" program debugging and development of future options.",
" ",
" debug:N Display limited program progress indicators where larger N",
" increase the level of detail. Note: Tiffcrop may be compiled with",
" -DDEVELMODE to enable additional very low level debug reporting.",
"",
" Format:txt|raw Format any logged data as ASCII text or raw binary ",
" values. ASCII text dumps include strings of ones and zeroes",
" representing the binary values in the image data plus identifying headers.",
" ",
" level:N Specify the level of detail presented in the dump files.",
" This can vary from dumps of the entire input or output image data to dumps",
" of data processed by specific functions. Current range of levels is 1 to 3.",
" ",
" input:full-path-to-directory/input-dumpname",
" ",
" output:full-path-to-directory/output-dumpnaem",
" ",
" When dump files are being written, each image will be written to a separate",
" file with the name built by adding a numeric sequence value to the dumpname",
" and an extension of .txt for ASCII dumps or .bin for binary dumps.",
" ",
" The four debug/dump options are independent, though it makes little sense to",
" specify a dump file without specifying a detail level.",
" ",
NULL
};
/* This function could be modified to pass starting sample offset
* and number of samples as args to select fewer than spp
* from input image. These would then be passed to individual
* extractContigSampleXX routines.
*/
static int readContigTilesIntoBuffer (TIFF* in, uint8* buf,
uint32 imagelength,
uint32 imagewidth,
uint32 tw, uint32 tl,
tsample_t spp, uint16 bps)
{
int status = 1;
tsample_t sample = 0;
tsample_t count = spp;
uint32 row, col, trow;
uint32 nrow, ncol;
uint32 dst_rowsize, shift_width;
uint32 bytes_per_sample, bytes_per_pixel;
uint32 trailing_bits, prev_trailing_bits;
uint32 tile_rowsize = TIFFTileRowSize(in);
uint32 src_offset, dst_offset;
uint32 row_offset, col_offset;
uint8 *bufp = (uint8*) buf;
unsigned char *src = NULL;
unsigned char *dst = NULL;
tsize_t tbytes = 0, tile_buffsize = 0;
tsize_t tilesize = TIFFTileSize(in);
unsigned char *tilebuf = NULL;
bytes_per_sample = (bps + 7) / 8;
bytes_per_pixel = ((bps * spp) + 7) / 8;
if ((bps % 8) == 0)
shift_width = 0;
else
{
if (bytes_per_pixel < (bytes_per_sample + 1))
shift_width = bytes_per_pixel;
else
shift_width = bytes_per_sample + 1;
}
tile_buffsize = tilesize;
if (tilesize == 0 || tile_rowsize == 0)
{
TIFFError("readContigTilesIntoBuffer", "Tile size or tile rowsize is zero");
exit(-1);
}
if (tilesize < (tsize_t)(tl * tile_rowsize))
{
#ifdef DEBUG2
TIFFError("readContigTilesIntoBuffer",
"Tilesize %lu is too small, using alternate calculation %u",
tilesize, tl * tile_rowsize);
#endif
tile_buffsize = tl * tile_rowsize;
if (tl != (tile_buffsize / tile_rowsize))
{
TIFFError("readContigTilesIntoBuffer", "Integer overflow when calculating buffer size.");
exit(-1);
}
}
tilebuf = _TIFFmalloc(tile_buffsize);
if (tilebuf == 0)
return 0;
dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
for (row = 0; row < imagelength; row += tl)
{
nrow = (row + tl > imagelength) ? imagelength - row : tl;
for (col = 0; col < imagewidth; col += tw)
{
tbytes = TIFFReadTile(in, tilebuf, col, row, 0, 0);
if (tbytes < tilesize && !ignore)
{
TIFFError(TIFFFileName(in),
"Error, can't read tile at row %lu col %lu, Read %lu bytes of %lu",
(unsigned long) col, (unsigned long) row, (unsigned long)tbytes,
(unsigned long)tilesize);
status = 0;
_TIFFfree(tilebuf);
return status;
}
row_offset = row * dst_rowsize;
col_offset = ((col * bps * spp) + 7)/ 8;
bufp = buf + row_offset + col_offset;
if (col + tw > imagewidth)
ncol = imagewidth - col;
else
ncol = tw;
/* Each tile scanline will start on a byte boundary but it
* has to be merged into the scanline for the entire
* image buffer and the previous segment may not have
* ended on a byte boundary
*/
/* Optimization for common bit depths, all samples */
if (((bps % 8) == 0) && (count == spp))
{
for (trow = 0; trow < nrow; trow++)
{
src_offset = trow * tile_rowsize;
_TIFFmemcpy (bufp, tilebuf + src_offset, (ncol * spp * bps) / 8);
bufp += (imagewidth * bps * spp) / 8;
}
}
else
{
/* Bit depths not a multiple of 8 and/or extract fewer than spp samples */
prev_trailing_bits = trailing_bits = 0;
trailing_bits = (ncol * bps * spp) % 8;
/* for (trow = 0; tl < nrow; trow++) */
for (trow = 0; trow < nrow; trow++)
{
src_offset = trow * tile_rowsize;
src = tilebuf + src_offset;
dst_offset = (row + trow) * dst_rowsize;
dst = buf + dst_offset + col_offset;
switch (shift_width)
{
case 0: if (extractContigSamplesBytes (src, dst, ncol, sample,
spp, bps, count, 0, ncol))
{
TIFFError("readContigTilesIntoBuffer",
"Unable to extract row %d from tile %lu",
row, (unsigned long)TIFFCurrentTile(in));
return 1;
}
break;
case 1: if (bps == 1)
{
if (extractContigSamplesShifted8bits (src, dst, ncol,
sample, spp,
bps, count,
0, ncol,
prev_trailing_bits))
{
TIFFError("readContigTilesIntoBuffer",
"Unable to extract row %d from tile %lu",
row, (unsigned long)TIFFCurrentTile(in));
return 1;
}
break;
}
else
if (extractContigSamplesShifted16bits (src, dst, ncol,
sample, spp,
bps, count,
0, ncol,
prev_trailing_bits))
{
TIFFError("readContigTilesIntoBuffer",
"Unable to extract row %d from tile %lu",
row, (unsigned long)TIFFCurrentTile(in));
return 1;
}
break;
case 2: if (extractContigSamplesShifted24bits (src, dst, ncol,
sample, spp,
bps, count,
0, ncol,
prev_trailing_bits))
{
TIFFError("readContigTilesIntoBuffer",
"Unable to extract row %d from tile %lu",
row, (unsigned long)TIFFCurrentTile(in));
return 1;
}
break;
case 3:
case 4:
case 5: if (extractContigSamplesShifted32bits (src, dst, ncol,
sample, spp,
bps, count,
0, ncol,
prev_trailing_bits))
{
TIFFError("readContigTilesIntoBuffer",
"Unable to extract row %d from tile %lu",
row, (unsigned long)TIFFCurrentTile(in));
return 1;
}
break;
default: TIFFError("readContigTilesIntoBuffer", "Unsupported bit depth %d", bps);
return 1;
}
}
prev_trailing_bits += trailing_bits;
if (prev_trailing_bits > 7)
prev_trailing_bits-= 8;
}
}
}
_TIFFfree(tilebuf);
return status;
}
static int readSeparateTilesIntoBuffer (TIFF* in, uint8 *obuf,
uint32 imagelength, uint32 imagewidth,
uint32 tw, uint32 tl,
uint16 spp, uint16 bps)
{
int i, status = 1, sample;
int shift_width, bytes_per_pixel;
uint16 bytes_per_sample;
uint32 row, col; /* Current row and col of image */
uint32 nrow, ncol; /* Number of rows and cols in current tile */
uint32 row_offset, col_offset; /* Output buffer offsets */
tsize_t tbytes = 0, tilesize = TIFFTileSize(in);
tsample_t s;
uint8* bufp = (uint8*)obuf;
unsigned char *srcbuffs[MAX_SAMPLES];
unsigned char *tbuff = NULL;
bytes_per_sample = (bps + 7) / 8;
for (sample = 0; (sample < spp) && (sample < MAX_SAMPLES); sample++)
{
srcbuffs[sample] = NULL;
tbuff = (unsigned char *)_TIFFmalloc(tilesize + 8);
if (!tbuff)
{
TIFFError ("readSeparateTilesIntoBuffer",
"Unable to allocate tile read buffer for sample %d", sample);
for (i = 0; i < sample; i++)
_TIFFfree (srcbuffs[i]);
return 0;
}
srcbuffs[sample] = tbuff;
}
/* Each tile contains only the data for a single plane
* arranged in scanlines of tw * bytes_per_sample bytes.
*/
for (row = 0; row < imagelength; row += tl)
{
nrow = (row + tl > imagelength) ? imagelength - row : tl;
for (col = 0; col < imagewidth; col += tw)
{
for (s = 0; s < spp; s++)
{ /* Read each plane of a tile set into srcbuffs[s] */
tbytes = TIFFReadTile(in, srcbuffs[s], col, row, 0, s);
if (tbytes < 0 && !ignore)