| 1 | /*
|
|---|
| 2 |
|
|---|
| 3 | gbmtif.c - Microsoft/Aldus Tagged Image File Format support
|
|---|
| 4 |
|
|---|
| 5 | Reads and writes 1,4,8 and 24 bit colour files.
|
|---|
| 6 | Supports uncompressed, Packbits and LZW compressed files only.
|
|---|
| 7 | Input option: index=N (default is 0)
|
|---|
| 8 | Output options: artist=,software=,make=,model=,host=,documentname=,pagename=,
|
|---|
| 9 | imagedescription=,pal1bpp
|
|---|
| 10 |
|
|---|
| 11 | Added support to allow SamplePerPixel>=3 for RGB data (TIFF 6.0 new feature).
|
|---|
| 12 | Added rejection test of FillOrder!=1.
|
|---|
| 13 | Added rejection test of PlanarConfiguration!=1.
|
|---|
| 14 | Added support for CMYK images.
|
|---|
| 15 | Changed write of 1bpp data to Baseline black and white write.
|
|---|
| 16 | Added pal1bpp output option meaning don't force Baseline write of 1bpp data.
|
|---|
| 17 | Improved error messages substantially.
|
|---|
| 18 | Fixed Packbits compression.
|
|---|
| 19 | Added support for PlanarConfiguration==2 for RGB images only.
|
|---|
| 20 | Added Predictor==2 support for bps==8, spp=1 case.
|
|---|
| 21 | Added Predictor==2 support for bps==8, spp>=3 case.
|
|---|
| 22 | Removed Too Many Strips limitation.
|
|---|
| 23 | Faster LZW code.
|
|---|
| 24 | Fixes to LZW compressor (and #ifdef DEBUG debug code).
|
|---|
| 25 |
|
|---|
| 26 | */
|
|---|
| 27 |
|
|---|
| 28 | /*...sincludes:0:*/
|
|---|
| 29 | #include <stdio.h>
|
|---|
| 30 | #include <ctype.h>
|
|---|
| 31 | #include <stddef.h>
|
|---|
| 32 | #include <stdlib.h>
|
|---|
| 33 | #include <string.h>
|
|---|
| 34 | #include "gbm.h"
|
|---|
| 35 | #include "gbmhelp.h"
|
|---|
| 36 | #include "gbmtifh.h"
|
|---|
| 37 |
|
|---|
| 38 | /*...vgbm\46\h:0:*/
|
|---|
| 39 | /*...vgbmhelp\46\h:0:*/
|
|---|
| 40 | /*...vgbmtifh\46\h:0:*/
|
|---|
| 41 |
|
|---|
| 42 | #ifndef min
|
|---|
| 43 | #define min(a,b) (((a)<(b))?(a):(b))
|
|---|
| 44 | #endif
|
|---|
| 45 | /*...e*/
|
|---|
| 46 |
|
|---|
| 47 | /* #define DEBUG */
|
|---|
| 48 |
|
|---|
| 49 | static GBMFT tif_gbmft =
|
|---|
| 50 | {
|
|---|
| 51 | "TIFF",
|
|---|
| 52 | "Tagged Image File Format support (almost TIFF 6.0 Baseline)",
|
|---|
| 53 | "TIF TIFF",
|
|---|
| 54 | GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|GBM_FT_R24|
|
|---|
| 55 | GBM_FT_W1|GBM_FT_W4|GBM_FT_W8|GBM_FT_W24,
|
|---|
| 56 | };
|
|---|
| 57 |
|
|---|
| 58 | /*...serror codes:0:*/
|
|---|
| 59 | #define GBM_ERR_TIF_VERSION ((GBM_ERR) 800)
|
|---|
| 60 | #define GBM_ERR_TIF_N_TAGS ((GBM_ERR) 801)
|
|---|
| 61 | #define GBM_ERR_TIF_TAG_TYPE ((GBM_ERR) 802)
|
|---|
| 62 | #define GBM_ERR_TIF_HEADER ((GBM_ERR) 803)
|
|---|
| 63 | #define GBM_ERR_TIF_MISSING_TAG ((GBM_ERR) 804)
|
|---|
| 64 | #define GBM_ERR_TIF_SPP_BIT ((GBM_ERR) 805)
|
|---|
| 65 | #define GBM_ERR_TIF_BPS_BIT ((GBM_ERR) 806)
|
|---|
| 66 | #define GBM_ERR_TIF_SPP_RGB ((GBM_ERR) 807)
|
|---|
| 67 | #define GBM_ERR_TIF_BPS_RGB ((GBM_ERR) 808)
|
|---|
| 68 | #define GBM_ERR_TIF_SPP_PAL ((GBM_ERR) 809)
|
|---|
| 69 | #define GBM_ERR_TIF_BPS_PAL ((GBM_ERR) 810)
|
|---|
| 70 | #define GBM_ERR_TIF_SPP_CMYK ((GBM_ERR) 811)
|
|---|
| 71 | #define GBM_ERR_TIF_BPS_CMYK ((GBM_ERR) 812)
|
|---|
| 72 | #define GBM_ERR_TIF_COMP_1D_MH ((GBM_ERR) 813)
|
|---|
| 73 | #define GBM_ERR_TIF_COMP_T4 ((GBM_ERR) 814)
|
|---|
| 74 | #define GBM_ERR_TIF_COMP_T6 ((GBM_ERR) 815)
|
|---|
| 75 | #define GBM_ERR_TIF_COMP ((GBM_ERR) 816)
|
|---|
| 76 | #define GBM_ERR_TIF_COLORMAP ((GBM_ERR) 817)
|
|---|
| 77 | #define GBM_ERR_TIF_CORRUPT ((GBM_ERR) 818)
|
|---|
| 78 | #define GBM_ERR_TIF_PREDICTOR ((GBM_ERR) 819)
|
|---|
| 79 | #define GBM_ERR_TIF_PHOTO_TRANS ((GBM_ERR) 821)
|
|---|
| 80 | #define GBM_ERR_TIF_PHOTO_Y_Cb_Cr ((GBM_ERR) 822)
|
|---|
| 81 | #define GBM_ERR_TIF_PHOTO ((GBM_ERR) 823)
|
|---|
| 82 | #define GBM_ERR_TIF_FILLORDER ((GBM_ERR) 824)
|
|---|
| 83 | #define GBM_ERR_TIF_PLANARCONFIG_1 ((GBM_ERR) 825)
|
|---|
| 84 | #define GBM_ERR_TIF_PLANARCONFIG_12 ((GBM_ERR) 826)
|
|---|
| 85 | #define GBM_ERR_TIF_INKSET ((GBM_ERR) 827)
|
|---|
| 86 | #define GBM_ERR_TIF_ORIENT ((GBM_ERR) 828)
|
|---|
| 87 | #define GBM_ERR_TIF_INDEX ((GBM_ERR) 829)
|
|---|
| 88 | /*...e*/
|
|---|
| 89 |
|
|---|
| 90 | /*...sdefns:0:*/
|
|---|
| 91 | /*
|
|---|
| 92 | #define MAX_STRIPS 200
|
|---|
| 93 | */
|
|---|
| 94 | #define MAX_STRIPS ((PRIV_SIZE-9*sizeof(int)-0x100*sizeof(GBMRGB))/sizeof(long))
|
|---|
| 95 |
|
|---|
| 96 | typedef struct
|
|---|
| 97 | {
|
|---|
| 98 | GBMRGB gbmrgb[0x100];
|
|---|
| 99 | int rps, spp, bps, comp, photo, orient, planar, predictor, inx;
|
|---|
| 100 | long so[MAX_STRIPS];
|
|---|
| 101 | } TIF_PRIV;
|
|---|
| 102 |
|
|---|
| 103 | #define ENC_NONE ((int) 1)
|
|---|
| 104 | #define ENC_G3_1D_MH ((int) 2)
|
|---|
| 105 | #define ENC_T4 ((int) 3)
|
|---|
| 106 | #define ENC_T6 ((int) 4)
|
|---|
| 107 | #define ENC_LZW ((int) 5)
|
|---|
| 108 | #define ENC_PACKBITS ((int) 32773)
|
|---|
| 109 |
|
|---|
| 110 | #define PHOTO_BIT0 0
|
|---|
| 111 | #define PHOTO_BIT1 1
|
|---|
| 112 | #define PHOTO_RGB 2
|
|---|
| 113 | #define PHOTO_PAL 3
|
|---|
| 114 | #define PHOTO_TRANS 4
|
|---|
| 115 | #define PHOTO_CMYK 5
|
|---|
| 116 | #define PHOTO_Y_Cb_Cr 6
|
|---|
| 117 |
|
|---|
| 118 | /* TIFF LZW definitions */
|
|---|
| 119 |
|
|---|
| 120 | #define INIT_CODE_SIZE 9
|
|---|
| 121 | #define CLEAR_CODE 0x100
|
|---|
| 122 | #define EOI_CODE 0x101
|
|---|
| 123 | #define FIRST_FREE_CODE 0x102
|
|---|
| 124 | /*...e*/
|
|---|
| 125 |
|
|---|
| 126 | /*...srgb_bgr:0:*/
|
|---|
| 127 | static void rgb_bgr(const byte *p, byte *q, int n)
|
|---|
| 128 | {
|
|---|
| 129 | while ( n-- )
|
|---|
| 130 | {
|
|---|
| 131 | byte r = *p++;
|
|---|
| 132 | byte g = *p++;
|
|---|
| 133 | byte b = *p++;
|
|---|
| 134 |
|
|---|
| 135 | *q++ = b;
|
|---|
| 136 | *q++ = g;
|
|---|
| 137 | *q++ = r;
|
|---|
| 138 | }
|
|---|
| 139 | }
|
|---|
| 140 | /*...e*/
|
|---|
| 141 |
|
|---|
| 142 | typedef unsigned int cword;
|
|---|
| 143 |
|
|---|
| 144 | #ifdef DEBUG
|
|---|
| 145 | #define LOG(args) printf args
|
|---|
| 146 | #else
|
|---|
| 147 | #define LOG(args)
|
|---|
| 148 | #endif
|
|---|
| 149 |
|
|---|
| 150 | /*...stif_qft:0:*/
|
|---|
| 151 | GBM_ERR tif_qft(GBMFT *gbmft)
|
|---|
| 152 | {
|
|---|
| 153 | *gbmft = tif_gbmft;
|
|---|
| 154 | return GBM_ERR_OK;
|
|---|
| 155 | }
|
|---|
| 156 | /*...e*/
|
|---|
| 157 | /*...stif_rhdr:0:*/
|
|---|
| 158 | /*...svalue_of_tag_def:0:*/
|
|---|
| 159 | static long value_of_tag_def(IFD *ifd, short type, long def)
|
|---|
| 160 | {
|
|---|
| 161 | TAG *tag;
|
|---|
| 162 |
|
|---|
| 163 | if ( (tag = locate_tag(ifd, type)) != NULL )
|
|---|
| 164 | return value_of_tag(tag);
|
|---|
| 165 | else
|
|---|
| 166 | return def;
|
|---|
| 167 | }
|
|---|
| 168 | /*...e*/
|
|---|
| 169 |
|
|---|
| 170 | GBM_ERR tif_rhdr(const char *fn, int fd, GBM *gbm, const char *opt)
|
|---|
| 171 | {
|
|---|
| 172 | TIF_PRIV *tif_priv = (TIF_PRIV *) gbm->priv;
|
|---|
| 173 | TAG *tag_w, *tag_h, *tag_so;
|
|---|
| 174 | GBM_ERR rc;
|
|---|
| 175 | IFH *ifh;
|
|---|
| 176 | IFD *ifd;
|
|---|
| 177 | int inx = 0, strip, n_strips, fillorder;
|
|---|
| 178 | const char *index;
|
|---|
| 179 |
|
|---|
| 180 | if ( (index = gbm_find_word_prefix(opt, "index=")) != NULL )
|
|---|
| 181 | sscanf(index + 6, "%d", &inx);
|
|---|
| 182 | tif_priv->inx = inx;
|
|---|
| 183 |
|
|---|
| 184 | fn=fn; /* Suppress 'unref arg' compiler warnings */
|
|---|
| 185 |
|
|---|
| 186 | switch ( read_ifh_and_ifd(fd, inx, &ifh) )
|
|---|
| 187 | {
|
|---|
| 188 | case TE_OK: rc = GBM_ERR_OK; break;
|
|---|
| 189 | case TE_MEM: rc = GBM_ERR_MEM; break;
|
|---|
| 190 | case TE_VERSION: rc = GBM_ERR_TIF_VERSION; break;
|
|---|
| 191 | case TE_N_TAGS: rc = GBM_ERR_TIF_N_TAGS; break;
|
|---|
| 192 | case TE_TAG_TYPE: rc = GBM_ERR_TIF_TAG_TYPE; break;
|
|---|
| 193 | case TE_N_IFD: rc = GBM_ERR_TIF_INDEX; break;
|
|---|
| 194 | default: rc = GBM_ERR_TIF_HEADER; break;
|
|---|
| 195 | }
|
|---|
| 196 |
|
|---|
| 197 | if ( rc != GBM_ERR_OK )
|
|---|
| 198 | return rc;
|
|---|
| 199 |
|
|---|
| 200 | ifd = ifh->ifd;
|
|---|
| 201 |
|
|---|
| 202 | if ( (tag_w = locate_tag(ifd, T_IMAGEWIDTH )) == NULL ||
|
|---|
| 203 | (tag_h = locate_tag(ifd, T_IMAGELENGTH )) == NULL ||
|
|---|
| 204 | (tag_so = locate_tag(ifd, T_STRIPOFFSETS)) == NULL )
|
|---|
| 205 | {
|
|---|
| 206 | free_ifh(ifh);
|
|---|
| 207 | return GBM_ERR_TIF_MISSING_TAG;
|
|---|
| 208 | }
|
|---|
| 209 |
|
|---|
| 210 | gbm->w = (int) value_of_tag(tag_w);
|
|---|
| 211 | gbm->h = (int) value_of_tag(tag_h);
|
|---|
| 212 | tif_priv->photo = (int) value_of_tag_def(ifd, T_PHOTOMETRIC , 1L);
|
|---|
| 213 | tif_priv->rps = (int) value_of_tag_def(ifd, T_ROWSPERSTRIP , (long) gbm->h);
|
|---|
| 214 | tif_priv->spp = (int) value_of_tag_def(ifd, T_SAMPLESPERPIXEL, 1L);
|
|---|
| 215 | tif_priv->bps = (int) value_of_tag_def(ifd, T_BITSPERSAMPLE , 1L);
|
|---|
| 216 | tif_priv->comp = (int) value_of_tag_def(ifd, T_COMPRESSION , 1L);
|
|---|
| 217 | tif_priv->orient = (int) value_of_tag_def(ifd, T_ORIENTATION , 1L);
|
|---|
| 218 | tif_priv->planar = (int) value_of_tag_def(ifd, T_PLANARCONFIG , 1L);
|
|---|
| 219 |
|
|---|
| 220 | rc = GBM_ERR_OK;
|
|---|
| 221 | switch ( tif_priv->photo )
|
|---|
| 222 | {
|
|---|
| 223 | /*...sPHOTO_BITx \45\ bitmap or greyscale:16:*/
|
|---|
| 224 | case PHOTO_BIT0:
|
|---|
| 225 | case PHOTO_BIT1:
|
|---|
| 226 | if ( tif_priv->spp != 1 )
|
|---|
| 227 | rc = GBM_ERR_TIF_SPP_BIT;
|
|---|
| 228 | else if ( tif_priv->bps != 1 && tif_priv->bps != 4 && tif_priv->bps != 8 )
|
|---|
| 229 | rc = GBM_ERR_TIF_BPS_BIT;
|
|---|
| 230 | else
|
|---|
| 231 | {
|
|---|
| 232 | int i, n_pal;
|
|---|
| 233 |
|
|---|
| 234 | n_pal = ( 1 << tif_priv->bps );
|
|---|
| 235 | for ( i = 0; i < n_pal; i++ )
|
|---|
| 236 | {
|
|---|
| 237 | tif_priv->gbmrgb[i].r =
|
|---|
| 238 | tif_priv->gbmrgb[i].g =
|
|---|
| 239 | tif_priv->gbmrgb[i].b = (byte) ((0xff * i) / (n_pal - 1));
|
|---|
| 240 | }
|
|---|
| 241 | if ( tif_priv->photo == PHOTO_BIT0 )
|
|---|
| 242 | for ( i = 0; i < n_pal; i++ )
|
|---|
| 243 | {
|
|---|
| 244 | tif_priv->gbmrgb[i].r ^= 0xff;
|
|---|
| 245 | tif_priv->gbmrgb[i].g ^= 0xff;
|
|---|
| 246 | tif_priv->gbmrgb[i].b ^= 0xff;
|
|---|
| 247 | }
|
|---|
| 248 | }
|
|---|
| 249 | gbm->bpp = tif_priv->bps;
|
|---|
| 250 | break;
|
|---|
| 251 | /*...e*/
|
|---|
| 252 | /*...sPHOTO_RGB \45\ 24 bit data:16:*/
|
|---|
| 253 | /* It is possible for sample per pixel to be greater than 3.
|
|---|
| 254 | This implies there are extra samples (which we will ignore).
|
|---|
| 255 | This is a new TIFF 6.0 feature. */
|
|---|
| 256 |
|
|---|
| 257 | case PHOTO_RGB:
|
|---|
| 258 | if ( tif_priv->spp < 3 )
|
|---|
| 259 | rc = GBM_ERR_TIF_SPP_RGB;
|
|---|
| 260 | else if ( tif_priv->bps != 8 )
|
|---|
| 261 | rc = GBM_ERR_TIF_BPS_RGB;
|
|---|
| 262 | gbm->bpp = 24;
|
|---|
| 263 | break;
|
|---|
| 264 | /*...e*/
|
|---|
| 265 | /*...sPHOTO_PAL \45\ palettised:16:*/
|
|---|
| 266 | /*
|
|---|
| 267 | There are 2 known bugs in commonly available TIFF files today.
|
|---|
| 268 | UBU will only write a ColorMap tag with a length field of 256 (not 256 * 3).
|
|---|
| 269 | This bug is fixed inside my TIFF library itself!
|
|---|
| 270 | OS/2 Image Support will write all palette entrys as bytes!
|
|---|
| 271 | */
|
|---|
| 272 |
|
|---|
| 273 | case PHOTO_PAL:
|
|---|
| 274 | if ( tif_priv->spp != 1 )
|
|---|
| 275 | rc = GBM_ERR_TIF_SPP_PAL;
|
|---|
| 276 | else if ( tif_priv->bps != 1 && tif_priv->bps != 4 && tif_priv->bps != 8 )
|
|---|
| 277 | rc = GBM_ERR_TIF_BPS_PAL;
|
|---|
| 278 | else
|
|---|
| 279 | {
|
|---|
| 280 | int i, n_pal;
|
|---|
| 281 | TAG *tag_cm;
|
|---|
| 282 |
|
|---|
| 283 | n_pal = (1 << tif_priv->bps);
|
|---|
| 284 | if ( (tag_cm = locate_tag(ifd, T_COLORMAP)) != NULL )
|
|---|
| 285 | {
|
|---|
| 286 | GBMRGB *gbmrgb;
|
|---|
| 287 |
|
|---|
| 288 | for ( i = 0, gbmrgb = tif_priv->gbmrgb; i < n_pal; i++, gbmrgb++ )
|
|---|
| 289 | {
|
|---|
| 290 | gbmrgb->r = (byte) ((unsigned)value_of_tag_n(tag_cm, i) >> 8);
|
|---|
| 291 | gbmrgb->g = (byte) ((unsigned)value_of_tag_n(tag_cm, n_pal + i) >> 8);
|
|---|
| 292 | gbmrgb->b = (byte) ((unsigned)value_of_tag_n(tag_cm, 2 * n_pal + i) >> 8);
|
|---|
| 293 | }
|
|---|
| 294 | /*...sfix for OS\47\2 Image Support \40\and others\41\:40:*/
|
|---|
| 295 | {
|
|---|
| 296 | byte bugfix = 0;
|
|---|
| 297 |
|
|---|
| 298 | for ( i = 0, gbmrgb = tif_priv->gbmrgb; i < n_pal; i++, gbmrgb++ )
|
|---|
| 299 | bugfix |= (gbmrgb->r | gbmrgb->g | gbmrgb->b);
|
|---|
| 300 |
|
|---|
| 301 | if ( bugfix == 0 )
|
|---|
| 302 | for ( i = 0, gbmrgb = tif_priv->gbmrgb; i < n_pal; i++, gbmrgb++ )
|
|---|
| 303 | {
|
|---|
| 304 | gbmrgb->r = (byte) value_of_tag_n(tag_cm, i);
|
|---|
| 305 | gbmrgb->g = (byte) value_of_tag_n(tag_cm, n_pal + i);
|
|---|
| 306 | gbmrgb->b = (byte) value_of_tag_n(tag_cm, 2 * n_pal + i);
|
|---|
| 307 | }
|
|---|
| 308 | }
|
|---|
| 309 | /*...e*/
|
|---|
| 310 | }
|
|---|
| 311 | else
|
|---|
| 312 | rc = GBM_ERR_TIF_COLORMAP;
|
|---|
| 313 | }
|
|---|
| 314 | gbm->bpp = tif_priv->bps;
|
|---|
| 315 | break;
|
|---|
| 316 | /*...e*/
|
|---|
| 317 | /*...sPHOTO_TRANS \45\ transparency mask:16:*/
|
|---|
| 318 | case PHOTO_TRANS:
|
|---|
| 319 | rc = GBM_ERR_TIF_PHOTO_TRANS;
|
|---|
| 320 | break;
|
|---|
| 321 | /*...e*/
|
|---|
| 322 | /*...sPHOTO_CMYK \45\ CMYK or other seperated image:16:*/
|
|---|
| 323 | /* This is a colour seperated image.
|
|---|
| 324 | Typically expect 4 seperations, for CMYK.
|
|---|
| 325 | Can be other numbers, and possibly 4 with non standard ink colours.
|
|---|
| 326 | Ignore all but 4 seperations which are CMYK.
|
|---|
| 327 | Consider this a 24 bit RGB, mapping will occur from CMYK to RGB. */
|
|---|
| 328 |
|
|---|
| 329 | case PHOTO_CMYK:
|
|---|
| 330 | if ( tif_priv->spp != 4 )
|
|---|
| 331 | rc = GBM_ERR_TIF_SPP_CMYK;
|
|---|
| 332 | else if ( tif_priv->bps != 8 )
|
|---|
| 333 | rc = GBM_ERR_TIF_BPS_CMYK;
|
|---|
| 334 | else if ( value_of_tag_def(ifd, T_INKSET, 1L) != 1 )
|
|---|
| 335 | rc = GBM_ERR_TIF_INKSET;
|
|---|
| 336 | else
|
|---|
| 337 | gbm->bpp = 24;
|
|---|
| 338 | break;
|
|---|
| 339 | /*...e*/
|
|---|
| 340 | /*...sPHOTO_Y_Cb_Cr \45\ Y\45\Cb\45\Cr colour space:16:*/
|
|---|
| 341 | case PHOTO_Y_Cb_Cr:
|
|---|
| 342 | rc = GBM_ERR_TIF_PHOTO_Y_Cb_Cr;
|
|---|
| 343 | break;
|
|---|
| 344 | /*...e*/
|
|---|
| 345 | /*...sdefault \45\ wierd PhotometricInterpretation:16:*/
|
|---|
| 346 | default:
|
|---|
| 347 | rc = GBM_ERR_TIF_PHOTO;
|
|---|
| 348 | break;
|
|---|
| 349 | /*...e*/
|
|---|
| 350 | }
|
|---|
| 351 |
|
|---|
| 352 | if ( rc != GBM_ERR_OK )
|
|---|
| 353 | { free_ifh(ifh); return rc; }
|
|---|
| 354 |
|
|---|
| 355 | /* Remember where strips are, and how big they are */
|
|---|
| 356 |
|
|---|
| 357 | n_strips = (gbm->h + (tif_priv->rps - 1)) / tif_priv->rps;
|
|---|
| 358 | if ( tif_priv->photo == PHOTO_RGB && tif_priv->planar == 2 )
|
|---|
| 359 | n_strips *= 3;
|
|---|
| 360 |
|
|---|
| 361 | if ( n_strips <= MAX_STRIPS )
|
|---|
| 362 | for ( strip = 0; strip < n_strips; strip++ )
|
|---|
| 363 | tif_priv->so[strip] = value_of_tag_n(tag_so, strip);
|
|---|
| 364 |
|
|---|
| 365 | if ( tif_priv->comp != ENC_NONE &&
|
|---|
| 366 | tif_priv->comp != ENC_PACKBITS &&
|
|---|
| 367 | tif_priv->comp != ENC_LZW )
|
|---|
| 368 | /*...sreject compression type:16:*/
|
|---|
| 369 | {
|
|---|
| 370 | free_ifh(ifh);
|
|---|
| 371 | switch ( tif_priv->comp )
|
|---|
| 372 | {
|
|---|
| 373 | case ENC_G3_1D_MH: return GBM_ERR_TIF_COMP_1D_MH;
|
|---|
| 374 | case ENC_T4: return GBM_ERR_TIF_COMP_T4 ;
|
|---|
| 375 | case ENC_T6: return GBM_ERR_TIF_COMP_T6 ;
|
|---|
| 376 | default: return GBM_ERR_TIF_COMP ;
|
|---|
| 377 | }
|
|---|
| 378 | }
|
|---|
| 379 | /*...e*/
|
|---|
| 380 |
|
|---|
| 381 | if ( tif_priv->orient != 1 && tif_priv->orient != 4 )
|
|---|
| 382 | { free_ifh(ifh); return GBM_ERR_TIF_ORIENT; }
|
|---|
| 383 |
|
|---|
| 384 | fillorder = (int) value_of_tag_def(ifd, T_FILLORDER, 1L);
|
|---|
| 385 | if ( fillorder != 1 )
|
|---|
| 386 | { free_ifh(ifh); return GBM_ERR_TIF_FILLORDER; }
|
|---|
| 387 |
|
|---|
| 388 | if ( tif_priv->photo == PHOTO_RGB )
|
|---|
| 389 | /* Allow photo of 1 or 2 */
|
|---|
| 390 | {
|
|---|
| 391 | if ( tif_priv->planar != 1 && tif_priv->planar != 2 )
|
|---|
| 392 | { free_ifh(ifh); return GBM_ERR_TIF_PLANARCONFIG_12; }
|
|---|
| 393 | }
|
|---|
| 394 | else
|
|---|
| 395 | /* Allow photo of 1 only */
|
|---|
| 396 | {
|
|---|
| 397 | if ( tif_priv->planar != 1 )
|
|---|
| 398 | { free_ifh(ifh); return GBM_ERR_TIF_PLANARCONFIG_1; }
|
|---|
| 399 | }
|
|---|
| 400 |
|
|---|
| 401 | tif_priv->predictor = (int) value_of_tag_def(ifd, T_PREDICTOR, 1L);
|
|---|
| 402 |
|
|---|
| 403 | /* Only allow predictor of 1, unless a special case we handle */
|
|---|
| 404 | if ( tif_priv->predictor != 1 &&
|
|---|
| 405 | !(tif_priv->comp == ENC_LZW &&
|
|---|
| 406 | tif_priv->bps == 8 &&
|
|---|
| 407 | (tif_priv->spp == 1 || tif_priv->spp >= 3)) )
|
|---|
| 408 | { free_ifh(ifh); return GBM_ERR_TIF_PREDICTOR; }
|
|---|
| 409 |
|
|---|
| 410 | free_ifh(ifh);
|
|---|
| 411 |
|
|---|
| 412 | return GBM_ERR_OK;
|
|---|
| 413 | }
|
|---|
| 414 | /*...e*/
|
|---|
| 415 | /*...stif_rpal:0:*/
|
|---|
| 416 | GBM_ERR tif_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
|
|---|
| 417 | {
|
|---|
| 418 | TIF_PRIV *tif_priv = (TIF_PRIV *) gbm->priv;
|
|---|
| 419 |
|
|---|
| 420 | fd=fd; /* Suppress 'unref arg' compiler warning */
|
|---|
| 421 |
|
|---|
| 422 | if ( gbm->bpp != 24 )
|
|---|
| 423 | memcpy(gbmrgb, tif_priv->gbmrgb, (1 << gbm->bpp) * sizeof(GBMRGB));
|
|---|
| 424 |
|
|---|
| 425 | return GBM_ERR_OK;
|
|---|
| 426 | }
|
|---|
| 427 | /*...e*/
|
|---|
| 428 | /*...stif_rdata:0:*/
|
|---|
| 429 | /*
|
|---|
| 430 | TIFF data is usually stored top-left-origin based.
|
|---|
| 431 | ie: We ignore the private "Orientation" tag.
|
|---|
| 432 | Our data format in memory has bigger padding than TIFF.
|
|---|
| 433 | It has 'istride' bytes per line, GBM uses/requires 'stride' bytes per line.
|
|---|
| 434 | Therefore we read it to the part of the strip area and then expand downwards.
|
|---|
| 435 | */
|
|---|
| 436 |
|
|---|
| 437 | /*...sget_strip_packbits \45\ get bytes with packbits decompression:0:*/
|
|---|
| 438 | static GBM_ERR get_strip_packbits(int fd, byte *dest, long n_bytes)
|
|---|
| 439 | {
|
|---|
| 440 | AHEAD *ahead;
|
|---|
| 441 |
|
|---|
| 442 | if ( (ahead = gbm_create_ahead(fd)) == NULL )
|
|---|
| 443 | return GBM_ERR_MEM;
|
|---|
| 444 |
|
|---|
| 445 | while ( n_bytes > 0 )
|
|---|
| 446 | {
|
|---|
| 447 | byte b = (byte) gbm_read_ahead(ahead);
|
|---|
| 448 |
|
|---|
| 449 | if ( b < 0x80 )
|
|---|
| 450 | {
|
|---|
| 451 | unsigned int count = b + 1;
|
|---|
| 452 |
|
|---|
| 453 | do
|
|---|
| 454 | *dest++ = (byte) gbm_read_ahead(ahead);
|
|---|
| 455 | while ( --count > 0 );
|
|---|
| 456 | n_bytes -= (b + 1);
|
|---|
| 457 | }
|
|---|
| 458 | else if ( b > 0x80 )
|
|---|
| 459 | {
|
|---|
| 460 | unsigned int count = 0x101 - (unsigned int) b;
|
|---|
| 461 | byte c = (byte) gbm_read_ahead(ahead);
|
|---|
| 462 |
|
|---|
| 463 | memset(dest, c, count);
|
|---|
| 464 | dest += count;
|
|---|
| 465 | n_bytes -= count;
|
|---|
| 466 | }
|
|---|
| 467 | }
|
|---|
| 468 |
|
|---|
| 469 | gbm_destroy_ahead(ahead);
|
|---|
| 470 | return GBM_ERR_OK;
|
|---|
| 471 | }
|
|---|
| 472 | /*...e*/
|
|---|
| 473 | /*...sget_strip_lzw \45\ get bytes with TIFF style LZW decompression:0:*/
|
|---|
| 474 | /*
|
|---|
| 475 | This code runs on output of FotoTouch and some sample TIFFs from an afs
|
|---|
| 476 | directory on the IBM IP-network.
|
|---|
| 477 | */
|
|---|
| 478 |
|
|---|
| 479 | /*...sread context:0:*/
|
|---|
| 480 | typedef struct
|
|---|
| 481 | {
|
|---|
| 482 | int fd; /* File descriptor to read */
|
|---|
| 483 | int inx, size; /* Index and size in bits */
|
|---|
| 484 | byte buf[255+3]; /* Buffer holding bits */
|
|---|
| 485 | int code_size; /* Number of bits to return at once */
|
|---|
| 486 | cword read_mask; /* 2^code_size-1 */
|
|---|
| 487 | } READ_CONTEXT;
|
|---|
| 488 |
|
|---|
| 489 | static cword read_code(READ_CONTEXT *c)
|
|---|
| 490 | {
|
|---|
| 491 | dword raw_code; int byte_inx;
|
|---|
| 492 |
|
|---|
| 493 | while ( c->inx + c->code_size > c->size )
|
|---|
| 494 | /*...snot enough bits in buffer\44\ refill it:16:*/
|
|---|
| 495 | /* Not very efficient, but infrequently called */
|
|---|
| 496 |
|
|---|
| 497 | {
|
|---|
| 498 | int bytes_to_lose = ((unsigned)c->inx >> 3);
|
|---|
| 499 | int bytes;
|
|---|
| 500 |
|
|---|
| 501 | /* Note biggest code size is 12 bits */
|
|---|
| 502 | /* And this can at worst span 3 bytes */
|
|---|
| 503 | memcpy(c->buf, c->buf + bytes_to_lose, 3);
|
|---|
| 504 | (c->inx) &= 7;
|
|---|
| 505 | (c->size) -= (bytes_to_lose << 3);
|
|---|
| 506 | bytes = 255 - ( (unsigned)c->size >> 3 );
|
|---|
| 507 | if ( (bytes = gbm_file_read(c->fd, c->buf + ((unsigned)c->size >> 3), bytes)) <= 0 )
|
|---|
| 508 | return 0xffff;
|
|---|
| 509 | (c->size) += (bytes << 3);
|
|---|
| 510 | }
|
|---|
| 511 | /*...e*/
|
|---|
| 512 |
|
|---|
| 513 | byte_inx = ((unsigned)c->inx >> 3);
|
|---|
| 514 | raw_code = ((c->buf[byte_inx ]) << 16) +
|
|---|
| 515 | ((c->buf[byte_inx + 1]) << 8) +
|
|---|
| 516 | ( c->buf[byte_inx + 2] ) ;
|
|---|
| 517 | raw_code <<= ((c->inx) & 7);
|
|---|
| 518 | (c->inx) += (byte) (c->code_size);
|
|---|
| 519 | raw_code >>= ( 24 - c->code_size );
|
|---|
| 520 | return (cword) raw_code & c->read_mask;
|
|---|
| 521 | }
|
|---|
| 522 | /*...e*/
|
|---|
| 523 |
|
|---|
| 524 | static GBM_ERR get_strip_lzw(int fd, byte *dest, long n_bytes)
|
|---|
| 525 | {
|
|---|
| 526 | cword max_code; /* 1 << code_size */
|
|---|
| 527 | cword free_code; /* Next available free code slot */
|
|---|
| 528 | int i, out_count = 0;
|
|---|
| 529 | cword code, cur_code, old_code, in_code, fin_char;
|
|---|
| 530 | cword *prefix, *suffix, *outcode;
|
|---|
| 531 | READ_CONTEXT c;
|
|---|
| 532 | BOOLEAN table_full = FALSE;
|
|---|
| 533 | byte *limit = dest+n_bytes;
|
|---|
| 534 |
|
|---|
| 535 | if ( (prefix = (cword *) malloc((size_t) (4096 * sizeof(cword)))) == NULL )
|
|---|
| 536 | return GBM_ERR_MEM;
|
|---|
| 537 | if ( (suffix = (cword *) malloc((size_t) (4096 * sizeof(cword)))) == NULL )
|
|---|
| 538 | {
|
|---|
| 539 | free(prefix);
|
|---|
| 540 | return GBM_ERR_MEM;
|
|---|
| 541 | }
|
|---|
| 542 | if ( (outcode = (cword *) malloc((size_t) (4097 * sizeof(cword)))) == NULL )
|
|---|
| 543 | {
|
|---|
| 544 | free(suffix);
|
|---|
| 545 | free(prefix);
|
|---|
| 546 | return GBM_ERR_MEM;
|
|---|
| 547 | }
|
|---|
| 548 |
|
|---|
| 549 | /* Initial read context */
|
|---|
| 550 |
|
|---|
| 551 | c.inx = 0;
|
|---|
| 552 | c.size = 0;
|
|---|
| 553 | c.fd = fd;
|
|---|
| 554 | c.code_size = INIT_CODE_SIZE;
|
|---|
| 555 | c.read_mask = (cword) ( (1 << INIT_CODE_SIZE) - 1 );
|
|---|
| 556 |
|
|---|
| 557 | /* 2^min_code size accounts for all colours in file */
|
|---|
| 558 |
|
|---|
| 559 | free_code = FIRST_FREE_CODE;
|
|---|
| 560 | max_code = (cword) ( 1 << INIT_CODE_SIZE );
|
|---|
| 561 |
|
|---|
| 562 | LOG(("STRIP\n"));
|
|---|
| 563 | while ( dest < limit && (code = read_code(&c)) != EOI_CODE && code != 0xffff )
|
|---|
| 564 | {
|
|---|
| 565 | if ( code == CLEAR_CODE )
|
|---|
| 566 | {
|
|---|
| 567 | LOG(("CLEARED\n"));
|
|---|
| 568 | c.code_size = INIT_CODE_SIZE;
|
|---|
| 569 | c.read_mask = (cword) ( (1 << INIT_CODE_SIZE) - 1);
|
|---|
| 570 | max_code = (cword) ( 1 << INIT_CODE_SIZE );
|
|---|
| 571 | free_code = FIRST_FREE_CODE;
|
|---|
| 572 | cur_code = old_code = code = read_code(&c);
|
|---|
| 573 | if ( code == EOI_CODE || code == 0xffff )
|
|---|
| 574 | break;
|
|---|
| 575 | fin_char = cur_code;
|
|---|
| 576 | if ( cur_code >= 0x100 )
|
|---|
| 577 | {
|
|---|
| 578 | free(outcode);
|
|---|
| 579 | free(suffix);
|
|---|
| 580 | free(prefix);
|
|---|
| 581 | LOG(("CORRUPT1\n"));
|
|---|
| 582 | return GBM_ERR_TIF_CORRUPT;
|
|---|
| 583 | }
|
|---|
| 584 | *dest++ = (byte) fin_char;
|
|---|
| 585 | LOG(("%02x ", (byte) fin_char));
|
|---|
| 586 | LOG(("%03x:%u\n", code, c.code_size));
|
|---|
| 587 | table_full = FALSE;
|
|---|
| 588 | }
|
|---|
| 589 | else
|
|---|
| 590 | {
|
|---|
| 591 | cur_code = in_code = code;
|
|---|
| 592 | if ( cur_code >= free_code )
|
|---|
| 593 | {
|
|---|
| 594 | cur_code = old_code;
|
|---|
| 595 | outcode[out_count++] = fin_char;
|
|---|
| 596 | }
|
|---|
| 597 | while ( cur_code > 0xff )
|
|---|
| 598 | {
|
|---|
| 599 | if ( out_count > 4096 )
|
|---|
| 600 | {
|
|---|
| 601 | free(outcode);
|
|---|
| 602 | free(suffix);
|
|---|
| 603 | free(prefix);
|
|---|
| 604 | LOG(("CORRUPT2\n"));
|
|---|
| 605 | return GBM_ERR_TIF_CORRUPT;
|
|---|
| 606 | }
|
|---|
| 607 | outcode[out_count++] = suffix[cur_code];
|
|---|
| 608 | cur_code = prefix[cur_code];
|
|---|
| 609 | }
|
|---|
| 610 | fin_char = cur_code;
|
|---|
| 611 | outcode[out_count++] = fin_char;
|
|---|
| 612 | for ( i = out_count - 1; i >= 0; i-- )
|
|---|
| 613 | {
|
|---|
| 614 | *dest++ = (byte) outcode[i];
|
|---|
| 615 | LOG(("%02x ", (byte) outcode[i]));
|
|---|
| 616 | }
|
|---|
| 617 | LOG(("%03x:%u\n", code, c.code_size));
|
|---|
| 618 | out_count = 0;
|
|---|
| 619 |
|
|---|
| 620 | /* Update dictionary */
|
|---|
| 621 |
|
|---|
| 622 | if ( !table_full )
|
|---|
| 623 | {
|
|---|
| 624 | prefix[free_code] = old_code;
|
|---|
| 625 | suffix[free_code] = fin_char;
|
|---|
| 626 |
|
|---|
| 627 | /* Advance to next free slot */
|
|---|
| 628 |
|
|---|
| 629 | if ( ++free_code >= max_code - 1 )
|
|---|
| 630 | {
|
|---|
| 631 | if ( c.code_size < 12 )
|
|---|
| 632 | {
|
|---|
| 633 | c.code_size++;
|
|---|
| 634 | max_code <<= 1;
|
|---|
| 635 | c.read_mask = (cword) (( 1 << c.code_size ) - 1);
|
|---|
| 636 | }
|
|---|
| 637 | else
|
|---|
| 638 | {
|
|---|
| 639 | table_full = TRUE;
|
|---|
| 640 | LOG(("FULL\n"));
|
|---|
| 641 | }
|
|---|
| 642 | }
|
|---|
| 643 | }
|
|---|
| 644 | old_code = in_code;
|
|---|
| 645 | }
|
|---|
| 646 | }
|
|---|
| 647 |
|
|---|
| 648 | free(outcode);
|
|---|
| 649 | free(suffix);
|
|---|
| 650 | free(prefix);
|
|---|
| 651 |
|
|---|
| 652 | if ( dest < limit && code == 0xffff )
|
|---|
| 653 | return GBM_ERR_READ;
|
|---|
| 654 |
|
|---|
| 655 | return GBM_ERR_OK;
|
|---|
| 656 | }
|
|---|
| 657 | /*...e*/
|
|---|
| 658 | /*...sget_strip_lzw_pred \45\ get_strip_lzw with non 1 predictor fixup:0:*/
|
|---|
| 659 | static GBM_ERR get_strip_lzw_pred(
|
|---|
| 660 | int fd,
|
|---|
| 661 | byte *dest,
|
|---|
| 662 | long n_bytes,
|
|---|
| 663 | TIF_PRIV *tif_priv,
|
|---|
| 664 | int w, int h
|
|---|
| 665 | )
|
|---|
| 666 | {
|
|---|
| 667 | GBM_ERR rc;
|
|---|
| 668 |
|
|---|
| 669 | if ( (rc = get_strip_lzw(fd, dest, n_bytes)) != GBM_ERR_OK )
|
|---|
| 670 | return rc;
|
|---|
| 671 |
|
|---|
| 672 | if ( tif_priv->predictor == 2 )
|
|---|
| 673 | /* Note: This is only allowed if bps==8 */
|
|---|
| 674 | {
|
|---|
| 675 | int x, y, spp = tif_priv->spp;
|
|---|
| 676 | for ( y = 0; y < h; y++, dest += w * spp )
|
|---|
| 677 | for ( x = spp; x < w * spp; x++ )
|
|---|
| 678 | dest[x] += dest[x - spp];
|
|---|
| 679 | }
|
|---|
| 680 |
|
|---|
| 681 | return GBM_ERR_OK;
|
|---|
| 682 | }
|
|---|
| 683 | /*...e*/
|
|---|
| 684 | /*...sget_strip_comp \45\ get strip\44\ dealing with any compression:0:*/
|
|---|
| 685 | /* n_bytes is passed in as istride * n_lines */
|
|---|
| 686 |
|
|---|
| 687 | static GBM_ERR get_strip_comp(
|
|---|
| 688 | int fd,
|
|---|
| 689 | byte *dest,
|
|---|
| 690 | long so, long n_bytes,
|
|---|
| 691 | TIF_PRIV *tif_priv,
|
|---|
| 692 | int w, int h
|
|---|
| 693 | )
|
|---|
| 694 | {
|
|---|
| 695 | gbm_file_lseek(fd, so, SEEK_SET);
|
|---|
| 696 | switch ( tif_priv->comp )
|
|---|
| 697 | {
|
|---|
| 698 | /*...sENC_NONE \45\ no compression:16:*/
|
|---|
| 699 | case ENC_NONE:
|
|---|
| 700 | return ( (int) n_bytes == gbm_file_read(fd, dest, (int) n_bytes) ) ?
|
|---|
| 701 | GBM_ERR_OK : GBM_ERR_READ;
|
|---|
| 702 | /*...e*/
|
|---|
| 703 | /*...sENC_PACKBITS \45\ packbits:16:*/
|
|---|
| 704 | case ENC_PACKBITS:
|
|---|
| 705 | return get_strip_packbits(fd, dest, n_bytes);
|
|---|
| 706 | /*...e*/
|
|---|
| 707 | /*...sENC_LZW \45\ lzw:16:*/
|
|---|
| 708 | case ENC_LZW:
|
|---|
| 709 | return get_strip_lzw_pred(fd, dest, n_bytes, tif_priv, w, h);
|
|---|
| 710 | /*...e*/
|
|---|
| 711 | }
|
|---|
| 712 | return GBM_ERR_NOT_SUPP;
|
|---|
| 713 | }
|
|---|
| 714 | /*...e*/
|
|---|
| 715 | /*...sget_strip \45\ get strip\44\ discarding extra samples\44\ and CMYK mapping:0:*/
|
|---|
| 716 | /*
|
|---|
| 717 | If there are too many samples per pixel, this code can ignore the extra ones.
|
|---|
| 718 | Also, if CMYK data is being read, it will read the CMYK, and convert.
|
|---|
| 719 | This requires a temporary buffer, to read the original data in.
|
|---|
| 720 | The original data is then 'converted'.
|
|---|
| 721 | */
|
|---|
| 722 |
|
|---|
| 723 | static GBM_ERR get_strip(
|
|---|
| 724 | int fd,
|
|---|
| 725 | byte *dest,
|
|---|
| 726 | long so, long n_bytes,
|
|---|
| 727 | TIF_PRIV *tif_priv,
|
|---|
| 728 | int w, int h
|
|---|
| 729 | )
|
|---|
| 730 | {
|
|---|
| 731 | byte *buf = dest;
|
|---|
| 732 | GBM_ERR rc;
|
|---|
| 733 |
|
|---|
| 734 | if ( tif_priv->photo == PHOTO_CMYK )
|
|---|
| 735 | /*...sallocate space for CMYK image:16:*/
|
|---|
| 736 | {
|
|---|
| 737 | n_bytes = (long) w * 4L * (long) h;
|
|---|
| 738 | if ( (buf = malloc((size_t) n_bytes)) == NULL )
|
|---|
| 739 | return GBM_ERR_MEM;
|
|---|
| 740 | }
|
|---|
| 741 | /*...e*/
|
|---|
| 742 | else if ( tif_priv->photo == PHOTO_RGB && tif_priv->spp > 3 )
|
|---|
| 743 | /*...sallocate space for image \43\ extra samples:16:*/
|
|---|
| 744 | {
|
|---|
| 745 | n_bytes = (long) w * tif_priv->spp * (long) h;
|
|---|
| 746 | if ( (buf = malloc((size_t) n_bytes)) == NULL )
|
|---|
| 747 | return GBM_ERR_MEM;
|
|---|
| 748 | }
|
|---|
| 749 | /*...e*/
|
|---|
| 750 |
|
|---|
| 751 | if ( (rc = get_strip_comp(fd, buf, so, n_bytes, tif_priv, w, h)) != GBM_ERR_OK )
|
|---|
| 752 | {
|
|---|
| 753 | if ( buf != dest )
|
|---|
| 754 | free(buf);
|
|---|
| 755 | return rc;
|
|---|
| 756 | }
|
|---|
| 757 |
|
|---|
| 758 | if ( tif_priv->photo == PHOTO_CMYK )
|
|---|
| 759 | /*...sconvert from CMYK to RGB:16:*/
|
|---|
| 760 | {
|
|---|
| 761 | int x, yy;
|
|---|
| 762 | byte *buf_p = buf, *dest_p = dest;
|
|---|
| 763 | for ( yy = 0; yy < h; yy++ )
|
|---|
| 764 | for ( x = 0; x < w; x++ )
|
|---|
| 765 | {
|
|---|
| 766 | word c = *buf_p++;
|
|---|
| 767 | word m = *buf_p++;
|
|---|
| 768 | word y = *buf_p++;
|
|---|
| 769 | word k = *buf_p++;
|
|---|
| 770 |
|
|---|
| 771 | /* Exploit 8 bit modulo arithmetic by biasing by + 0x100 */
|
|---|
| 772 |
|
|---|
| 773 | word r = 0x1ff - (c + k);
|
|---|
| 774 | word g = 0x1ff - (m + k);
|
|---|
| 775 | word b = 0x1ff - (y + k);
|
|---|
| 776 |
|
|---|
| 777 | if ( r < 0x100 ) r = 0x100;
|
|---|
| 778 | if ( g < 0x100 ) g = 0x100;
|
|---|
| 779 | if ( b < 0x100 ) b = 0x100;
|
|---|
| 780 |
|
|---|
| 781 | *dest_p++ = (byte) r;
|
|---|
| 782 | *dest_p++ = (byte) g;
|
|---|
| 783 | *dest_p++ = (byte) b;
|
|---|
| 784 | }
|
|---|
| 785 |
|
|---|
| 786 | free(buf);
|
|---|
| 787 | }
|
|---|
| 788 | /*...e*/
|
|---|
| 789 | else if ( tif_priv->photo == PHOTO_RGB && tif_priv->spp > 3 )
|
|---|
| 790 | /*...sextract\44\ ignoring extra\45\samples:16:*/
|
|---|
| 791 | {
|
|---|
| 792 | int x, y, skip = tif_priv->spp - 2;
|
|---|
| 793 | byte *buf_p = buf, *dest_p = dest;
|
|---|
| 794 | for ( y = 0; y < h; y++ )
|
|---|
| 795 | for ( x = 0; x < w; x++ )
|
|---|
| 796 | {
|
|---|
| 797 | *dest_p++ = *buf_p++;
|
|---|
| 798 | *dest_p++ = *buf_p++;
|
|---|
| 799 | *dest_p++ = *buf_p ;
|
|---|
| 800 | buf_p += skip;
|
|---|
| 801 | }
|
|---|
| 802 |
|
|---|
| 803 | free(buf);
|
|---|
| 804 | }
|
|---|
| 805 | /*...e*/
|
|---|
| 806 |
|
|---|
| 807 | return GBM_ERR_OK;
|
|---|
| 808 | }
|
|---|
| 809 | /*...e*/
|
|---|
| 810 | /*...sget_image \45\ get all strips\44\ result is whole image:0:*/
|
|---|
| 811 | /*
|
|---|
| 812 | This routine calls get_strip() to get strips data one after another until it
|
|---|
| 813 | has read the entire images worth of data. Of course, scan lines are aligned on
|
|---|
| 814 | byte boundaries, and the data is usually considered to be image top to bottom.
|
|---|
| 815 | */
|
|---|
| 816 |
|
|---|
| 817 | static GBM_ERR get_image(
|
|---|
| 818 | int fd,
|
|---|
| 819 | byte *dest,
|
|---|
| 820 | TIF_PRIV *tif_priv,
|
|---|
| 821 | long *so,
|
|---|
| 822 | GBM *gbm,
|
|---|
| 823 | int *strip
|
|---|
| 824 | )
|
|---|
| 825 | {
|
|---|
| 826 | GBM_ERR rc;
|
|---|
| 827 | int y, istride = ((gbm->w * gbm->bpp + 7) / 8);
|
|---|
| 828 |
|
|---|
| 829 | for ( y = 0; y < gbm->h; y += tif_priv->rps, (*strip)++ )
|
|---|
| 830 | {
|
|---|
| 831 | int n_lines = min(tif_priv->rps, gbm->h - y);
|
|---|
| 832 | if ( (rc = get_strip(fd, dest + y * istride,
|
|---|
| 833 | so[*strip],
|
|---|
| 834 | (long) n_lines * (long) istride,
|
|---|
| 835 | tif_priv,
|
|---|
| 836 | gbm->w, n_lines)) != GBM_ERR_OK )
|
|---|
| 837 | return rc;
|
|---|
| 838 | }
|
|---|
| 839 |
|
|---|
| 840 | return GBM_ERR_OK;
|
|---|
| 841 | }
|
|---|
| 842 | /*...e*/
|
|---|
| 843 | /*...sget_image_planar \45\ get all strips\44\ allowing for PlanarConfiguration:0:*/
|
|---|
| 844 | /*
|
|---|
| 845 | get_image() will assume the data is in PlanarConfiguration==1, ie: chunky
|
|---|
| 846 | pixel mode. This is TRUE most of the time. But sometimes we will actually
|
|---|
| 847 | allow PlanarConfiguration==2. In this case, use get_image() and then fix-up
|
|---|
| 848 | the results.
|
|---|
| 849 | */
|
|---|
| 850 |
|
|---|
| 851 | static GBM_ERR get_image_planar(
|
|---|
| 852 | int fd,
|
|---|
| 853 | byte *dest,
|
|---|
| 854 | TIF_PRIV *tif_priv,
|
|---|
| 855 | long *so,
|
|---|
| 856 | GBM *gbm
|
|---|
| 857 | )
|
|---|
| 858 | {
|
|---|
| 859 | int strip = 0;
|
|---|
| 860 |
|
|---|
| 861 | if ( tif_priv->photo == PHOTO_RGB &&
|
|---|
| 862 | tif_priv->planar == 2 )
|
|---|
| 863 | /*...sread 3 seperate planes\44\ and combine them:16:*/
|
|---|
| 864 | /*
|
|---|
| 865 | If PhotometricInterpretation==RGB and
|
|---|
| 866 | SamplesPerPixel>=3 and
|
|---|
| 867 | BitsPerSample==8 then
|
|---|
| 868 | we allow PlanarConfiguration==2
|
|---|
| 869 |
|
|---|
| 870 | I have successfully read in a PlanarConfiguration==2 RGB TIFF file by using
|
|---|
| 871 | the "read 3 images" logic below. This image had RowsPerStrip==1, and so
|
|---|
| 872 | technically either fold below would have worked. I think the read 3 images
|
|---|
| 873 | logic is a better interpretation of the TIFF 6.0 spec., but until I find
|
|---|
| 874 | some other images I can handle, I will keep the alternative peice of code.
|
|---|
| 875 | */
|
|---|
| 876 |
|
|---|
| 877 | {
|
|---|
| 878 | GBM_ERR rc;
|
|---|
| 879 | GBM gbm_planar;
|
|---|
| 880 | int saved_spp = tif_priv->spp;
|
|---|
| 881 | int n_bytes = gbm->w * gbm->h;
|
|---|
| 882 | int x, y;
|
|---|
| 883 | byte *buf, *p[3];
|
|---|
| 884 |
|
|---|
| 885 | if ( (buf = malloc((size_t) (n_bytes * 3))) == NULL )
|
|---|
| 886 | return GBM_ERR_MEM;
|
|---|
| 887 | p[0] = buf;
|
|---|
| 888 | p[1] = p[0] + n_bytes;
|
|---|
| 889 | p[2] = p[1] + n_bytes;
|
|---|
| 890 |
|
|---|
| 891 | tif_priv->spp = 1;
|
|---|
| 892 | /*...sread 3 images:16:*/
|
|---|
| 893 | {
|
|---|
| 894 | int i;
|
|---|
| 895 |
|
|---|
| 896 | gbm_planar.w = gbm->w;
|
|---|
| 897 | gbm_planar.h = gbm->h;
|
|---|
| 898 | gbm_planar.bpp = 8;
|
|---|
| 899 | for ( i = 0; i < 3; i++ )
|
|---|
| 900 | if ( (rc = get_image(fd, p[i], tif_priv, so, &gbm_planar, &strip)) != GBM_ERR_OK )
|
|---|
| 901 | {
|
|---|
| 902 | tif_priv->spp = saved_spp;
|
|---|
| 903 | free(buf);
|
|---|
| 904 | return rc;
|
|---|
| 905 | }
|
|---|
| 906 | }
|
|---|
| 907 | /*...e*/
|
|---|
| 908 | #ifdef NEVER
|
|---|
| 909 | /*...sread single image 3x too high:16:*/
|
|---|
| 910 | gbm_planar.w = gbm->w;
|
|---|
| 911 | gbm_planar.h = gbm->h * 3;
|
|---|
| 912 | gbm_planar.bpp = 8;
|
|---|
| 913 | if ( (rc = get_image(fd, buf, tif_priv, so, &gbm_planar, &strip)) != GBM_ERR_OK )
|
|---|
| 914 | {
|
|---|
| 915 | tif_priv->spp = saved_spp;
|
|---|
| 916 | free(buf);
|
|---|
| 917 | return rc;
|
|---|
| 918 | }
|
|---|
| 919 | /*...e*/
|
|---|
| 920 | #endif
|
|---|
| 921 | tif_priv->spp = saved_spp;
|
|---|
| 922 |
|
|---|
| 923 | for ( y = 0; y < gbm->h; y++ )
|
|---|
| 924 | for ( x = 0; x < gbm->w; x++ )
|
|---|
| 925 | {
|
|---|
| 926 | *dest++ = *(p[0])++;
|
|---|
| 927 | *dest++ = *(p[1])++;
|
|---|
| 928 | *dest++ = *(p[2])++;
|
|---|
| 929 | }
|
|---|
| 930 | free(buf);
|
|---|
| 931 | return GBM_ERR_OK;
|
|---|
| 932 | }
|
|---|
| 933 | /*...e*/
|
|---|
| 934 | else
|
|---|
| 935 | return get_image(fd, dest, tif_priv, so, gbm, &strip);
|
|---|
| 936 | }
|
|---|
| 937 | /*...e*/
|
|---|
| 938 | /*...sget_image_orient \45\ get all strips\44\ correctly orientated:0:*/
|
|---|
| 939 | static GBM_ERR get_image_orient(
|
|---|
| 940 | int fd,
|
|---|
| 941 | byte *dest,
|
|---|
| 942 | TIF_PRIV *tif_priv,
|
|---|
| 943 | long *so,
|
|---|
| 944 | GBM *gbm
|
|---|
| 945 | )
|
|---|
| 946 | {
|
|---|
| 947 | switch ( tif_priv->orient )
|
|---|
| 948 | {
|
|---|
| 949 | /*...s1 \45\ usual Baseline required case:16:*/
|
|---|
| 950 | /*
|
|---|
| 951 | File has array[scanlines_down] of array[pixels_across] of pixel.
|
|---|
| 952 | GBMs bitmap data is array[scanlines_up] of array[pixels_across] of pixel.
|
|---|
| 953 | So call get_image_planar(), and vertically reflect resulting data.
|
|---|
| 954 | */
|
|---|
| 955 |
|
|---|
| 956 | case 1:
|
|---|
| 957 | {
|
|---|
| 958 | int istride = ((gbm->bpp * gbm->w + 7) / 8);
|
|---|
| 959 | byte *p0, *p1, *p2;
|
|---|
| 960 | GBM_ERR rc;
|
|---|
| 961 | if ( (rc = get_image_planar(fd, dest, tif_priv, so, gbm)) != GBM_ERR_OK )
|
|---|
| 962 | return rc;
|
|---|
| 963 | if ( (p0 = malloc((size_t) istride)) == NULL )
|
|---|
| 964 | return GBM_ERR_MEM;
|
|---|
| 965 | for ( p1 = dest, p2 = p1 + (gbm->h - 1) * istride;
|
|---|
| 966 | p1 < p2;
|
|---|
| 967 | p1 += istride, p2 -= istride )
|
|---|
| 968 | {
|
|---|
| 969 | memcpy(p0, p1, istride);
|
|---|
| 970 | memcpy(p1, p2, istride);
|
|---|
| 971 | memcpy(p2, p0, istride);
|
|---|
| 972 | }
|
|---|
| 973 | free(p0);
|
|---|
| 974 | return GBM_ERR_OK;
|
|---|
| 975 | }
|
|---|
| 976 | /*...e*/
|
|---|
| 977 | /*...s4 \45\ vertically swapped case we can easily handle:16:*/
|
|---|
| 978 | /*
|
|---|
| 979 | File has array[scanlines_up] of array[pixels_across] of pixel.
|
|---|
| 980 | Exactly matches GBMs layout of a bitmap.
|
|---|
| 981 | So simply call get_image() and be done with.
|
|---|
| 982 | */
|
|---|
| 983 |
|
|---|
| 984 | case 4:
|
|---|
| 985 | return get_image_planar(fd, dest, tif_priv, so, gbm);
|
|---|
| 986 | /*...e*/
|
|---|
| 987 | }
|
|---|
| 988 | return GBM_ERR_NOT_SUPP; /* Shouldn't get here */
|
|---|
| 989 | }
|
|---|
| 990 | /*...e*/
|
|---|
| 991 | /*...sget_image_strippy \45\ get all strips\44\ when there are loads of them:0:*/
|
|---|
| 992 | static GBM_ERR get_image_strippy(
|
|---|
| 993 | int fd,
|
|---|
| 994 | byte *dest,
|
|---|
| 995 | TIF_PRIV *tif_priv,
|
|---|
| 996 | GBM *gbm
|
|---|
| 997 | )
|
|---|
| 998 | {
|
|---|
| 999 | int n_strips = (gbm->h + (tif_priv->rps - 1)) / tif_priv->rps;
|
|---|
| 1000 | long *so = tif_priv->so;
|
|---|
| 1001 |
|
|---|
| 1002 | if ( n_strips > MAX_STRIPS )
|
|---|
| 1003 | /*...sre\45\read TIFF file header:16:*/
|
|---|
| 1004 | {
|
|---|
| 1005 | GBM_ERR rc;
|
|---|
| 1006 | int strip;
|
|---|
| 1007 | IFH *ifh;
|
|---|
| 1008 | IFD *ifd;
|
|---|
| 1009 | TAG *tag_so;
|
|---|
| 1010 |
|
|---|
| 1011 | if ( (so = malloc((size_t) (n_strips * sizeof(long)))) == NULL )
|
|---|
| 1012 | return GBM_ERR_MEM;
|
|---|
| 1013 |
|
|---|
| 1014 | gbm_file_lseek(fd, 0L, SEEK_SET);
|
|---|
| 1015 | if ( read_ifh_and_ifd(fd, tif_priv->inx, &ifh) != TE_OK )
|
|---|
| 1016 | {
|
|---|
| 1017 | free(so);
|
|---|
| 1018 | return GBM_ERR_MEM;
|
|---|
| 1019 | }
|
|---|
| 1020 | ifd = ifh->ifd;
|
|---|
| 1021 | tag_so = locate_tag(ifd, T_STRIPOFFSETS);
|
|---|
| 1022 | for ( strip = 0; strip < n_strips; strip++ )
|
|---|
| 1023 | so[strip] = value_of_tag_n(tag_so, strip);
|
|---|
| 1024 | free_ifh(ifh);
|
|---|
| 1025 |
|
|---|
| 1026 | rc = get_image_orient(fd, dest, tif_priv, so, gbm);
|
|---|
| 1027 |
|
|---|
| 1028 | free(so);
|
|---|
| 1029 | return rc;
|
|---|
| 1030 | }
|
|---|
| 1031 | /*...e*/
|
|---|
| 1032 | else
|
|---|
| 1033 | return get_image_orient(fd, dest, tif_priv, so, gbm);
|
|---|
| 1034 | }
|
|---|
| 1035 | /*...e*/
|
|---|
| 1036 |
|
|---|
| 1037 | GBM_ERR tif_rdata(int fd, GBM *gbm, byte *data)
|
|---|
| 1038 | {
|
|---|
| 1039 | TIF_PRIV *tif_priv = (TIF_PRIV *) gbm->priv;
|
|---|
| 1040 | int stride = ((gbm->bpp * gbm->w + 31) / 32) * 4;
|
|---|
| 1041 | int istride = ((gbm->bpp * gbm->w + 7) / 8);
|
|---|
| 1042 | int bias = gbm->h * (stride - istride);
|
|---|
| 1043 | GBM_ERR rc;
|
|---|
| 1044 |
|
|---|
| 1045 | /* Read in data, packed close, and upside down */
|
|---|
| 1046 |
|
|---|
| 1047 | if ( (rc = get_image_strippy(fd, data + bias, tif_priv, gbm)) != GBM_ERR_OK )
|
|---|
| 1048 | return rc;
|
|---|
| 1049 |
|
|---|
| 1050 | /*...snow expand out from byte padding to dword padding:8:*/
|
|---|
| 1051 | if ( bias )
|
|---|
| 1052 | {
|
|---|
| 1053 | int y;
|
|---|
| 1054 | byte *dest = data, *src = data + bias;
|
|---|
| 1055 |
|
|---|
| 1056 | for ( y = 0; y < gbm->h; y++, dest += stride, src += istride )
|
|---|
| 1057 | memcpy(dest, src, istride);
|
|---|
| 1058 | }
|
|---|
| 1059 | /*...e*/
|
|---|
| 1060 | /*...snow RGB\45\\62\BGR if 24 bit data returned:8:*/
|
|---|
| 1061 | if ( gbm->bpp == 24 )
|
|---|
| 1062 | {
|
|---|
| 1063 | int y;
|
|---|
| 1064 | byte *p = data;
|
|---|
| 1065 |
|
|---|
| 1066 | for ( y = 0; y < gbm->h; y++, p += stride )
|
|---|
| 1067 | rgb_bgr(p, p, gbm->w);
|
|---|
| 1068 | }
|
|---|
| 1069 | /*...e*/
|
|---|
| 1070 |
|
|---|
| 1071 | return GBM_ERR_OK;
|
|---|
| 1072 | }
|
|---|
| 1073 | /*...e*/
|
|---|
| 1074 | /*...stif_w:0:*/
|
|---|
| 1075 | /*
|
|---|
| 1076 | Write out data in a single large strip for now.
|
|---|
| 1077 | Note that the palette entrys are written as ((r << 8) | r).
|
|---|
| 1078 | This means they are 257/256 too big (insignificant).
|
|---|
| 1079 | Most programs only look at the top 8 bits (ie: no error).
|
|---|
| 1080 | A few (incorrectly) look at the bottom 8 bits.
|
|---|
| 1081 | Therefore we cater for all programs, with minimal fuss.
|
|---|
| 1082 | */
|
|---|
| 1083 |
|
|---|
| 1084 | /*...suser_tag:0:*/
|
|---|
| 1085 | static BOOLEAN user_tag(IFD *ifd, char *name, short type, const char *opt, char *def)
|
|---|
| 1086 | {
|
|---|
| 1087 | char buf[200+1];
|
|---|
| 1088 | const char *s;
|
|---|
| 1089 |
|
|---|
| 1090 | if ( (s = gbm_find_word_prefix(opt, name)) != NULL )
|
|---|
| 1091 | sscanf(s + strlen(name), "%s", buf);
|
|---|
| 1092 | else
|
|---|
| 1093 | strcpy(buf, def);
|
|---|
| 1094 |
|
|---|
| 1095 | if ( *buf == '\0' )
|
|---|
| 1096 | return TRUE;
|
|---|
| 1097 |
|
|---|
| 1098 | return add_ascii_tag(ifd, type, buf);
|
|---|
| 1099 | }
|
|---|
| 1100 | /*...e*/
|
|---|
| 1101 | /*...swrite_strip:0:*/
|
|---|
| 1102 | static GBM_ERR write_strip(int fd, int w, int h, int bpp, const byte *data)
|
|---|
| 1103 | {
|
|---|
| 1104 | int stride = ((bpp * w + 31) / 32) * 4;
|
|---|
| 1105 | int ostride = ((bpp * w + 7) / 8);
|
|---|
| 1106 | int y;
|
|---|
| 1107 | data += ((h - 1) * stride);
|
|---|
| 1108 | if ( bpp == 24 )
|
|---|
| 1109 | /*...sreverse rgb\47\bgr ordering and write:16:*/
|
|---|
| 1110 | {
|
|---|
| 1111 | byte *line;
|
|---|
| 1112 |
|
|---|
| 1113 | if ( (line = malloc((size_t) ostride)) == NULL )
|
|---|
| 1114 | return GBM_ERR_MEM;
|
|---|
| 1115 | for ( y = 0; y < h; y++, data -= stride )
|
|---|
| 1116 | {
|
|---|
| 1117 | rgb_bgr(data, line, w);
|
|---|
| 1118 | if ( gbm_file_write(fd, line, ostride) != ostride )
|
|---|
| 1119 | {
|
|---|
| 1120 | free(line);
|
|---|
| 1121 | return GBM_ERR_WRITE;
|
|---|
| 1122 | }
|
|---|
| 1123 | }
|
|---|
| 1124 | free(line);
|
|---|
| 1125 | }
|
|---|
| 1126 | /*...e*/
|
|---|
| 1127 | else
|
|---|
| 1128 | /*...swrite:16:*/
|
|---|
| 1129 | for ( y = 0; y < h; y++, data -= stride )
|
|---|
| 1130 | if ( gbm_file_write(fd, data, ostride) != ostride )
|
|---|
| 1131 | return GBM_ERR_WRITE;
|
|---|
| 1132 | /*...e*/
|
|---|
| 1133 | return GBM_ERR_OK;
|
|---|
| 1134 | }
|
|---|
| 1135 | /*...e*/
|
|---|
| 1136 | /*...swrite_strip_lzw \45\ new fast tail\43\col lookup version:0:*/
|
|---|
| 1137 | /*
|
|---|
| 1138 | This is a tricky bit of code to get right.
|
|---|
| 1139 | This code blantantly copied and hacked from that in gbmgif.c!
|
|---|
| 1140 | hashvalue is calculated from a string of pixels cumulatively.
|
|---|
| 1141 | hashtable is searched starting at index hashvalue for to find the entry.
|
|---|
| 1142 | hashtable is big enough so that MAX_HASH > 4*MAX_DICT.
|
|---|
| 1143 | */
|
|---|
| 1144 |
|
|---|
| 1145 | /*...swrite context:0:*/
|
|---|
| 1146 | #define L_BUF 1024
|
|---|
| 1147 |
|
|---|
| 1148 | typedef struct
|
|---|
| 1149 | {
|
|---|
| 1150 | int fd; /* Open file descriptor to write to */
|
|---|
| 1151 | int inx; /* Bit index into buf */
|
|---|
| 1152 | int code_size; /* Code size in bits */
|
|---|
| 1153 | byte buf[L_BUF+2]; /* Biggest block + overflow space */
|
|---|
| 1154 | } WRITE_CONTEXT;
|
|---|
| 1155 |
|
|---|
| 1156 | static BOOLEAN write_code(cword code, WRITE_CONTEXT *w)
|
|---|
| 1157 | {
|
|---|
| 1158 | byte *buf = w->buf + ((unsigned)w->inx >> 3);
|
|---|
| 1159 |
|
|---|
| 1160 | LOG(("%03x:%u\n", code, w->code_size));
|
|---|
| 1161 | code <<= (24-w->code_size);
|
|---|
| 1162 | code >>= (w->inx&7U);
|
|---|
| 1163 | *buf++ |= (byte) (code >> 16);
|
|---|
| 1164 | *buf++ = (byte) (code >> 8);
|
|---|
| 1165 | *buf = (byte) code ;
|
|---|
| 1166 |
|
|---|
| 1167 | (w->inx) += (w->code_size);
|
|---|
| 1168 | if ( w->inx >= L_BUF * 8 )
|
|---|
| 1169 | /* Flush out full buffer */
|
|---|
| 1170 | {
|
|---|
| 1171 | if ( gbm_file_write(w->fd, w->buf, L_BUF) != L_BUF )
|
|---|
| 1172 | return FALSE;
|
|---|
| 1173 | memcpy(w->buf, w->buf + L_BUF, 2);
|
|---|
| 1174 | memset(w->buf + 2, 0, L_BUF);
|
|---|
| 1175 | (w->inx) -= (L_BUF * 8);
|
|---|
| 1176 | }
|
|---|
| 1177 |
|
|---|
| 1178 | return TRUE;
|
|---|
| 1179 | }
|
|---|
| 1180 |
|
|---|
| 1181 | static BOOLEAN flush_code(WRITE_CONTEXT *w)
|
|---|
| 1182 | {
|
|---|
| 1183 | int bytes = (((unsigned)w->inx + 7) >> 3);
|
|---|
| 1184 |
|
|---|
| 1185 | if ( bytes )
|
|---|
| 1186 | {
|
|---|
| 1187 | if ( gbm_file_write(w->fd, w->buf, bytes) != bytes )
|
|---|
| 1188 | return FALSE;
|
|---|
| 1189 | }
|
|---|
| 1190 |
|
|---|
| 1191 | return TRUE;
|
|---|
| 1192 | }
|
|---|
| 1193 | /*...e*/
|
|---|
| 1194 |
|
|---|
| 1195 | #define MAX_HASH 17777 /* Probably prime, and > 4096 */
|
|---|
| 1196 | #define MAX_DICT 4096 /* Dictionary size */
|
|---|
| 1197 | #define INIT_HASH(p) (((p)+3)*301) /* Initial hash value */
|
|---|
| 1198 |
|
|---|
| 1199 | typedef struct { cword tail; byte col; } DICT;
|
|---|
| 1200 |
|
|---|
| 1201 | static GBM_ERR write_strip_lzw(int fd, int w, int h, int bpp, const byte *data)
|
|---|
| 1202 | {
|
|---|
| 1203 | int stride = ((bpp * w + 31) / 32) * 4;
|
|---|
| 1204 | int ostride = ((bpp * w + 7) / 8);
|
|---|
| 1205 | WRITE_CONTEXT wc;
|
|---|
| 1206 | cword last_code, max_code, tail;
|
|---|
| 1207 | int x, y;
|
|---|
| 1208 | unsigned int hashvalue, lenstring, j;
|
|---|
| 1209 | DICT *dict, **hashtable;
|
|---|
| 1210 |
|
|---|
| 1211 | if ( (dict = (DICT *) malloc((size_t) (MAX_DICT * sizeof(DICT)))) == NULL )
|
|---|
| 1212 | return GBM_ERR_MEM;
|
|---|
| 1213 |
|
|---|
| 1214 | if ( (hashtable = (DICT **) malloc((size_t) (MAX_HASH * sizeof(DICT *)))) == NULL )
|
|---|
| 1215 | {
|
|---|
| 1216 | free(dict);
|
|---|
| 1217 | return GBM_ERR_MEM;
|
|---|
| 1218 | }
|
|---|
| 1219 |
|
|---|
| 1220 | /* Setup write context */
|
|---|
| 1221 |
|
|---|
| 1222 | wc.fd = fd;
|
|---|
| 1223 | wc.inx = 0;
|
|---|
| 1224 | wc.code_size = INIT_CODE_SIZE;
|
|---|
| 1225 | memset(wc.buf, 0, sizeof(wc.buf));
|
|---|
| 1226 |
|
|---|
| 1227 | if ( !write_code(CLEAR_CODE, &wc) )
|
|---|
| 1228 | {
|
|---|
| 1229 | free(hashtable);
|
|---|
| 1230 | free(dict);
|
|---|
| 1231 | return GBM_ERR_WRITE;
|
|---|
| 1232 | }
|
|---|
| 1233 |
|
|---|
| 1234 | last_code = EOI_CODE;
|
|---|
| 1235 | max_code = ( 1 << INIT_CODE_SIZE );
|
|---|
| 1236 | lenstring = 0;
|
|---|
| 1237 |
|
|---|
| 1238 | for ( j = 0; j < MAX_HASH; j++ )
|
|---|
| 1239 | hashtable[j] = NULL;
|
|---|
| 1240 |
|
|---|
| 1241 | data += ( (h - 1) * stride );
|
|---|
| 1242 | for ( y = h - 1; y >= 0; y--, data -= stride )
|
|---|
| 1243 | {
|
|---|
| 1244 | int inx1 = 0, inx2 = 2;
|
|---|
| 1245 | for ( x = 0; x < ostride; x++ )
|
|---|
| 1246 | {
|
|---|
| 1247 | byte col;
|
|---|
| 1248 | /*...sget byte to write to col:24:*/
|
|---|
| 1249 | if ( bpp == 24 )
|
|---|
| 1250 | /* Have to handle rgb/bgr reverse as we go along */
|
|---|
| 1251 | {
|
|---|
| 1252 | col = data[inx1+inx2];
|
|---|
| 1253 | if ( --inx2 < 0 )
|
|---|
| 1254 | {
|
|---|
| 1255 | inx1 += 3; inx2 = 2;
|
|---|
| 1256 | }
|
|---|
| 1257 | }
|
|---|
| 1258 | else
|
|---|
| 1259 | col = data[x];
|
|---|
| 1260 | /*...e*/
|
|---|
| 1261 | /*...sLZW encode:24:*/
|
|---|
| 1262 | if ( ++lenstring == 1 )
|
|---|
| 1263 | {
|
|---|
| 1264 | tail = col;
|
|---|
| 1265 | hashvalue = INIT_HASH(col);
|
|---|
| 1266 | }
|
|---|
| 1267 | else
|
|---|
| 1268 | {
|
|---|
| 1269 | hashvalue *= ( col + lenstring + 4 );
|
|---|
| 1270 | j = ( hashvalue %= MAX_HASH );
|
|---|
| 1271 | while ( hashtable[j] != NULL &&
|
|---|
| 1272 | ( hashtable[j]->tail != tail ||
|
|---|
| 1273 | hashtable[j]->col != col ) )
|
|---|
| 1274 | if ( ++j >= MAX_HASH )
|
|---|
| 1275 | j = 0;
|
|---|
| 1276 | if ( hashtable[j] != NULL )
|
|---|
| 1277 | /* Found in the strings table */
|
|---|
| 1278 | {
|
|---|
| 1279 | tail = (hashtable[j]-dict);
|
|---|
| 1280 | LOG(("%02x ", col));
|
|---|
| 1281 | }
|
|---|
| 1282 | else
|
|---|
| 1283 | /* Not found */
|
|---|
| 1284 | {
|
|---|
| 1285 | if ( !write_code(tail, &wc) )
|
|---|
| 1286 | {
|
|---|
| 1287 | free(hashtable);
|
|---|
| 1288 | free(dict);
|
|---|
| 1289 | return GBM_ERR_WRITE;
|
|---|
| 1290 | }
|
|---|
| 1291 | hashtable[j] = dict + ++last_code;
|
|---|
| 1292 | hashtable[j]->tail = tail;
|
|---|
| 1293 | hashtable[j]->col = col;
|
|---|
| 1294 | LOG(("%02x ", col));
|
|---|
| 1295 | tail = col;
|
|---|
| 1296 | hashvalue = INIT_HASH(col);
|
|---|
| 1297 | lenstring = 1;
|
|---|
| 1298 |
|
|---|
| 1299 | /* Note: Things change 1 earlier than in the GIF LZW case, hence -1. */
|
|---|
| 1300 | if ( last_code >= max_code -1 )
|
|---|
| 1301 | /* Next code will be written longer */
|
|---|
| 1302 | {
|
|---|
| 1303 | max_code <<= 1;
|
|---|
| 1304 | wc.code_size++;
|
|---|
| 1305 | }
|
|---|
| 1306 | else if ( last_code >= MAX_DICT-2 )
|
|---|
| 1307 | /* Reset tables */
|
|---|
| 1308 | {
|
|---|
| 1309 | if ( !write_code(tail , &wc) ||
|
|---|
| 1310 | !write_code(CLEAR_CODE, &wc) )
|
|---|
| 1311 | {
|
|---|
| 1312 | free(hashtable);
|
|---|
| 1313 | free(dict);
|
|---|
| 1314 | return GBM_ERR_WRITE;
|
|---|
| 1315 | }
|
|---|
| 1316 | lenstring = 0;
|
|---|
| 1317 | last_code = EOI_CODE;
|
|---|
| 1318 | wc.code_size = INIT_CODE_SIZE;
|
|---|
| 1319 | max_code = ( 1 << INIT_CODE_SIZE );
|
|---|
| 1320 | for ( j = 0; j < MAX_HASH; j++ )
|
|---|
| 1321 | hashtable[j] = NULL;
|
|---|
| 1322 | }
|
|---|
| 1323 | }
|
|---|
| 1324 | }
|
|---|
| 1325 | /*...e*/
|
|---|
| 1326 | }
|
|---|
| 1327 | }
|
|---|
| 1328 |
|
|---|
| 1329 | free(hashtable);
|
|---|
| 1330 | free(dict);
|
|---|
| 1331 |
|
|---|
| 1332 | if ( lenstring != 0 )
|
|---|
| 1333 | /* Only write tail if no code written for some input */
|
|---|
| 1334 | {
|
|---|
| 1335 | if ( !write_code(tail, &wc) )
|
|---|
| 1336 | return GBM_ERR_WRITE;
|
|---|
| 1337 | if ( ++last_code >= max_code -1 )
|
|---|
| 1338 | /* Next code will be written longer */
|
|---|
| 1339 | wc.code_size++;
|
|---|
| 1340 | }
|
|---|
| 1341 |
|
|---|
| 1342 | if ( !write_code(EOI_CODE, &wc) ||
|
|---|
| 1343 | !flush_code( &wc) )
|
|---|
| 1344 | return GBM_ERR_WRITE;
|
|---|
| 1345 |
|
|---|
| 1346 | return GBM_ERR_OK;
|
|---|
| 1347 | }
|
|---|
| 1348 | /*...e*/
|
|---|
| 1349 |
|
|---|
| 1350 | GBM_ERR tif_w(const char *fn, int fd, const GBM *gbm, const GBMRGB *gbmrgb, const byte *data, const char *opt)
|
|---|
| 1351 | {
|
|---|
| 1352 | BOOLEAN baseline = ( gbm_find_word(opt, "pal1bpp") == NULL );
|
|---|
| 1353 | BOOLEAN lzw = ( gbm_find_word(opt, "lzw" ) != NULL );
|
|---|
| 1354 | IFH *ifh;
|
|---|
| 1355 | IFD *ifd;
|
|---|
| 1356 | long w = gbm->w;
|
|---|
| 1357 | long h = gbm->h;
|
|---|
| 1358 | long stripoffset, stripbytecount;
|
|---|
| 1359 | short samplesperpixel, bitspersample[3], photo, comp;
|
|---|
| 1360 | short colormap[0x100+0x100+0x100];
|
|---|
| 1361 | BOOLEAN ok;
|
|---|
| 1362 | GBM_ERR rc;
|
|---|
| 1363 |
|
|---|
| 1364 | fn=fn; /* Suppress 'unref arg' compiler warning */
|
|---|
| 1365 |
|
|---|
| 1366 | if ( (ifh = make_ifh()) == NULL )
|
|---|
| 1367 | return GBM_ERR_MEM;
|
|---|
| 1368 |
|
|---|
| 1369 | ifd = ifh->ifd;
|
|---|
| 1370 |
|
|---|
| 1371 | if ( gbm->bpp == 1 && baseline )
|
|---|
| 1372 | {
|
|---|
| 1373 | word k0 = (word) gbmrgb[0].r + (word) gbmrgb[0].g + (word) gbmrgb[0].b;
|
|---|
| 1374 | word k1 = (word) gbmrgb[1].r + (word) gbmrgb[1].g + (word) gbmrgb[1].b;
|
|---|
| 1375 | samplesperpixel = 1;
|
|---|
| 1376 | bitspersample[0] = 1;
|
|---|
| 1377 | photo = ( k0 < k1 ) ? PHOTO_BIT1 : PHOTO_BIT0; /* Black is zero : White is zero */
|
|---|
| 1378 | }
|
|---|
| 1379 | else if ( gbm->bpp == 24 )
|
|---|
| 1380 | {
|
|---|
| 1381 | samplesperpixel = 3;
|
|---|
| 1382 | bitspersample[0] =
|
|---|
| 1383 | bitspersample[1] =
|
|---|
| 1384 | bitspersample[2] = 8;
|
|---|
| 1385 | photo = PHOTO_RGB;
|
|---|
| 1386 | }
|
|---|
| 1387 | else
|
|---|
| 1388 | {
|
|---|
| 1389 | samplesperpixel = 1;
|
|---|
| 1390 | bitspersample[0] = (short) gbm->bpp;
|
|---|
| 1391 | photo = PHOTO_PAL;
|
|---|
| 1392 | }
|
|---|
| 1393 |
|
|---|
| 1394 | comp = ( lzw ) ? ENC_LZW : ENC_NONE;
|
|---|
| 1395 |
|
|---|
| 1396 | ok = add_long_tag(ifd, T_IMAGEWIDTH, &w, 1) &&
|
|---|
| 1397 | add_long_tag(ifd, T_IMAGELENGTH, &h, 1) &&
|
|---|
| 1398 | add_long_tag(ifd, T_STRIPOFFSETS, &stripoffset, 1) &&
|
|---|
| 1399 | add_long_tag(ifd, T_STRIPBYTECOUNTS, &stripbytecount, 1) &&
|
|---|
| 1400 | add_short_tag(ifd, T_SAMPLESPERPIXEL, &samplesperpixel, 1) &&
|
|---|
| 1401 | add_short_tag(ifd, T_BITSPERSAMPLE, bitspersample, samplesperpixel) &&
|
|---|
| 1402 | add_short_tag(ifd, T_PHOTOMETRIC, &photo, 1) &&
|
|---|
| 1403 | add_short_tag(ifd, T_COMPRESSION, &comp, 1) &&
|
|---|
| 1404 | user_tag(ifd, "artist=", T_ARTIST, opt, "") &&
|
|---|
| 1405 | user_tag(ifd, "software=", T_MAKE, opt, "") &&
|
|---|
| 1406 | user_tag(ifd, "make=", T_MAKE, opt, "") &&
|
|---|
| 1407 | user_tag(ifd, "model=", T_MODEL, opt, "") &&
|
|---|
| 1408 | user_tag(ifd, "hostcomputer=", T_HOSTCOMPUTER, opt, "") &&
|
|---|
| 1409 | user_tag(ifd, "documentname=", T_DOCNAME, opt, "") &&
|
|---|
| 1410 | user_tag(ifd, "pagename=", T_PAGENAME, opt, "") &&
|
|---|
| 1411 | user_tag(ifd, "imagedescription=", T_DESCRIPTION, opt, "");
|
|---|
| 1412 |
|
|---|
| 1413 | if ( gbm->bpp != 24 )
|
|---|
| 1414 | {
|
|---|
| 1415 | int i, n_cols = (1 << gbm->bpp);
|
|---|
| 1416 |
|
|---|
| 1417 | for ( i = 0; i < n_cols; i++ )
|
|---|
| 1418 | {
|
|---|
| 1419 | short r = (short) gbmrgb[i].r;
|
|---|
| 1420 | short g = (short) gbmrgb[i].g;
|
|---|
| 1421 | short b = (short) gbmrgb[i].b;
|
|---|
| 1422 |
|
|---|
| 1423 | colormap[ i] = ((r << 8) | r);
|
|---|
| 1424 | colormap[ n_cols + i] = ((g << 8) | g);
|
|---|
| 1425 | colormap[2 * n_cols + i] = ((b << 8) | b);
|
|---|
| 1426 | }
|
|---|
| 1427 | if ( gbm->bpp != 1 || !baseline )
|
|---|
| 1428 | ok &= add_short_tag(ifd, T_COLORMAP, colormap, n_cols * 3);
|
|---|
| 1429 | }
|
|---|
| 1430 |
|
|---|
| 1431 | if ( !ok )
|
|---|
| 1432 | {
|
|---|
| 1433 | free_ifh(ifh);
|
|---|
| 1434 | return GBM_ERR_MEM;
|
|---|
| 1435 | }
|
|---|
| 1436 |
|
|---|
| 1437 | if ( !write_ifh_and_ifd(ifh, fd) )
|
|---|
| 1438 | {
|
|---|
| 1439 | free_ifh(ifh);
|
|---|
| 1440 | return GBM_ERR_WRITE;
|
|---|
| 1441 | }
|
|---|
| 1442 |
|
|---|
| 1443 | stripoffset = gbm_file_lseek(fd, 0L, SEEK_CUR);
|
|---|
| 1444 |
|
|---|
| 1445 | if ( lzw )
|
|---|
| 1446 | rc = write_strip_lzw(fd, gbm->w, gbm->h, gbm->bpp, data);
|
|---|
| 1447 | else
|
|---|
| 1448 | rc = write_strip(fd, gbm->w, gbm->h, gbm->bpp, data);
|
|---|
| 1449 |
|
|---|
| 1450 | if ( rc != GBM_ERR_OK )
|
|---|
| 1451 | {
|
|---|
| 1452 | free_ifh(ifh);
|
|---|
| 1453 | return rc;
|
|---|
| 1454 | }
|
|---|
| 1455 |
|
|---|
| 1456 | stripbytecount = gbm_file_lseek(fd, 0L, SEEK_CUR) - stripoffset;
|
|---|
| 1457 |
|
|---|
| 1458 | update_long_tag(ifd, T_STRIPOFFSETS, &stripoffset);
|
|---|
| 1459 | update_long_tag(ifd, T_STRIPBYTECOUNTS, &stripbytecount);
|
|---|
| 1460 |
|
|---|
| 1461 | if ( !update_ifd(ifd, fd) )
|
|---|
| 1462 | {
|
|---|
| 1463 | free_ifh(ifh);
|
|---|
| 1464 | return GBM_ERR_WRITE;
|
|---|
| 1465 | }
|
|---|
| 1466 |
|
|---|
| 1467 | free_ifh(ifh);
|
|---|
| 1468 |
|
|---|
| 1469 | return GBM_ERR_OK;
|
|---|
| 1470 | }
|
|---|
| 1471 | /*...e*/
|
|---|
| 1472 | /*...stif_err:0:*/
|
|---|
| 1473 | const char *tif_err(GBM_ERR rc)
|
|---|
| 1474 | {
|
|---|
| 1475 | switch ( (int) rc )
|
|---|
| 1476 | {
|
|---|
| 1477 | case GBM_ERR_TIF_VERSION:
|
|---|
| 1478 | return "version number not 42";
|
|---|
| 1479 | case GBM_ERR_TIF_N_TAGS:
|
|---|
| 1480 | return "too many tags in file";
|
|---|
| 1481 | case GBM_ERR_TIF_TAG_TYPE:
|
|---|
| 1482 | return "bad tag type";
|
|---|
| 1483 | case GBM_ERR_TIF_HEADER:
|
|---|
| 1484 | return "corrupt header";
|
|---|
| 1485 | case GBM_ERR_TIF_MISSING_TAG:
|
|---|
| 1486 | return "ImageWidth, ImageLength or StripOffsets tag missing";
|
|---|
| 1487 | case GBM_ERR_TIF_SPP_BIT:
|
|---|
| 1488 | return "SamplesPerPixel tag must be 1 for bitmap or greyscale file";
|
|---|
| 1489 | case GBM_ERR_TIF_BPS_BIT:
|
|---|
| 1490 | return "BitsPerSample tag must be 1,4 or 8 for bitmap or greyscale file";
|
|---|
| 1491 | case GBM_ERR_TIF_SPP_RGB:
|
|---|
| 1492 | return "SamplesPerPixel tag must be 3 or more for RGB file";
|
|---|
| 1493 | case GBM_ERR_TIF_BPS_RGB:
|
|---|
| 1494 | return "BitsPerSample tag must be 8 for RGB file";
|
|---|
| 1495 | case GBM_ERR_TIF_SPP_PAL:
|
|---|
| 1496 | return "SamplesPerPixel tag must be 1 for palettised file";
|
|---|
| 1497 | case GBM_ERR_TIF_BPS_PAL:
|
|---|
| 1498 | return "BitsPerSample tag must be 1,4 or 8 for palettised file";
|
|---|
| 1499 | case GBM_ERR_TIF_SPP_CMYK:
|
|---|
| 1500 | return "SamplesPerPixel tag must be 4 for CMYK file";
|
|---|
| 1501 | case GBM_ERR_TIF_BPS_CMYK:
|
|---|
| 1502 | return "BitsPerSample tag must be 8 for CMYK file";
|
|---|
| 1503 | case GBM_ERR_TIF_COMP_1D_MH:
|
|---|
| 1504 | return "Compression tag is CCITT 1D Modified Huffman, not supported";
|
|---|
| 1505 | case GBM_ERR_TIF_COMP_T4:
|
|---|
| 1506 | return "Compression tag is CCITT T.4 G3 Facsimile, not supported";
|
|---|
| 1507 | case GBM_ERR_TIF_COMP_T6:
|
|---|
| 1508 | return "Compression tag is CCITT T.6 G4 Facsimile, not supported";
|
|---|
| 1509 | case GBM_ERR_TIF_COMP:
|
|---|
| 1510 | return "Compression tag not uncompressed, PackBits or LZW, not supported";
|
|---|
| 1511 | case GBM_ERR_TIF_COLORMAP:
|
|---|
| 1512 | return "ColorMap tag missing";
|
|---|
| 1513 | case GBM_ERR_TIF_CORRUPT:
|
|---|
| 1514 | return "encoded data is corrupt";
|
|---|
| 1515 | case GBM_ERR_TIF_PREDICTOR:
|
|---|
| 1516 | return "Predictor tag bad";
|
|---|
| 1517 | case GBM_ERR_TIF_PHOTO_TRANS:
|
|---|
| 1518 | return "PhotometricInterpretation tag is transparency mask, not supported";
|
|---|
| 1519 | case GBM_ERR_TIF_PHOTO_Y_Cb_Cr:
|
|---|
| 1520 | return "PhotometricInterpreation tag is Y-Cb-Cr colour space, not supported";
|
|---|
| 1521 | case GBM_ERR_TIF_PHOTO:
|
|---|
| 1522 | return "PhotometricInterpretation tag unsupported/bad";
|
|---|
| 1523 | case GBM_ERR_TIF_FILLORDER:
|
|---|
| 1524 | return "FillOrder tag must be 1";
|
|---|
| 1525 | case GBM_ERR_TIF_PLANARCONFIG_1:
|
|---|
| 1526 | return "PlanarConfiguration tag must be 1 for non RGB files";
|
|---|
| 1527 | case GBM_ERR_TIF_PLANARCONFIG_12:
|
|---|
| 1528 | return "PlanarConfiguration tag must be 1 or 2 for RGB files";
|
|---|
| 1529 | case GBM_ERR_TIF_INKSET:
|
|---|
| 1530 | return "InkSet tag indicates non-CMYK colour seperations";
|
|---|
| 1531 | case GBM_ERR_TIF_ORIENT:
|
|---|
| 1532 | return "Orientation tag must be 1 or 4";
|
|---|
| 1533 | case GBM_ERR_TIF_INDEX:
|
|---|
| 1534 | return "less bitmaps in file than index requested";
|
|---|
| 1535 | }
|
|---|
| 1536 | return NULL;
|
|---|
| 1537 | }
|
|---|
| 1538 | /*...e*/
|
|---|