xref: /third_party/backends/frontend/stiff.c (revision 141cc406)
1/* Create SANE/tiff headers TIFF interfacing routines for SANE
2   Copyright (C) 2000 Peter Kirchgessner
3   Copyright (C) 2002 Oliver Rauch: added tiff ICC profile
4   Copyright (C) 2017 Aaron Muir Hamilton <aaron@correspondwith.me>
5
6   This program is free software; you can redistribute it and/or
7   modify it under the terms of the GNU General Public License as
8   published by the Free Software Foundation; either version 2 of the
9   License, or (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <https://www.gnu.org/licenses/>.
18*/
19
20/* Changes:
21   2000-11-19, PK: Color TIFF-header: write 3 values for bits per sample
22   2001-12-16, PK: Write fill order tag for b/w-images
23   2002-08-27, OR: Added tiff tag for ICC profile
24   2017-04-16, AMH: Separate ICC profile loading into a separate file
25*/
26#ifdef _AIX
27# include "../include/lalloca.h"	/* MUST come first for AIX! */
28#endif
29
30#include <stdlib.h>
31#include <stdio.h>
32
33#include "../include/sane/config.h"
34#include "../include/sane/sane.h"
35
36#include "sicc.h"
37#include "stiff.h"
38
39typedef struct {
40    int tag, typ, nvals, val;
41} IFD_ENTRY;
42
43
44typedef struct {
45    int maxtags;
46    int ntags;
47    IFD_ENTRY *ifde;
48} IFD;
49
50#define IFDE_TYP_BYTE     (1)
51#define IFDE_TYP_ASCII    (2)
52#define IFDE_TYP_SHORT    (3)
53#define IFDE_TYP_LONG     (4)
54#define IFDE_TYP_RATIONAL (5)
55
56static IFD *
57create_ifd (void)
58
59{   IFD *ifd;
60    int maxtags = 10;
61
62    ifd = (IFD *)malloc (sizeof (IFD));
63    if (ifd == NULL) return NULL;
64
65    ifd->ifde = (IFD_ENTRY *)malloc (maxtags * sizeof (IFD_ENTRY));
66    if (ifd->ifde == NULL)
67    {
68        free (ifd);
69        return NULL;
70    }
71    ifd->ntags = 0;
72    ifd->maxtags = maxtags;
73
74    return ifd;
75}
76
77static void
78free_ifd (IFD *ifd)
79
80{
81    if (ifd == NULL) return;
82    if (ifd->ifde != NULL)
83    {
84        free (ifd->ifde);
85        ifd->ifde = NULL;
86    }
87    free (ifd);
88    ifd = NULL;
89}
90
91static void
92add_ifd_entry (IFD *ifd, int tag, int typ, int nvals, int val)
93
94{   IFD_ENTRY *ifde;
95    int add_entries = 10;
96
97    if (ifd == NULL) return;
98    if (ifd->ntags == ifd->maxtags)
99    {
100        ifde = (IFD_ENTRY *)realloc (ifd->ifde,
101                                     (ifd->maxtags+add_entries)*sizeof (IFD_ENTRY));
102        if (ifde == NULL) return;
103        ifd->ifde = ifde;
104        ifd->maxtags += add_entries;
105    }
106    ifde = &(ifd->ifde[ifd->ntags]);
107    ifde->tag = tag;
108    ifde->typ = typ;
109    ifde->nvals = nvals;
110    ifde->val = val;
111    (ifd->ntags)++;
112}
113
114static void
115write_i2 (FILE *fptr, int val, int motorola)
116{
117    if (motorola)
118    {
119        putc ((val >> 8) & 0xff, fptr);
120        putc (val & 0xff, fptr);
121    }
122    else
123    {
124        putc (val & 0xff, fptr);
125        putc ((val >> 8) & 0xff, fptr);
126    }
127}
128
129
130static void
131write_i4 (FILE *fptr, int val, int motorola)
132{
133    if (motorola)
134    {
135        putc ((val >> 24) & 0xff, fptr);
136        putc ((val >> 16) & 0xff, fptr);
137        putc ((val >> 8) & 0xff, fptr);
138        putc (val & 0xff, fptr);
139    }
140    else
141    {
142        putc (val & 0xff, fptr);
143        putc ((val >> 8) & 0xff, fptr);
144        putc ((val >> 16) & 0xff, fptr);
145        putc ((val >> 24) & 0xff, fptr);
146    }
147}
148
149static void
150write_ifd (FILE *fptr, IFD *ifd, int motorola)
151{int k;
152    IFD_ENTRY *ifde;
153
154    if (!ifd) return;
155
156    if (motorola) putc ('M', fptr), putc ('M', fptr);
157    else putc ('I', fptr), putc ('I', fptr);
158
159    write_i2 (fptr, 42, motorola);  /* Magic */
160    write_i4 (fptr, 8, motorola);   /* Offset to first IFD */
161    write_i2 (fptr, ifd->ntags, motorola);
162
163    for (k = 0; k < ifd->ntags; k++)
164    {
165        ifde = &(ifd->ifde[k]);
166        write_i2 (fptr, ifde->tag, motorola);
167        write_i2 (fptr, ifde->typ, motorola);
168        write_i4 (fptr, ifde->nvals, motorola);
169        if ((ifde->typ == IFDE_TYP_SHORT) && (ifde->nvals == 1))
170        {
171            write_i2 (fptr, ifde->val, motorola);
172            write_i2 (fptr, 0, motorola);
173        }
174        else
175        {
176            write_i4 (fptr, ifde->val, motorola);
177        }
178    }
179    write_i4 (fptr, 0, motorola); /* End of IFD chain */
180}
181
182
183static void
184write_tiff_bw_header (FILE *fptr, int width, int height, int resolution)
185{IFD *ifd;
186    int header_size = 8, ifd_size;
187    int strip_offset, data_offset, data_size;
188    int strip_bytecount;
189    int ntags;
190    int motorola;
191
192    ifd = create_ifd ();
193
194    strip_bytecount = ((width+7)/8) * height;
195
196    /* the following values must be known in advance */
197    ntags = 12;
198    data_size = 0;
199    if (resolution > 0)
200    {
201        ntags += 3;
202        data_size += 2*4 + 2*4;
203    }
204
205    ifd_size = 2 + ntags*12 + 4;
206    data_offset = header_size + ifd_size;
207    strip_offset = data_offset + data_size;
208
209    /* New subfile type */
210    add_ifd_entry (ifd, 254, IFDE_TYP_LONG, 1, 0);
211    /* image width */
212    add_ifd_entry (ifd, 256, (width > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT,
213                   1, width);
214    /* image length */
215    add_ifd_entry (ifd, 257, (height > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT,
216                   1, height);
217    /* bits per sample */
218    add_ifd_entry (ifd, 258, IFDE_TYP_SHORT, 1, 1);
219    /* compression (uncompressed) */
220    add_ifd_entry (ifd, 259, IFDE_TYP_SHORT, 1, 1);
221    /* photometric interpretation */
222    add_ifd_entry (ifd, 262, IFDE_TYP_SHORT, 1, 0);
223    /* fill order */
224    add_ifd_entry (ifd, 266, IFDE_TYP_SHORT, 1, 1);
225    /* strip offset */
226    add_ifd_entry (ifd, 273, IFDE_TYP_LONG, 1, strip_offset);
227    /* orientation */
228    add_ifd_entry (ifd, 274, IFDE_TYP_SHORT, 1, 1);
229    /* samples per pixel */
230    add_ifd_entry (ifd, 277, IFDE_TYP_SHORT, 1, 1);
231    /* rows per strip */
232    add_ifd_entry (ifd, 278, IFDE_TYP_LONG, 1, height);
233    /* strip bytecount */
234    add_ifd_entry (ifd, 279, IFDE_TYP_LONG, 1, strip_bytecount);
235    if (resolution > 0)
236    {
237        /* x resolution */
238        add_ifd_entry (ifd, 282, IFDE_TYP_RATIONAL, 1, data_offset);
239        data_offset += 2*4;
240        /* y resolution */
241        add_ifd_entry (ifd, 283, IFDE_TYP_RATIONAL, 1, data_offset);
242        data_offset += 2*4;
243    }
244    if (resolution > 0)
245    {
246        /* resolution unit (dpi) */
247        add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2);
248    }
249
250    /* I prefer motorola format. Its human readable. */
251    motorola = 1;
252    write_ifd (fptr, ifd, motorola);
253
254    /* Write x/y resolution */
255    if (resolution > 0)
256    {
257        write_i4 (fptr, resolution, motorola);
258        write_i4 (fptr, 1, motorola);
259        write_i4 (fptr, resolution, motorola);
260        write_i4 (fptr, 1, motorola);
261    }
262
263    free_ifd (ifd);
264}
265
266static void
267write_tiff_grey_header (FILE *fptr, int width, int height, int depth,
268                        int resolution, const char *icc_profile)
269{IFD *ifd;
270    int header_size = 8, ifd_size;
271    int strip_offset, data_offset, data_size;
272    int strip_bytecount;
273    int ntags;
274    int motorola, bps, maxsamplevalue;
275    void *icc_buffer = NULL;
276    size_t icc_size = 0;
277
278    if (icc_profile)
279    {
280      icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
281    }
282
283    ifd = create_ifd ();
284
285    bps = (depth <= 8) ? 1 : 2;  /* Bytes per sample */
286    maxsamplevalue = (depth <= 8) ? 255 : 65535;
287    strip_bytecount = width * height * bps;
288
289    /* the following values must be known in advance */
290    ntags = 13;
291    data_size = 0;
292    if (resolution > 0)
293    {
294        ntags += 3;
295        data_size += 2*4 + 2*4;
296    }
297
298    if (icc_size > 0) /* if icc profile exists add memory for tag */
299    {
300        ntags += 1;
301        data_size += icc_size;
302    }
303
304    ifd_size = 2 + ntags*12 + 4;
305    data_offset = header_size + ifd_size;
306    strip_offset = data_offset + data_size;
307
308    /* New subfile type */
309    add_ifd_entry (ifd, 254, IFDE_TYP_LONG, 1, 0);
310    /* image width */
311    add_ifd_entry (ifd, 256, (width > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT,
312                   1, width);
313    /* image length */
314    add_ifd_entry (ifd, 257, (height > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT,
315                   1, height);
316    /* bits per sample */
317    add_ifd_entry (ifd, 258, IFDE_TYP_SHORT, 1, depth);
318    /* compression (uncompressed) */
319    add_ifd_entry (ifd, 259, IFDE_TYP_SHORT, 1, 1);
320    /* photometric interpretation */
321    add_ifd_entry (ifd, 262, IFDE_TYP_SHORT, 1, 1);
322    /* strip offset */
323    add_ifd_entry (ifd, 273, IFDE_TYP_LONG, 1, strip_offset);
324    /* orientation */
325    add_ifd_entry (ifd, 274, IFDE_TYP_SHORT, 1, 1);
326    /* samples per pixel */
327    add_ifd_entry (ifd, 277, IFDE_TYP_SHORT, 1, 1);
328    /* rows per strip */
329    add_ifd_entry (ifd, 278, IFDE_TYP_LONG, 1, height);
330    /* strip bytecount */
331    add_ifd_entry (ifd, 279, IFDE_TYP_LONG, 1, strip_bytecount);
332    /* min sample value */
333    add_ifd_entry (ifd, 280, IFDE_TYP_SHORT, 1, 0);
334    /* max sample value */
335    add_ifd_entry (ifd, 281, IFDE_TYP_SHORT, 1, maxsamplevalue);
336    if (resolution > 0)
337    {
338        /* x resolution */
339        add_ifd_entry (ifd, 282, IFDE_TYP_RATIONAL, 1, data_offset);
340        data_offset += 2*4;
341        /* y resolution */
342        add_ifd_entry (ifd, 283, IFDE_TYP_RATIONAL, 1, data_offset);
343        data_offset += 2*4;
344    }
345    if (resolution > 0)
346    {
347        /* resolution unit (dpi) */
348        add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2);
349    }
350
351    if (icc_size > 0) /* add ICC-profile TAG */
352    {
353      add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset);
354      data_offset += icc_size;
355    }
356
357    /* I prefer motorola format. Its human readable. But for 16 bit, */
358    /* the image format is defined by SANE to be the native byte order */
359    if (bps == 1)
360    {
361        motorola = 1;
362    }
363    else
364    {int check = 1;
365        motorola = ((*((char *)&check)) == 0);
366    }
367
368    write_ifd (fptr, ifd, motorola);
369
370    /* Write x/y resolution */
371    if (resolution > 0)
372    {
373        write_i4 (fptr, resolution, motorola);
374        write_i4 (fptr, 1, motorola);
375        write_i4 (fptr, resolution, motorola);
376        write_i4 (fptr, 1, motorola);
377    }
378
379    if (icc_size > 0)
380    {
381      fwrite(icc_buffer, icc_size, 1, fptr);
382    }
383
384    free(icc_buffer);
385
386    free_ifd (ifd);
387}
388
389static void
390write_tiff_color_header (FILE *fptr, int width, int height, int depth,
391                         int resolution, const char *icc_profile)
392{IFD *ifd;
393    int header_size = 8, ifd_size;
394    int strip_offset, data_offset, data_size;
395    int strip_bytecount;
396    int ntags;
397    int motorola, bps, maxsamplevalue;
398    void *icc_buffer = NULL;
399    size_t icc_size = 0;
400
401    if (icc_profile)
402    {
403      icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
404    }
405
406
407    ifd = create_ifd ();
408
409    bps = (depth <= 8) ? 1 : 2;  /* Bytes per sample */
410    maxsamplevalue = (depth <= 8) ? 255 : 65535;
411    strip_bytecount = width * height * 3 * bps;
412
413    /* the following values must be known in advance */
414    ntags = 13;
415    data_size = 3*2 + 3*2 + 3*2;
416
417    if (resolution > 0)
418    {
419        ntags += 3;
420        data_size += 2*4 + 2*4;
421    }
422
423    if (icc_size > 0) /* if icc profile exists add memory for tag */
424    {
425        ntags += 1;
426        data_size += icc_size;
427    }
428
429
430    ifd_size = 2 + ntags*12 + 4;
431    data_offset = header_size + ifd_size;
432    strip_offset = data_offset + data_size;
433
434    /* New subfile type */
435    add_ifd_entry (ifd, 254, IFDE_TYP_LONG, 1, 0);
436    /* image width */
437    add_ifd_entry (ifd, 256, (width > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT,
438                   1, width);
439    /* image length */
440    add_ifd_entry (ifd, 257, (height > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT,
441                   1, height);
442    /* bits per sample */
443    add_ifd_entry (ifd, 258, IFDE_TYP_SHORT, 3, data_offset);
444    data_offset += 3*2;
445    /* compression (uncompressed) */
446    add_ifd_entry (ifd, 259, IFDE_TYP_SHORT, 1, 1);
447    /* photometric interpretation */
448    add_ifd_entry (ifd, 262, IFDE_TYP_SHORT, 1, 2);
449    /* strip offset */
450    add_ifd_entry (ifd, 273, IFDE_TYP_LONG, 1, strip_offset);
451    /* orientation */
452    add_ifd_entry (ifd, 274, IFDE_TYP_SHORT, 1, 1);
453    /* samples per pixel */
454    add_ifd_entry (ifd, 277, IFDE_TYP_SHORT, 1, 3);
455    /* rows per strip */
456    add_ifd_entry (ifd, 278, IFDE_TYP_LONG, 1, height);
457    /* strip bytecount */
458    add_ifd_entry (ifd, 279, IFDE_TYP_LONG, 1, strip_bytecount);
459    /* min sample value */
460    add_ifd_entry (ifd, 280, IFDE_TYP_SHORT, 3, data_offset);
461    data_offset += 3*2;
462    /* max sample value */
463    add_ifd_entry (ifd, 281, IFDE_TYP_SHORT, 3, data_offset);
464    data_offset += 3*2;
465
466    if (resolution > 0)
467    {
468        /* x resolution */
469        add_ifd_entry (ifd, 282, IFDE_TYP_RATIONAL, 1, data_offset);
470        data_offset += 2*4;
471        /* y resolution */
472        add_ifd_entry (ifd, 283, IFDE_TYP_RATIONAL, 1, data_offset);
473        data_offset += 2*4;
474    }
475
476    if (resolution > 0)
477    {
478        /* resolution unit (dpi) */
479        add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2);
480    }
481
482    if (icc_size > 0) /* add ICC-profile TAG */
483    {
484      add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset);
485      data_offset += icc_size;
486    }
487
488
489    /* I prefer motorola format. Its human readable. But for 16 bit, */
490    /* the image format is defined by SANE to be the native byte order */
491    if (bps == 1)
492    {
493        motorola = 1;
494    }
495    else
496    {int check = 1;
497        motorola = ((*((char *)&check)) == 0);
498    }
499
500    write_ifd (fptr, ifd, motorola);
501
502    /* Write bits per sample value values */
503    write_i2 (fptr, depth, motorola);
504    write_i2 (fptr, depth, motorola);
505    write_i2 (fptr, depth, motorola);
506
507    /* Write min sample value values */
508    write_i2 (fptr, 0, motorola);
509    write_i2 (fptr, 0, motorola);
510    write_i2 (fptr, 0, motorola);
511
512    /* Write max sample value values */
513    write_i2 (fptr, maxsamplevalue, motorola);
514    write_i2 (fptr, maxsamplevalue, motorola);
515    write_i2 (fptr, maxsamplevalue, motorola);
516
517    /* Write x/y resolution */
518    if (resolution > 0)
519    {
520        write_i4 (fptr, resolution, motorola);
521        write_i4 (fptr, 1, motorola);
522        write_i4 (fptr, resolution, motorola);
523        write_i4 (fptr, 1, motorola);
524    }
525
526    /* Write ICC profile */
527    if (icc_size > 0)
528    {
529      fwrite(icc_buffer, icc_size, 1, fptr);
530    }
531
532    free(icc_buffer);
533
534    free_ifd (ifd);
535}
536
537
538void
539sanei_write_tiff_header (SANE_Frame format, int width, int height, int depth,
540			 int resolution, const char *icc_profile, FILE *ofp)
541{
542#ifdef __EMX__	/* OS2 - write in binary mode. */
543    _fsetmode(ofp, "b");
544#endif
545    switch (format)
546    {
547    case SANE_FRAME_RED:
548    case SANE_FRAME_GREEN:
549    case SANE_FRAME_BLUE:
550    case SANE_FRAME_RGB:
551        write_tiff_color_header (ofp, width, height, depth, resolution, icc_profile);
552        break;
553
554    default:
555        if (depth == 1)
556            write_tiff_bw_header (ofp, width, height, resolution);
557        else
558            write_tiff_grey_header (ofp, width, height, depth, resolution, icc_profile);
559        break;
560    }
561}
562