1141cc406Sopenharmony_ci/* Create SANE/tiff headers TIFF interfacing routines for SANE 2141cc406Sopenharmony_ci Copyright (C) 2000 Peter Kirchgessner 3141cc406Sopenharmony_ci Copyright (C) 2002 Oliver Rauch: added tiff ICC profile 4141cc406Sopenharmony_ci Copyright (C) 2017 Aaron Muir Hamilton <aaron@correspondwith.me> 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 7141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 8141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 9141cc406Sopenharmony_ci License, or (at your option) any later version. 10141cc406Sopenharmony_ci 11141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 12141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 13141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14141cc406Sopenharmony_ci General Public License for more details. 15141cc406Sopenharmony_ci 16141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 17141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 18141cc406Sopenharmony_ci*/ 19141cc406Sopenharmony_ci 20141cc406Sopenharmony_ci/* Changes: 21141cc406Sopenharmony_ci 2000-11-19, PK: Color TIFF-header: write 3 values for bits per sample 22141cc406Sopenharmony_ci 2001-12-16, PK: Write fill order tag for b/w-images 23141cc406Sopenharmony_ci 2002-08-27, OR: Added tiff tag for ICC profile 24141cc406Sopenharmony_ci 2017-04-16, AMH: Separate ICC profile loading into a separate file 25141cc406Sopenharmony_ci*/ 26141cc406Sopenharmony_ci#ifdef _AIX 27141cc406Sopenharmony_ci# include "../include/lalloca.h" /* MUST come first for AIX! */ 28141cc406Sopenharmony_ci#endif 29141cc406Sopenharmony_ci 30141cc406Sopenharmony_ci#include <stdlib.h> 31141cc406Sopenharmony_ci#include <stdio.h> 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci#include "../include/sane/config.h" 34141cc406Sopenharmony_ci#include "../include/sane/sane.h" 35141cc406Sopenharmony_ci 36141cc406Sopenharmony_ci#include "sicc.h" 37141cc406Sopenharmony_ci#include "stiff.h" 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_citypedef struct { 40141cc406Sopenharmony_ci int tag, typ, nvals, val; 41141cc406Sopenharmony_ci} IFD_ENTRY; 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_citypedef struct { 45141cc406Sopenharmony_ci int maxtags; 46141cc406Sopenharmony_ci int ntags; 47141cc406Sopenharmony_ci IFD_ENTRY *ifde; 48141cc406Sopenharmony_ci} IFD; 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_ci#define IFDE_TYP_BYTE (1) 51141cc406Sopenharmony_ci#define IFDE_TYP_ASCII (2) 52141cc406Sopenharmony_ci#define IFDE_TYP_SHORT (3) 53141cc406Sopenharmony_ci#define IFDE_TYP_LONG (4) 54141cc406Sopenharmony_ci#define IFDE_TYP_RATIONAL (5) 55141cc406Sopenharmony_ci 56141cc406Sopenharmony_cistatic IFD * 57141cc406Sopenharmony_cicreate_ifd (void) 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci{ IFD *ifd; 60141cc406Sopenharmony_ci int maxtags = 10; 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci ifd = (IFD *)malloc (sizeof (IFD)); 63141cc406Sopenharmony_ci if (ifd == NULL) return NULL; 64141cc406Sopenharmony_ci 65141cc406Sopenharmony_ci ifd->ifde = (IFD_ENTRY *)malloc (maxtags * sizeof (IFD_ENTRY)); 66141cc406Sopenharmony_ci if (ifd->ifde == NULL) 67141cc406Sopenharmony_ci { 68141cc406Sopenharmony_ci free (ifd); 69141cc406Sopenharmony_ci return NULL; 70141cc406Sopenharmony_ci } 71141cc406Sopenharmony_ci ifd->ntags = 0; 72141cc406Sopenharmony_ci ifd->maxtags = maxtags; 73141cc406Sopenharmony_ci 74141cc406Sopenharmony_ci return ifd; 75141cc406Sopenharmony_ci} 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_cistatic void 78141cc406Sopenharmony_cifree_ifd (IFD *ifd) 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci{ 81141cc406Sopenharmony_ci if (ifd == NULL) return; 82141cc406Sopenharmony_ci if (ifd->ifde != NULL) 83141cc406Sopenharmony_ci { 84141cc406Sopenharmony_ci free (ifd->ifde); 85141cc406Sopenharmony_ci ifd->ifde = NULL; 86141cc406Sopenharmony_ci } 87141cc406Sopenharmony_ci free (ifd); 88141cc406Sopenharmony_ci ifd = NULL; 89141cc406Sopenharmony_ci} 90141cc406Sopenharmony_ci 91141cc406Sopenharmony_cistatic void 92141cc406Sopenharmony_ciadd_ifd_entry (IFD *ifd, int tag, int typ, int nvals, int val) 93141cc406Sopenharmony_ci 94141cc406Sopenharmony_ci{ IFD_ENTRY *ifde; 95141cc406Sopenharmony_ci int add_entries = 10; 96141cc406Sopenharmony_ci 97141cc406Sopenharmony_ci if (ifd == NULL) return; 98141cc406Sopenharmony_ci if (ifd->ntags == ifd->maxtags) 99141cc406Sopenharmony_ci { 100141cc406Sopenharmony_ci ifde = (IFD_ENTRY *)realloc (ifd->ifde, 101141cc406Sopenharmony_ci (ifd->maxtags+add_entries)*sizeof (IFD_ENTRY)); 102141cc406Sopenharmony_ci if (ifde == NULL) return; 103141cc406Sopenharmony_ci ifd->ifde = ifde; 104141cc406Sopenharmony_ci ifd->maxtags += add_entries; 105141cc406Sopenharmony_ci } 106141cc406Sopenharmony_ci ifde = &(ifd->ifde[ifd->ntags]); 107141cc406Sopenharmony_ci ifde->tag = tag; 108141cc406Sopenharmony_ci ifde->typ = typ; 109141cc406Sopenharmony_ci ifde->nvals = nvals; 110141cc406Sopenharmony_ci ifde->val = val; 111141cc406Sopenharmony_ci (ifd->ntags)++; 112141cc406Sopenharmony_ci} 113141cc406Sopenharmony_ci 114141cc406Sopenharmony_cistatic void 115141cc406Sopenharmony_ciwrite_i2 (FILE *fptr, int val, int motorola) 116141cc406Sopenharmony_ci{ 117141cc406Sopenharmony_ci if (motorola) 118141cc406Sopenharmony_ci { 119141cc406Sopenharmony_ci putc ((val >> 8) & 0xff, fptr); 120141cc406Sopenharmony_ci putc (val & 0xff, fptr); 121141cc406Sopenharmony_ci } 122141cc406Sopenharmony_ci else 123141cc406Sopenharmony_ci { 124141cc406Sopenharmony_ci putc (val & 0xff, fptr); 125141cc406Sopenharmony_ci putc ((val >> 8) & 0xff, fptr); 126141cc406Sopenharmony_ci } 127141cc406Sopenharmony_ci} 128141cc406Sopenharmony_ci 129141cc406Sopenharmony_ci 130141cc406Sopenharmony_cistatic void 131141cc406Sopenharmony_ciwrite_i4 (FILE *fptr, int val, int motorola) 132141cc406Sopenharmony_ci{ 133141cc406Sopenharmony_ci if (motorola) 134141cc406Sopenharmony_ci { 135141cc406Sopenharmony_ci putc ((val >> 24) & 0xff, fptr); 136141cc406Sopenharmony_ci putc ((val >> 16) & 0xff, fptr); 137141cc406Sopenharmony_ci putc ((val >> 8) & 0xff, fptr); 138141cc406Sopenharmony_ci putc (val & 0xff, fptr); 139141cc406Sopenharmony_ci } 140141cc406Sopenharmony_ci else 141141cc406Sopenharmony_ci { 142141cc406Sopenharmony_ci putc (val & 0xff, fptr); 143141cc406Sopenharmony_ci putc ((val >> 8) & 0xff, fptr); 144141cc406Sopenharmony_ci putc ((val >> 16) & 0xff, fptr); 145141cc406Sopenharmony_ci putc ((val >> 24) & 0xff, fptr); 146141cc406Sopenharmony_ci } 147141cc406Sopenharmony_ci} 148141cc406Sopenharmony_ci 149141cc406Sopenharmony_cistatic void 150141cc406Sopenharmony_ciwrite_ifd (FILE *fptr, IFD *ifd, int motorola) 151141cc406Sopenharmony_ci{int k; 152141cc406Sopenharmony_ci IFD_ENTRY *ifde; 153141cc406Sopenharmony_ci 154141cc406Sopenharmony_ci if (!ifd) return; 155141cc406Sopenharmony_ci 156141cc406Sopenharmony_ci if (motorola) putc ('M', fptr), putc ('M', fptr); 157141cc406Sopenharmony_ci else putc ('I', fptr), putc ('I', fptr); 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci write_i2 (fptr, 42, motorola); /* Magic */ 160141cc406Sopenharmony_ci write_i4 (fptr, 8, motorola); /* Offset to first IFD */ 161141cc406Sopenharmony_ci write_i2 (fptr, ifd->ntags, motorola); 162141cc406Sopenharmony_ci 163141cc406Sopenharmony_ci for (k = 0; k < ifd->ntags; k++) 164141cc406Sopenharmony_ci { 165141cc406Sopenharmony_ci ifde = &(ifd->ifde[k]); 166141cc406Sopenharmony_ci write_i2 (fptr, ifde->tag, motorola); 167141cc406Sopenharmony_ci write_i2 (fptr, ifde->typ, motorola); 168141cc406Sopenharmony_ci write_i4 (fptr, ifde->nvals, motorola); 169141cc406Sopenharmony_ci if ((ifde->typ == IFDE_TYP_SHORT) && (ifde->nvals == 1)) 170141cc406Sopenharmony_ci { 171141cc406Sopenharmony_ci write_i2 (fptr, ifde->val, motorola); 172141cc406Sopenharmony_ci write_i2 (fptr, 0, motorola); 173141cc406Sopenharmony_ci } 174141cc406Sopenharmony_ci else 175141cc406Sopenharmony_ci { 176141cc406Sopenharmony_ci write_i4 (fptr, ifde->val, motorola); 177141cc406Sopenharmony_ci } 178141cc406Sopenharmony_ci } 179141cc406Sopenharmony_ci write_i4 (fptr, 0, motorola); /* End of IFD chain */ 180141cc406Sopenharmony_ci} 181141cc406Sopenharmony_ci 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_cistatic void 184141cc406Sopenharmony_ciwrite_tiff_bw_header (FILE *fptr, int width, int height, int resolution) 185141cc406Sopenharmony_ci{IFD *ifd; 186141cc406Sopenharmony_ci int header_size = 8, ifd_size; 187141cc406Sopenharmony_ci int strip_offset, data_offset, data_size; 188141cc406Sopenharmony_ci int strip_bytecount; 189141cc406Sopenharmony_ci int ntags; 190141cc406Sopenharmony_ci int motorola; 191141cc406Sopenharmony_ci 192141cc406Sopenharmony_ci ifd = create_ifd (); 193141cc406Sopenharmony_ci 194141cc406Sopenharmony_ci strip_bytecount = ((width+7)/8) * height; 195141cc406Sopenharmony_ci 196141cc406Sopenharmony_ci /* the following values must be known in advance */ 197141cc406Sopenharmony_ci ntags = 12; 198141cc406Sopenharmony_ci data_size = 0; 199141cc406Sopenharmony_ci if (resolution > 0) 200141cc406Sopenharmony_ci { 201141cc406Sopenharmony_ci ntags += 3; 202141cc406Sopenharmony_ci data_size += 2*4 + 2*4; 203141cc406Sopenharmony_ci } 204141cc406Sopenharmony_ci 205141cc406Sopenharmony_ci ifd_size = 2 + ntags*12 + 4; 206141cc406Sopenharmony_ci data_offset = header_size + ifd_size; 207141cc406Sopenharmony_ci strip_offset = data_offset + data_size; 208141cc406Sopenharmony_ci 209141cc406Sopenharmony_ci /* New subfile type */ 210141cc406Sopenharmony_ci add_ifd_entry (ifd, 254, IFDE_TYP_LONG, 1, 0); 211141cc406Sopenharmony_ci /* image width */ 212141cc406Sopenharmony_ci add_ifd_entry (ifd, 256, (width > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT, 213141cc406Sopenharmony_ci 1, width); 214141cc406Sopenharmony_ci /* image length */ 215141cc406Sopenharmony_ci add_ifd_entry (ifd, 257, (height > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT, 216141cc406Sopenharmony_ci 1, height); 217141cc406Sopenharmony_ci /* bits per sample */ 218141cc406Sopenharmony_ci add_ifd_entry (ifd, 258, IFDE_TYP_SHORT, 1, 1); 219141cc406Sopenharmony_ci /* compression (uncompressed) */ 220141cc406Sopenharmony_ci add_ifd_entry (ifd, 259, IFDE_TYP_SHORT, 1, 1); 221141cc406Sopenharmony_ci /* photometric interpretation */ 222141cc406Sopenharmony_ci add_ifd_entry (ifd, 262, IFDE_TYP_SHORT, 1, 0); 223141cc406Sopenharmony_ci /* fill order */ 224141cc406Sopenharmony_ci add_ifd_entry (ifd, 266, IFDE_TYP_SHORT, 1, 1); 225141cc406Sopenharmony_ci /* strip offset */ 226141cc406Sopenharmony_ci add_ifd_entry (ifd, 273, IFDE_TYP_LONG, 1, strip_offset); 227141cc406Sopenharmony_ci /* orientation */ 228141cc406Sopenharmony_ci add_ifd_entry (ifd, 274, IFDE_TYP_SHORT, 1, 1); 229141cc406Sopenharmony_ci /* samples per pixel */ 230141cc406Sopenharmony_ci add_ifd_entry (ifd, 277, IFDE_TYP_SHORT, 1, 1); 231141cc406Sopenharmony_ci /* rows per strip */ 232141cc406Sopenharmony_ci add_ifd_entry (ifd, 278, IFDE_TYP_LONG, 1, height); 233141cc406Sopenharmony_ci /* strip bytecount */ 234141cc406Sopenharmony_ci add_ifd_entry (ifd, 279, IFDE_TYP_LONG, 1, strip_bytecount); 235141cc406Sopenharmony_ci if (resolution > 0) 236141cc406Sopenharmony_ci { 237141cc406Sopenharmony_ci /* x resolution */ 238141cc406Sopenharmony_ci add_ifd_entry (ifd, 282, IFDE_TYP_RATIONAL, 1, data_offset); 239141cc406Sopenharmony_ci data_offset += 2*4; 240141cc406Sopenharmony_ci /* y resolution */ 241141cc406Sopenharmony_ci add_ifd_entry (ifd, 283, IFDE_TYP_RATIONAL, 1, data_offset); 242141cc406Sopenharmony_ci data_offset += 2*4; 243141cc406Sopenharmony_ci } 244141cc406Sopenharmony_ci if (resolution > 0) 245141cc406Sopenharmony_ci { 246141cc406Sopenharmony_ci /* resolution unit (dpi) */ 247141cc406Sopenharmony_ci add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2); 248141cc406Sopenharmony_ci } 249141cc406Sopenharmony_ci 250141cc406Sopenharmony_ci /* I prefer motorola format. Its human readable. */ 251141cc406Sopenharmony_ci motorola = 1; 252141cc406Sopenharmony_ci write_ifd (fptr, ifd, motorola); 253141cc406Sopenharmony_ci 254141cc406Sopenharmony_ci /* Write x/y resolution */ 255141cc406Sopenharmony_ci if (resolution > 0) 256141cc406Sopenharmony_ci { 257141cc406Sopenharmony_ci write_i4 (fptr, resolution, motorola); 258141cc406Sopenharmony_ci write_i4 (fptr, 1, motorola); 259141cc406Sopenharmony_ci write_i4 (fptr, resolution, motorola); 260141cc406Sopenharmony_ci write_i4 (fptr, 1, motorola); 261141cc406Sopenharmony_ci } 262141cc406Sopenharmony_ci 263141cc406Sopenharmony_ci free_ifd (ifd); 264141cc406Sopenharmony_ci} 265141cc406Sopenharmony_ci 266141cc406Sopenharmony_cistatic void 267141cc406Sopenharmony_ciwrite_tiff_grey_header (FILE *fptr, int width, int height, int depth, 268141cc406Sopenharmony_ci int resolution, const char *icc_profile) 269141cc406Sopenharmony_ci{IFD *ifd; 270141cc406Sopenharmony_ci int header_size = 8, ifd_size; 271141cc406Sopenharmony_ci int strip_offset, data_offset, data_size; 272141cc406Sopenharmony_ci int strip_bytecount; 273141cc406Sopenharmony_ci int ntags; 274141cc406Sopenharmony_ci int motorola, bps, maxsamplevalue; 275141cc406Sopenharmony_ci void *icc_buffer = NULL; 276141cc406Sopenharmony_ci size_t icc_size = 0; 277141cc406Sopenharmony_ci 278141cc406Sopenharmony_ci if (icc_profile) 279141cc406Sopenharmony_ci { 280141cc406Sopenharmony_ci icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size); 281141cc406Sopenharmony_ci } 282141cc406Sopenharmony_ci 283141cc406Sopenharmony_ci ifd = create_ifd (); 284141cc406Sopenharmony_ci 285141cc406Sopenharmony_ci bps = (depth <= 8) ? 1 : 2; /* Bytes per sample */ 286141cc406Sopenharmony_ci maxsamplevalue = (depth <= 8) ? 255 : 65535; 287141cc406Sopenharmony_ci strip_bytecount = width * height * bps; 288141cc406Sopenharmony_ci 289141cc406Sopenharmony_ci /* the following values must be known in advance */ 290141cc406Sopenharmony_ci ntags = 13; 291141cc406Sopenharmony_ci data_size = 0; 292141cc406Sopenharmony_ci if (resolution > 0) 293141cc406Sopenharmony_ci { 294141cc406Sopenharmony_ci ntags += 3; 295141cc406Sopenharmony_ci data_size += 2*4 + 2*4; 296141cc406Sopenharmony_ci } 297141cc406Sopenharmony_ci 298141cc406Sopenharmony_ci if (icc_size > 0) /* if icc profile exists add memory for tag */ 299141cc406Sopenharmony_ci { 300141cc406Sopenharmony_ci ntags += 1; 301141cc406Sopenharmony_ci data_size += icc_size; 302141cc406Sopenharmony_ci } 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ci ifd_size = 2 + ntags*12 + 4; 305141cc406Sopenharmony_ci data_offset = header_size + ifd_size; 306141cc406Sopenharmony_ci strip_offset = data_offset + data_size; 307141cc406Sopenharmony_ci 308141cc406Sopenharmony_ci /* New subfile type */ 309141cc406Sopenharmony_ci add_ifd_entry (ifd, 254, IFDE_TYP_LONG, 1, 0); 310141cc406Sopenharmony_ci /* image width */ 311141cc406Sopenharmony_ci add_ifd_entry (ifd, 256, (width > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT, 312141cc406Sopenharmony_ci 1, width); 313141cc406Sopenharmony_ci /* image length */ 314141cc406Sopenharmony_ci add_ifd_entry (ifd, 257, (height > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT, 315141cc406Sopenharmony_ci 1, height); 316141cc406Sopenharmony_ci /* bits per sample */ 317141cc406Sopenharmony_ci add_ifd_entry (ifd, 258, IFDE_TYP_SHORT, 1, depth); 318141cc406Sopenharmony_ci /* compression (uncompressed) */ 319141cc406Sopenharmony_ci add_ifd_entry (ifd, 259, IFDE_TYP_SHORT, 1, 1); 320141cc406Sopenharmony_ci /* photometric interpretation */ 321141cc406Sopenharmony_ci add_ifd_entry (ifd, 262, IFDE_TYP_SHORT, 1, 1); 322141cc406Sopenharmony_ci /* strip offset */ 323141cc406Sopenharmony_ci add_ifd_entry (ifd, 273, IFDE_TYP_LONG, 1, strip_offset); 324141cc406Sopenharmony_ci /* orientation */ 325141cc406Sopenharmony_ci add_ifd_entry (ifd, 274, IFDE_TYP_SHORT, 1, 1); 326141cc406Sopenharmony_ci /* samples per pixel */ 327141cc406Sopenharmony_ci add_ifd_entry (ifd, 277, IFDE_TYP_SHORT, 1, 1); 328141cc406Sopenharmony_ci /* rows per strip */ 329141cc406Sopenharmony_ci add_ifd_entry (ifd, 278, IFDE_TYP_LONG, 1, height); 330141cc406Sopenharmony_ci /* strip bytecount */ 331141cc406Sopenharmony_ci add_ifd_entry (ifd, 279, IFDE_TYP_LONG, 1, strip_bytecount); 332141cc406Sopenharmony_ci /* min sample value */ 333141cc406Sopenharmony_ci add_ifd_entry (ifd, 280, IFDE_TYP_SHORT, 1, 0); 334141cc406Sopenharmony_ci /* max sample value */ 335141cc406Sopenharmony_ci add_ifd_entry (ifd, 281, IFDE_TYP_SHORT, 1, maxsamplevalue); 336141cc406Sopenharmony_ci if (resolution > 0) 337141cc406Sopenharmony_ci { 338141cc406Sopenharmony_ci /* x resolution */ 339141cc406Sopenharmony_ci add_ifd_entry (ifd, 282, IFDE_TYP_RATIONAL, 1, data_offset); 340141cc406Sopenharmony_ci data_offset += 2*4; 341141cc406Sopenharmony_ci /* y resolution */ 342141cc406Sopenharmony_ci add_ifd_entry (ifd, 283, IFDE_TYP_RATIONAL, 1, data_offset); 343141cc406Sopenharmony_ci data_offset += 2*4; 344141cc406Sopenharmony_ci } 345141cc406Sopenharmony_ci if (resolution > 0) 346141cc406Sopenharmony_ci { 347141cc406Sopenharmony_ci /* resolution unit (dpi) */ 348141cc406Sopenharmony_ci add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2); 349141cc406Sopenharmony_ci } 350141cc406Sopenharmony_ci 351141cc406Sopenharmony_ci if (icc_size > 0) /* add ICC-profile TAG */ 352141cc406Sopenharmony_ci { 353141cc406Sopenharmony_ci add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset); 354141cc406Sopenharmony_ci data_offset += icc_size; 355141cc406Sopenharmony_ci } 356141cc406Sopenharmony_ci 357141cc406Sopenharmony_ci /* I prefer motorola format. Its human readable. But for 16 bit, */ 358141cc406Sopenharmony_ci /* the image format is defined by SANE to be the native byte order */ 359141cc406Sopenharmony_ci if (bps == 1) 360141cc406Sopenharmony_ci { 361141cc406Sopenharmony_ci motorola = 1; 362141cc406Sopenharmony_ci } 363141cc406Sopenharmony_ci else 364141cc406Sopenharmony_ci {int check = 1; 365141cc406Sopenharmony_ci motorola = ((*((char *)&check)) == 0); 366141cc406Sopenharmony_ci } 367141cc406Sopenharmony_ci 368141cc406Sopenharmony_ci write_ifd (fptr, ifd, motorola); 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_ci /* Write x/y resolution */ 371141cc406Sopenharmony_ci if (resolution > 0) 372141cc406Sopenharmony_ci { 373141cc406Sopenharmony_ci write_i4 (fptr, resolution, motorola); 374141cc406Sopenharmony_ci write_i4 (fptr, 1, motorola); 375141cc406Sopenharmony_ci write_i4 (fptr, resolution, motorola); 376141cc406Sopenharmony_ci write_i4 (fptr, 1, motorola); 377141cc406Sopenharmony_ci } 378141cc406Sopenharmony_ci 379141cc406Sopenharmony_ci if (icc_size > 0) 380141cc406Sopenharmony_ci { 381141cc406Sopenharmony_ci fwrite(icc_buffer, icc_size, 1, fptr); 382141cc406Sopenharmony_ci } 383141cc406Sopenharmony_ci 384141cc406Sopenharmony_ci free(icc_buffer); 385141cc406Sopenharmony_ci 386141cc406Sopenharmony_ci free_ifd (ifd); 387141cc406Sopenharmony_ci} 388141cc406Sopenharmony_ci 389141cc406Sopenharmony_cistatic void 390141cc406Sopenharmony_ciwrite_tiff_color_header (FILE *fptr, int width, int height, int depth, 391141cc406Sopenharmony_ci int resolution, const char *icc_profile) 392141cc406Sopenharmony_ci{IFD *ifd; 393141cc406Sopenharmony_ci int header_size = 8, ifd_size; 394141cc406Sopenharmony_ci int strip_offset, data_offset, data_size; 395141cc406Sopenharmony_ci int strip_bytecount; 396141cc406Sopenharmony_ci int ntags; 397141cc406Sopenharmony_ci int motorola, bps, maxsamplevalue; 398141cc406Sopenharmony_ci void *icc_buffer = NULL; 399141cc406Sopenharmony_ci size_t icc_size = 0; 400141cc406Sopenharmony_ci 401141cc406Sopenharmony_ci if (icc_profile) 402141cc406Sopenharmony_ci { 403141cc406Sopenharmony_ci icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size); 404141cc406Sopenharmony_ci } 405141cc406Sopenharmony_ci 406141cc406Sopenharmony_ci 407141cc406Sopenharmony_ci ifd = create_ifd (); 408141cc406Sopenharmony_ci 409141cc406Sopenharmony_ci bps = (depth <= 8) ? 1 : 2; /* Bytes per sample */ 410141cc406Sopenharmony_ci maxsamplevalue = (depth <= 8) ? 255 : 65535; 411141cc406Sopenharmony_ci strip_bytecount = width * height * 3 * bps; 412141cc406Sopenharmony_ci 413141cc406Sopenharmony_ci /* the following values must be known in advance */ 414141cc406Sopenharmony_ci ntags = 13; 415141cc406Sopenharmony_ci data_size = 3*2 + 3*2 + 3*2; 416141cc406Sopenharmony_ci 417141cc406Sopenharmony_ci if (resolution > 0) 418141cc406Sopenharmony_ci { 419141cc406Sopenharmony_ci ntags += 3; 420141cc406Sopenharmony_ci data_size += 2*4 + 2*4; 421141cc406Sopenharmony_ci } 422141cc406Sopenharmony_ci 423141cc406Sopenharmony_ci if (icc_size > 0) /* if icc profile exists add memory for tag */ 424141cc406Sopenharmony_ci { 425141cc406Sopenharmony_ci ntags += 1; 426141cc406Sopenharmony_ci data_size += icc_size; 427141cc406Sopenharmony_ci } 428141cc406Sopenharmony_ci 429141cc406Sopenharmony_ci 430141cc406Sopenharmony_ci ifd_size = 2 + ntags*12 + 4; 431141cc406Sopenharmony_ci data_offset = header_size + ifd_size; 432141cc406Sopenharmony_ci strip_offset = data_offset + data_size; 433141cc406Sopenharmony_ci 434141cc406Sopenharmony_ci /* New subfile type */ 435141cc406Sopenharmony_ci add_ifd_entry (ifd, 254, IFDE_TYP_LONG, 1, 0); 436141cc406Sopenharmony_ci /* image width */ 437141cc406Sopenharmony_ci add_ifd_entry (ifd, 256, (width > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT, 438141cc406Sopenharmony_ci 1, width); 439141cc406Sopenharmony_ci /* image length */ 440141cc406Sopenharmony_ci add_ifd_entry (ifd, 257, (height > 0xffff) ? IFDE_TYP_LONG : IFDE_TYP_SHORT, 441141cc406Sopenharmony_ci 1, height); 442141cc406Sopenharmony_ci /* bits per sample */ 443141cc406Sopenharmony_ci add_ifd_entry (ifd, 258, IFDE_TYP_SHORT, 3, data_offset); 444141cc406Sopenharmony_ci data_offset += 3*2; 445141cc406Sopenharmony_ci /* compression (uncompressed) */ 446141cc406Sopenharmony_ci add_ifd_entry (ifd, 259, IFDE_TYP_SHORT, 1, 1); 447141cc406Sopenharmony_ci /* photometric interpretation */ 448141cc406Sopenharmony_ci add_ifd_entry (ifd, 262, IFDE_TYP_SHORT, 1, 2); 449141cc406Sopenharmony_ci /* strip offset */ 450141cc406Sopenharmony_ci add_ifd_entry (ifd, 273, IFDE_TYP_LONG, 1, strip_offset); 451141cc406Sopenharmony_ci /* orientation */ 452141cc406Sopenharmony_ci add_ifd_entry (ifd, 274, IFDE_TYP_SHORT, 1, 1); 453141cc406Sopenharmony_ci /* samples per pixel */ 454141cc406Sopenharmony_ci add_ifd_entry (ifd, 277, IFDE_TYP_SHORT, 1, 3); 455141cc406Sopenharmony_ci /* rows per strip */ 456141cc406Sopenharmony_ci add_ifd_entry (ifd, 278, IFDE_TYP_LONG, 1, height); 457141cc406Sopenharmony_ci /* strip bytecount */ 458141cc406Sopenharmony_ci add_ifd_entry (ifd, 279, IFDE_TYP_LONG, 1, strip_bytecount); 459141cc406Sopenharmony_ci /* min sample value */ 460141cc406Sopenharmony_ci add_ifd_entry (ifd, 280, IFDE_TYP_SHORT, 3, data_offset); 461141cc406Sopenharmony_ci data_offset += 3*2; 462141cc406Sopenharmony_ci /* max sample value */ 463141cc406Sopenharmony_ci add_ifd_entry (ifd, 281, IFDE_TYP_SHORT, 3, data_offset); 464141cc406Sopenharmony_ci data_offset += 3*2; 465141cc406Sopenharmony_ci 466141cc406Sopenharmony_ci if (resolution > 0) 467141cc406Sopenharmony_ci { 468141cc406Sopenharmony_ci /* x resolution */ 469141cc406Sopenharmony_ci add_ifd_entry (ifd, 282, IFDE_TYP_RATIONAL, 1, data_offset); 470141cc406Sopenharmony_ci data_offset += 2*4; 471141cc406Sopenharmony_ci /* y resolution */ 472141cc406Sopenharmony_ci add_ifd_entry (ifd, 283, IFDE_TYP_RATIONAL, 1, data_offset); 473141cc406Sopenharmony_ci data_offset += 2*4; 474141cc406Sopenharmony_ci } 475141cc406Sopenharmony_ci 476141cc406Sopenharmony_ci if (resolution > 0) 477141cc406Sopenharmony_ci { 478141cc406Sopenharmony_ci /* resolution unit (dpi) */ 479141cc406Sopenharmony_ci add_ifd_entry (ifd, 296, IFDE_TYP_SHORT, 1, 2); 480141cc406Sopenharmony_ci } 481141cc406Sopenharmony_ci 482141cc406Sopenharmony_ci if (icc_size > 0) /* add ICC-profile TAG */ 483141cc406Sopenharmony_ci { 484141cc406Sopenharmony_ci add_ifd_entry(ifd, 34675, 7, (int) icc_size, data_offset); 485141cc406Sopenharmony_ci data_offset += icc_size; 486141cc406Sopenharmony_ci } 487141cc406Sopenharmony_ci 488141cc406Sopenharmony_ci 489141cc406Sopenharmony_ci /* I prefer motorola format. Its human readable. But for 16 bit, */ 490141cc406Sopenharmony_ci /* the image format is defined by SANE to be the native byte order */ 491141cc406Sopenharmony_ci if (bps == 1) 492141cc406Sopenharmony_ci { 493141cc406Sopenharmony_ci motorola = 1; 494141cc406Sopenharmony_ci } 495141cc406Sopenharmony_ci else 496141cc406Sopenharmony_ci {int check = 1; 497141cc406Sopenharmony_ci motorola = ((*((char *)&check)) == 0); 498141cc406Sopenharmony_ci } 499141cc406Sopenharmony_ci 500141cc406Sopenharmony_ci write_ifd (fptr, ifd, motorola); 501141cc406Sopenharmony_ci 502141cc406Sopenharmony_ci /* Write bits per sample value values */ 503141cc406Sopenharmony_ci write_i2 (fptr, depth, motorola); 504141cc406Sopenharmony_ci write_i2 (fptr, depth, motorola); 505141cc406Sopenharmony_ci write_i2 (fptr, depth, motorola); 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_ci /* Write min sample value values */ 508141cc406Sopenharmony_ci write_i2 (fptr, 0, motorola); 509141cc406Sopenharmony_ci write_i2 (fptr, 0, motorola); 510141cc406Sopenharmony_ci write_i2 (fptr, 0, motorola); 511141cc406Sopenharmony_ci 512141cc406Sopenharmony_ci /* Write max sample value values */ 513141cc406Sopenharmony_ci write_i2 (fptr, maxsamplevalue, motorola); 514141cc406Sopenharmony_ci write_i2 (fptr, maxsamplevalue, motorola); 515141cc406Sopenharmony_ci write_i2 (fptr, maxsamplevalue, motorola); 516141cc406Sopenharmony_ci 517141cc406Sopenharmony_ci /* Write x/y resolution */ 518141cc406Sopenharmony_ci if (resolution > 0) 519141cc406Sopenharmony_ci { 520141cc406Sopenharmony_ci write_i4 (fptr, resolution, motorola); 521141cc406Sopenharmony_ci write_i4 (fptr, 1, motorola); 522141cc406Sopenharmony_ci write_i4 (fptr, resolution, motorola); 523141cc406Sopenharmony_ci write_i4 (fptr, 1, motorola); 524141cc406Sopenharmony_ci } 525141cc406Sopenharmony_ci 526141cc406Sopenharmony_ci /* Write ICC profile */ 527141cc406Sopenharmony_ci if (icc_size > 0) 528141cc406Sopenharmony_ci { 529141cc406Sopenharmony_ci fwrite(icc_buffer, icc_size, 1, fptr); 530141cc406Sopenharmony_ci } 531141cc406Sopenharmony_ci 532141cc406Sopenharmony_ci free(icc_buffer); 533141cc406Sopenharmony_ci 534141cc406Sopenharmony_ci free_ifd (ifd); 535141cc406Sopenharmony_ci} 536141cc406Sopenharmony_ci 537141cc406Sopenharmony_ci 538141cc406Sopenharmony_civoid 539141cc406Sopenharmony_cisanei_write_tiff_header (SANE_Frame format, int width, int height, int depth, 540141cc406Sopenharmony_ci int resolution, const char *icc_profile, FILE *ofp) 541141cc406Sopenharmony_ci{ 542141cc406Sopenharmony_ci#ifdef __EMX__ /* OS2 - write in binary mode. */ 543141cc406Sopenharmony_ci _fsetmode(ofp, "b"); 544141cc406Sopenharmony_ci#endif 545141cc406Sopenharmony_ci switch (format) 546141cc406Sopenharmony_ci { 547141cc406Sopenharmony_ci case SANE_FRAME_RED: 548141cc406Sopenharmony_ci case SANE_FRAME_GREEN: 549141cc406Sopenharmony_ci case SANE_FRAME_BLUE: 550141cc406Sopenharmony_ci case SANE_FRAME_RGB: 551141cc406Sopenharmony_ci write_tiff_color_header (ofp, width, height, depth, resolution, icc_profile); 552141cc406Sopenharmony_ci break; 553141cc406Sopenharmony_ci 554141cc406Sopenharmony_ci default: 555141cc406Sopenharmony_ci if (depth == 1) 556141cc406Sopenharmony_ci write_tiff_bw_header (ofp, width, height, resolution); 557141cc406Sopenharmony_ci else 558141cc406Sopenharmony_ci write_tiff_grey_header (ofp, width, height, depth, resolution, icc_profile); 559141cc406Sopenharmony_ci break; 560141cc406Sopenharmony_ci } 561141cc406Sopenharmony_ci} 562