1/* $Id: tif_getimage.c 276 2010-06-30 12:18:30Z nijtmans $ */ 2 3/* 4 * Copyright (c) 1991-1997 Sam Leffler 5 * Copyright (c) 1991-1997 Silicon Graphics, Inc. 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and 8 * its documentation for any purpose is hereby granted without fee, provided 9 * that (i) the above copyright notices and this permission notice appear in 10 * all copies of the software and related documentation, and (ii) the names of 11 * Sam Leffler and Silicon Graphics may not be used in any advertising or 12 * publicity relating to the software without the specific, prior written 13 * permission of Sam Leffler and Silicon Graphics. 14 * 15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 18 * 19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR 20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, 21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24 * OF THIS SOFTWARE. 25 */ 26 27/* 28 * TIFF Library 29 * 30 * Read and return a packed RGBA image. 31 */ 32#include "tiffiop.h" 33#include <stdio.h> 34 35static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32); 36static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); 37static int gtStripContig(TIFFRGBAImage*, uint32*, uint32, uint32); 38static int gtStripSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); 39static int PickContigCase(TIFFRGBAImage*); 40static int PickSeparateCase(TIFFRGBAImage*); 41static const char photoTag[] = "PhotometricInterpretation"; 42 43/* 44 * Helper constants used in Orientation tag handling 45 */ 46#define FLIP_VERTICALLY 0x01 47#define FLIP_HORIZONTALLY 0x02 48 49/* 50 * Color conversion constants. We will define display types here. 51 */ 52 53TIFFDisplay display_sRGB = { 54 { /* XYZ -> luminance matrix */ 55 { 3.2410F, -1.5374F, -0.4986F }, 56 { -0.9692F, 1.8760F, 0.0416F }, 57 { 0.0556F, -0.2040F, 1.0570F } 58 }, 59 100.0F, 100.0F, 100.0F, /* Light o/p for reference white */ 60 255, 255, 255, /* Pixel values for ref. white */ 61 1.0F, 1.0F, 1.0F, /* Residual light o/p for black pixel */ 62 2.4F, 2.4F, 2.4F, /* Gamma values for the three guns */ 63}; 64 65/* 66 * Check the image to see if TIFFReadRGBAImage can deal with it. 67 * 1/0 is returned according to whether or not the image can 68 * be handled. If 0 is returned, emsg contains the reason 69 * why it is being rejected. 70 */ 71int 72TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) 73{ 74 TIFFDirectory* td = &tif->tif_dir; 75 uint16 photometric; 76 int colorchannels; 77 78 if (!tif->tif_decodestatus) { 79 sprintf(emsg, "Sorry, requested compression method is not configured"); 80 return (0); 81 } 82 switch (td->td_bitspersample) { 83 case 1: 84 case 2: 85 case 4: 86 case 8: 87 case 16: 88 break; 89 default: 90 sprintf(emsg, "Sorry, can not handle images with %d-bit samples", 91 td->td_bitspersample); 92 return (0); 93 } 94 colorchannels = td->td_samplesperpixel - td->td_extrasamples; 95 if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) { 96 switch (colorchannels) { 97 case 1: 98 photometric = PHOTOMETRIC_MINISBLACK; 99 break; 100 case 3: 101 photometric = PHOTOMETRIC_RGB; 102 break; 103 default: 104 sprintf(emsg, "Missing needed %s tag", photoTag); 105 return (0); 106 } 107 } 108 switch (photometric) { 109 case PHOTOMETRIC_MINISWHITE: 110 case PHOTOMETRIC_MINISBLACK: 111 case PHOTOMETRIC_PALETTE: 112 if (td->td_planarconfig == PLANARCONFIG_CONTIG 113 && td->td_samplesperpixel != 1 114 && td->td_bitspersample < 8 ) { 115 sprintf(emsg, 116 "Sorry, can not handle contiguous data with %s=%d, " 117 "and %s=%d and Bits/Sample=%d", 118 photoTag, photometric, 119 "Samples/pixel", td->td_samplesperpixel, 120 td->td_bitspersample); 121 return (0); 122 } 123 /* 124 * We should likely validate that any extra samples are either 125 * to be ignored, or are alpha, and if alpha we should try to use 126 * them. But for now we won't bother with this. 127 */ 128 break; 129 case PHOTOMETRIC_YCBCR: 130 /* 131 * TODO: if at all meaningful and useful, make more complete 132 * support check here, or better still, refactor to let supporting 133 * code decide whether there is support and what meaningfull 134 * error to return 135 */ 136 break; 137 case PHOTOMETRIC_RGB: 138 if (colorchannels < 3) { 139 sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", 140 "Color channels", colorchannels); 141 return (0); 142 } 143 break; 144 case PHOTOMETRIC_SEPARATED: 145 { 146 uint16 inkset; 147 TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); 148 if (inkset != INKSET_CMYK) { 149 sprintf(emsg, 150 "Sorry, can not handle separated image with %s=%d", 151 "InkSet", inkset); 152 return 0; 153 } 154 if (td->td_samplesperpixel < 4) { 155 sprintf(emsg, 156 "Sorry, can not handle separated image with %s=%d", 157 "Samples/pixel", td->td_samplesperpixel); 158 return 0; 159 } 160 break; 161 } 162 case PHOTOMETRIC_LOGL: 163 if (td->td_compression != COMPRESSION_SGILOG) { 164 sprintf(emsg, "Sorry, LogL data must have %s=%d", 165 "Compression", COMPRESSION_SGILOG); 166 return (0); 167 } 168 break; 169 case PHOTOMETRIC_LOGLUV: 170 if (td->td_compression != COMPRESSION_SGILOG && 171 td->td_compression != COMPRESSION_SGILOG24) { 172 sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", 173 "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); 174 return (0); 175 } 176 if (td->td_planarconfig != PLANARCONFIG_CONTIG) { 177 sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", 178 "Planarconfiguration", td->td_planarconfig); 179 return (0); 180 } 181 break; 182 case PHOTOMETRIC_CIELAB: 183 break; 184 default: 185 sprintf(emsg, "Sorry, can not handle image with %s=%d", 186 photoTag, photometric); 187 return (0); 188 } 189 return (1); 190} 191 192void 193TIFFRGBAImageEnd(TIFFRGBAImage* img) 194{ 195 if (img->Map) 196 _TIFFfree(img->Map), img->Map = NULL; 197 if (img->BWmap) 198 _TIFFfree(img->BWmap), img->BWmap = NULL; 199 if (img->PALmap) 200 _TIFFfree(img->PALmap), img->PALmap = NULL; 201 if (img->ycbcr) 202 _TIFFfree(img->ycbcr), img->ycbcr = NULL; 203 if (img->cielab) 204 _TIFFfree(img->cielab), img->cielab = NULL; 205 if( img->redcmap ) { 206 _TIFFfree( img->redcmap ); 207 _TIFFfree( img->greencmap ); 208 _TIFFfree( img->bluecmap ); 209 } 210} 211 212static int 213isCCITTCompression(TIFF* tif) 214{ 215 uint16 compress; 216 TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress); 217 return (compress == COMPRESSION_CCITTFAX3 || 218 compress == COMPRESSION_CCITTFAX4 || 219 compress == COMPRESSION_CCITTRLE || 220 compress == COMPRESSION_CCITTRLEW); 221} 222 223int 224TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) 225{ 226 uint16* sampleinfo; 227 uint16 extrasamples; 228 uint16 planarconfig; 229 uint16 compress; 230 int colorchannels; 231 uint16 *red_orig, *green_orig, *blue_orig; 232 int n_color; 233 234 /* Initialize to normal values */ 235 img->row_offset = 0; 236 img->col_offset = 0; 237 img->redcmap = NULL; 238 img->greencmap = NULL; 239 img->bluecmap = NULL; 240 img->req_orientation = ORIENTATION_BOTLEFT; /* It is the default */ 241 242 img->tif = tif; 243 img->stoponerr = stop; 244 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample); 245 switch (img->bitspersample) { 246 case 1: 247 case 2: 248 case 4: 249 case 8: 250 case 16: 251 break; 252 default: 253 sprintf(emsg, "Sorry, can not handle images with %d-bit samples", 254 img->bitspersample); 255 return (0); 256 } 257 img->alpha = 0; 258 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel); 259 TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, 260 &extrasamples, &sampleinfo); 261 if (extrasamples >= 1) 262 { 263 switch (sampleinfo[0]) { 264 case EXTRASAMPLE_UNSPECIFIED: /* Workaround for some images without */ 265 if (img->samplesperpixel > 3) /* correct info about alpha channel */ 266 img->alpha = EXTRASAMPLE_ASSOCALPHA; 267 break; 268 case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */ 269 case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */ 270 img->alpha = sampleinfo[0]; 271 break; 272 } 273 } 274 275#ifdef DEFAULT_EXTRASAMPLE_AS_ALPHA 276 if( !TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) 277 img->photometric = PHOTOMETRIC_MINISWHITE; 278 279 if( extrasamples == 0 280 && img->samplesperpixel == 4 281 && img->photometric == PHOTOMETRIC_RGB ) 282 { 283 img->alpha = EXTRASAMPLE_ASSOCALPHA; 284 extrasamples = 1; 285 } 286#endif 287 288 colorchannels = img->samplesperpixel - extrasamples; 289 TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress); 290 TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); 291 if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) { 292 switch (colorchannels) { 293 case 1: 294 if (isCCITTCompression(tif)) 295 img->photometric = PHOTOMETRIC_MINISWHITE; 296 else 297 img->photometric = PHOTOMETRIC_MINISBLACK; 298 break; 299 case 3: 300 img->photometric = PHOTOMETRIC_RGB; 301 break; 302 default: 303 sprintf(emsg, "Missing needed %s tag", photoTag); 304 return (0); 305 } 306 } 307 switch (img->photometric) { 308 case PHOTOMETRIC_PALETTE: 309 if (!TIFFGetField(tif, TIFFTAG_COLORMAP, 310 &red_orig, &green_orig, &blue_orig)) { 311 sprintf(emsg, "Missing required \"Colormap\" tag"); 312 return (0); 313 } 314 315 /* copy the colormaps so we can modify them */ 316 n_color = (1L << img->bitspersample); 317 img->redcmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); 318 img->greencmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); 319 img->bluecmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); 320 if( !img->redcmap || !img->greencmap || !img->bluecmap ) { 321 sprintf(emsg, "Out of memory for colormap copy"); 322 return (0); 323 } 324 325 _TIFFmemcpy( img->redcmap, red_orig, n_color * 2 ); 326 _TIFFmemcpy( img->greencmap, green_orig, n_color * 2 ); 327 _TIFFmemcpy( img->bluecmap, blue_orig, n_color * 2 ); 328 329 /* fall thru... */ 330 case PHOTOMETRIC_MINISWHITE: 331 case PHOTOMETRIC_MINISBLACK: 332 if (planarconfig == PLANARCONFIG_CONTIG 333 && img->samplesperpixel != 1 334 && img->bitspersample < 8 ) { 335 sprintf(emsg, 336 "Sorry, can not handle contiguous data with %s=%d, " 337 "and %s=%d and Bits/Sample=%d", 338 photoTag, img->photometric, 339 "Samples/pixel", img->samplesperpixel, 340 img->bitspersample); 341 return (0); 342 } 343 break; 344 case PHOTOMETRIC_YCBCR: 345 /* It would probably be nice to have a reality check here. */ 346 if (planarconfig == PLANARCONFIG_CONTIG) 347 /* can rely on libjpeg to convert to RGB */ 348 /* XXX should restore current state on exit */ 349 switch (compress) { 350 case COMPRESSION_JPEG: 351 /* 352 * TODO: when complete tests verify complete desubsampling 353 * and YCbCr handling, remove use of TIFFTAG_JPEGCOLORMODE in 354 * favor of tif_getimage.c native handling 355 */ 356 TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); 357 img->photometric = PHOTOMETRIC_RGB; 358 break; 359 default: 360 /* do nothing */; 361 break; 362 } 363 /* 364 * TODO: if at all meaningful and useful, make more complete 365 * support check here, or better still, refactor to let supporting 366 * code decide whether there is support and what meaningfull 367 * error to return 368 */ 369 break; 370 case PHOTOMETRIC_RGB: 371 if (colorchannels < 3) { 372 sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", 373 "Color channels", colorchannels); 374 return (0); 375 } 376 break; 377 case PHOTOMETRIC_SEPARATED: 378 { 379 uint16 inkset; 380 TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); 381 if (inkset != INKSET_CMYK) { 382 sprintf(emsg, "Sorry, can not handle separated image with %s=%d", 383 "InkSet", inkset); 384 return (0); 385 } 386 if (img->samplesperpixel < 4) { 387 sprintf(emsg, "Sorry, can not handle separated image with %s=%d", 388 "Samples/pixel", img->samplesperpixel); 389 return (0); 390 } 391 } 392 break; 393 case PHOTOMETRIC_LOGL: 394 if (compress != COMPRESSION_SGILOG) { 395 sprintf(emsg, "Sorry, LogL data must have %s=%d", 396 "Compression", COMPRESSION_SGILOG); 397 return (0); 398 } 399 TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); 400 img->photometric = PHOTOMETRIC_MINISBLACK; /* little white lie */ 401 img->bitspersample = 8; 402 break; 403 case PHOTOMETRIC_LOGLUV: 404 if (compress != COMPRESSION_SGILOG && compress != COMPRESSION_SGILOG24) { 405 sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", 406 "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); 407 return (0); 408 } 409 if (planarconfig != PLANARCONFIG_CONTIG) { 410 sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", 411 "Planarconfiguration", planarconfig); 412 return (0); 413 } 414 TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); 415 img->photometric = PHOTOMETRIC_RGB; /* little white lie */ 416 img->bitspersample = 8; 417 break; 418 case PHOTOMETRIC_CIELAB: 419 break; 420 default: 421 sprintf(emsg, "Sorry, can not handle image with %s=%d", 422 photoTag, img->photometric); 423 return (0); 424 } 425 img->Map = NULL; 426 img->BWmap = NULL; 427 img->PALmap = NULL; 428 img->ycbcr = NULL; 429 img->cielab = NULL; 430 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width); 431 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height); 432 TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation); 433 img->isContig = 434 !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1); 435 if (img->isContig) { 436 if (!PickContigCase(img)) { 437 sprintf(emsg, "Sorry, can not handle image"); 438 return 0; 439 } 440 } else { 441 if (!PickSeparateCase(img)) { 442 sprintf(emsg, "Sorry, can not handle image"); 443 return 0; 444 } 445 } 446 return 1; 447} 448 449int 450TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) 451{ 452 if (img->get == NULL) { 453 TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup"); 454 return (0); 455 } 456 if (img->put.any == NULL) { 457 TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), 458 "No \"put\" routine setupl; probably can not handle image format"); 459 return (0); 460 } 461 return (*img->get)(img, raster, w, h); 462} 463 464/* 465 * Read the specified image into an ABGR-format rastertaking in account 466 * specified orientation. 467 */ 468int 469TIFFReadRGBAImageOriented(TIFF* tif, 470 uint32 rwidth, uint32 rheight, uint32* raster, 471 int orientation, int stop) 472{ 473 char emsg[1024] = ""; 474 TIFFRGBAImage img; 475 int ok; 476 477 if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop, emsg)) { 478 img.req_orientation = orientation; 479 /* XXX verify rwidth and rheight against width and height */ 480 ok = TIFFRGBAImageGet(&img, raster+(rheight-img.height)*rwidth, 481 rwidth, img.height); 482 TIFFRGBAImageEnd(&img); 483 } else { 484 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); 485 ok = 0; 486 } 487 return (ok); 488} 489 490/* 491 * Read the specified image into an ABGR-format raster. Use bottom left 492 * origin for raster by default. 493 */ 494int 495TIFFReadRGBAImage(TIFF* tif, 496 uint32 rwidth, uint32 rheight, uint32* raster, int stop) 497{ 498 return TIFFReadRGBAImageOriented(tif, rwidth, rheight, raster, 499 ORIENTATION_BOTLEFT, stop); 500} 501 502static int 503setorientation(TIFFRGBAImage* img) 504{ 505 switch (img->orientation) { 506 case ORIENTATION_TOPLEFT: 507 case ORIENTATION_LEFTTOP: 508 if (img->req_orientation == ORIENTATION_TOPRIGHT || 509 img->req_orientation == ORIENTATION_RIGHTTOP) 510 return FLIP_HORIZONTALLY; 511 else if (img->req_orientation == ORIENTATION_BOTRIGHT || 512 img->req_orientation == ORIENTATION_RIGHTBOT) 513 return FLIP_HORIZONTALLY | FLIP_VERTICALLY; 514 else if (img->req_orientation == ORIENTATION_BOTLEFT || 515 img->req_orientation == ORIENTATION_LEFTBOT) 516 return FLIP_VERTICALLY; 517 else 518 return 0; 519 case ORIENTATION_TOPRIGHT: 520 case ORIENTATION_RIGHTTOP: 521 if (img->req_orientation == ORIENTATION_TOPLEFT || 522 img->req_orientation == ORIENTATION_LEFTTOP) 523 return FLIP_HORIZONTALLY; 524 else if (img->req_orientation == ORIENTATION_BOTRIGHT || 525 img->req_orientation == ORIENTATION_RIGHTBOT) 526 return FLIP_VERTICALLY; 527 else if (img->req_orientation == ORIENTATION_BOTLEFT || 528 img->req_orientation == ORIENTATION_LEFTBOT) 529 return FLIP_HORIZONTALLY | FLIP_VERTICALLY; 530 else 531 return 0; 532 case ORIENTATION_BOTRIGHT: 533 case ORIENTATION_RIGHTBOT: 534 if (img->req_orientation == ORIENTATION_TOPLEFT || 535 img->req_orientation == ORIENTATION_LEFTTOP) 536 return FLIP_HORIZONTALLY | FLIP_VERTICALLY; 537 else if (img->req_orientation == ORIENTATION_TOPRIGHT || 538 img->req_orientation == ORIENTATION_RIGHTTOP) 539 return FLIP_VERTICALLY; 540 else if (img->req_orientation == ORIENTATION_BOTLEFT || 541 img->req_orientation == ORIENTATION_LEFTBOT) 542 return FLIP_HORIZONTALLY; 543 else 544 return 0; 545 case ORIENTATION_BOTLEFT: 546 case ORIENTATION_LEFTBOT: 547 if (img->req_orientation == ORIENTATION_TOPLEFT || 548 img->req_orientation == ORIENTATION_LEFTTOP) 549 return FLIP_VERTICALLY; 550 else if (img->req_orientation == ORIENTATION_TOPRIGHT || 551 img->req_orientation == ORIENTATION_RIGHTTOP) 552 return FLIP_HORIZONTALLY | FLIP_VERTICALLY; 553 else if (img->req_orientation == ORIENTATION_BOTRIGHT || 554 img->req_orientation == ORIENTATION_RIGHTBOT) 555 return FLIP_HORIZONTALLY; 556 else 557 return 0; 558 default: /* NOTREACHED */ 559 return 0; 560 } 561} 562 563/* 564 * Get an tile-organized image that has 565 * PlanarConfiguration contiguous if SamplesPerPixel > 1 566 * or 567 * SamplesPerPixel == 1 568 */ 569static int 570gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) 571{ 572 TIFF* tif = img->tif; 573 tileContigRoutine put = img->put.contig; 574 uint32 col, row, y, rowstoread; 575 uint32 pos; 576 uint32 tw, th; 577 unsigned char* buf; 578 int32 fromskew, toskew; 579 uint32 nrow; 580 int ret = 1, flip; 581 582 buf = (unsigned char*) _TIFFmalloc(TIFFTileSize(tif)); 583 if (buf == 0) { 584 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); 585 return (0); 586 } 587 _TIFFmemset(buf, 0, TIFFTileSize(tif)); 588 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); 589 TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); 590 591 flip = setorientation(img); 592 if (flip & FLIP_VERTICALLY) { 593 y = h - 1; 594 toskew = -(int32)(tw + w); 595 } 596 else { 597 y = 0; 598 toskew = -(int32)(tw - w); 599 } 600 601 for (row = 0; row < h; row += nrow) 602 { 603 rowstoread = th - (row + img->row_offset) % th; 604 nrow = (row + rowstoread > h ? h - row : rowstoread); 605 for (col = 0; col < w; col += tw) 606 { 607 if (TIFFReadTile(tif, buf, col+img->col_offset, 608 row+img->row_offset, 0, 0) < 0 && img->stoponerr) 609 { 610 ret = 0; 611 break; 612 } 613 614 pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); 615 616 if (col + tw > w) 617 { 618 /* 619 * Tile is clipped horizontally. Calculate 620 * visible portion and skewing factors. 621 */ 622 uint32 npix = w - col; 623 fromskew = tw - npix; 624 (*put)(img, raster+y*w+col, col, y, 625 npix, nrow, fromskew, toskew + fromskew, buf + pos); 626 } 627 else 628 { 629 (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf + pos); 630 } 631 } 632 633 y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); 634 } 635 _TIFFfree(buf); 636 637 if (flip & FLIP_HORIZONTALLY) { 638 uint32 line; 639 640 for (line = 0; line < h; line++) { 641 uint32 *left = raster + (line * w); 642 uint32 *right = left + w - 1; 643 644 while ( left < right ) { 645 uint32 temp = *left; 646 *left = *right; 647 *right = temp; 648 left++, right--; 649 } 650 } 651 } 652 653 return (ret); 654} 655 656/* 657 * Get an tile-organized image that has 658 * SamplesPerPixel > 1 659 * PlanarConfiguration separated 660 * We assume that all such images are RGB. 661 */ 662static int 663gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) 664{ 665 TIFF* tif = img->tif; 666 tileSeparateRoutine put = img->put.separate; 667 uint32 col, row, y, rowstoread; 668 uint32 pos; 669 uint32 tw, th; 670 unsigned char* buf; 671 unsigned char* p0; 672 unsigned char* p1; 673 unsigned char* p2; 674 unsigned char* pa; 675 tsize_t tilesize; 676 int32 fromskew, toskew; 677 int alpha = img->alpha; 678 uint32 nrow; 679 int ret = 1, flip; 680 681 tilesize = TIFFTileSize(tif); 682 buf = (unsigned char*) _TIFFmalloc((alpha?4:3)*tilesize); 683 if (buf == 0) { 684 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); 685 return (0); 686 } 687 _TIFFmemset(buf, 0, (alpha?4:3)*tilesize); 688 p0 = buf; 689 p1 = p0 + tilesize; 690 p2 = p1 + tilesize; 691 pa = (alpha?(p2+tilesize):NULL); 692 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); 693 TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); 694 695 flip = setorientation(img); 696 if (flip & FLIP_VERTICALLY) { 697 y = h - 1; 698 toskew = -(int32)(tw + w); 699 } 700 else { 701 y = 0; 702 toskew = -(int32)(tw - w); 703 } 704 705 for (row = 0; row < h; row += nrow) 706 { 707 rowstoread = th - (row + img->row_offset) % th; 708 nrow = (row + rowstoread > h ? h - row : rowstoread); 709 for (col = 0; col < w; col += tw) 710 { 711 if (TIFFReadTile(tif, p0, col+img->col_offset, 712 row+img->row_offset,0,0) < 0 && img->stoponerr) 713 { 714 ret = 0; 715 break; 716 } 717 if (TIFFReadTile(tif, p1, col+img->col_offset, 718 row+img->row_offset,0,1) < 0 && img->stoponerr) 719 { 720 ret = 0; 721 break; 722 } 723 if (TIFFReadTile(tif, p2, col+img->col_offset, 724 row+img->row_offset,0,2) < 0 && img->stoponerr) 725 { 726 ret = 0; 727 break; 728 } 729 if (alpha) 730 { 731 if (TIFFReadTile(tif,pa,col+img->col_offset, 732 row+img->row_offset,0,3) < 0 && img->stoponerr) 733 { 734 ret = 0; 735 break; 736 } 737 } 738 739 pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); 740 741 if (col + tw > w) 742 { 743 /* 744 * Tile is clipped horizontally. Calculate 745 * visible portion and skewing factors. 746 */ 747 uint32 npix = w - col; 748 fromskew = tw - npix; 749 (*put)(img, raster+y*w+col, col, y, 750 npix, nrow, fromskew, toskew + fromskew, 751 p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); 752 } else { 753 (*put)(img, raster+y*w+col, col, y, 754 tw, nrow, 0, toskew, p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); 755 } 756 } 757 758 y += (flip & FLIP_VERTICALLY ?-(int32) nrow : (int32) nrow); 759 } 760 761 if (flip & FLIP_HORIZONTALLY) { 762 uint32 line; 763 764 for (line = 0; line < h; line++) { 765 uint32 *left = raster + (line * w); 766 uint32 *right = left + w - 1; 767 768 while ( left < right ) { 769 uint32 temp = *left; 770 *left = *right; 771 *right = temp; 772 left++, right--; 773 } 774 } 775 } 776 777 _TIFFfree(buf); 778 return (ret); 779} 780 781/* 782 * Get a strip-organized image that has 783 * PlanarConfiguration contiguous if SamplesPerPixel > 1 784 * or 785 * SamplesPerPixel == 1 786 */ 787static int 788gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) 789{ 790 TIFF* tif = img->tif; 791 tileContigRoutine put = img->put.contig; 792 uint32 row, y, nrow, nrowsub, rowstoread; 793 uint32 pos; 794 unsigned char* buf; 795 uint32 rowsperstrip; 796 uint16 subsamplinghor,subsamplingver; 797 uint32 imagewidth = img->width; 798 tsize_t scanline; 799 int32 fromskew, toskew; 800 int ret = 1, flip; 801 802 buf = (unsigned char*) _TIFFmalloc(TIFFStripSize(tif)); 803 if (buf == 0) { 804 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer"); 805 return (0); 806 } 807 _TIFFmemset(buf, 0, TIFFStripSize(tif)); 808 809 flip = setorientation(img); 810 if (flip & FLIP_VERTICALLY) { 811 y = h - 1; 812 toskew = -(int32)(w + w); 813 } else { 814 y = 0; 815 toskew = -(int32)(w - w); 816 } 817 818 TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); 819 TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver); 820 scanline = TIFFNewScanlineSize(tif); 821 fromskew = (w < imagewidth ? imagewidth - w : 0); 822 for (row = 0; row < h; row += nrow) 823 { 824 rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; 825 nrow = (row + rowstoread > h ? h - row : rowstoread); 826 nrowsub = nrow; 827 if ((nrowsub%subsamplingver)!=0) 828 nrowsub+=subsamplingver-nrowsub%subsamplingver; 829 if (TIFFReadEncodedStrip(tif, 830 TIFFComputeStrip(tif,row+img->row_offset, 0), 831 buf, 832 ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline) < 0 833 && img->stoponerr) 834 { 835 ret = 0; 836 break; 837 } 838 839 pos = ((row + img->row_offset) % rowsperstrip) * scanline; 840 (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf + pos); 841 y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); 842 } 843 844 if (flip & FLIP_HORIZONTALLY) { 845 uint32 line; 846 847 for (line = 0; line < h; line++) { 848 uint32 *left = raster + (line * w); 849 uint32 *right = left + w - 1; 850 851 while ( left < right ) { 852 uint32 temp = *left; 853 *left = *right; 854 *right = temp; 855 left++, right--; 856 } 857 } 858 } 859 860 _TIFFfree(buf); 861 return (ret); 862} 863 864/* 865 * Get a strip-organized image with 866 * SamplesPerPixel > 1 867 * PlanarConfiguration separated 868 * We assume that all such images are RGB. 869 */ 870static int 871gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) 872{ 873 TIFF* tif = img->tif; 874 tileSeparateRoutine put = img->put.separate; 875 unsigned char *buf; 876 unsigned char *p0, *p1, *p2, *pa; 877 uint32 row, y, nrow, rowstoread; 878 uint32 pos; 879 tsize_t scanline; 880 uint32 rowsperstrip, offset_row; 881 uint32 imagewidth = img->width; 882 tsize_t stripsize; 883 int32 fromskew, toskew; 884 int alpha = img->alpha; 885 int ret = 1, flip; 886 887 stripsize = TIFFStripSize(tif); 888 p0 = buf = (unsigned char *)_TIFFmalloc((alpha?4:3)*stripsize); 889 if (buf == 0) { 890 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); 891 return (0); 892 } 893 _TIFFmemset(buf, 0, (alpha?4:3)*stripsize); 894 p1 = p0 + stripsize; 895 p2 = p1 + stripsize; 896 pa = (alpha?(p2+stripsize):NULL); 897 898 flip = setorientation(img); 899 if (flip & FLIP_VERTICALLY) { 900 y = h - 1; 901 toskew = -(int32)(w + w); 902 } 903 else { 904 y = 0; 905 toskew = -(int32)(w - w); 906 } 907 908 TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); 909 scanline = TIFFScanlineSize(tif); 910 fromskew = (w < imagewidth ? imagewidth - w : 0); 911 for (row = 0; row < h; row += nrow) 912 { 913 rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; 914 nrow = (row + rowstoread > h ? h - row : rowstoread); 915 offset_row = row + img->row_offset; 916 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0), 917 p0, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 918 && img->stoponerr) 919 { 920 ret = 0; 921 break; 922 } 923 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), 924 p1, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 925 && img->stoponerr) 926 { 927 ret = 0; 928 break; 929 } 930 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), 931 p2, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 932 && img->stoponerr) 933 { 934 ret = 0; 935 break; 936 } 937 if (alpha) 938 { 939 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 3), 940 pa, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 941 && img->stoponerr) 942 { 943 ret = 0; 944 break; 945 } 946 } 947 948 pos = ((row + img->row_offset) % rowsperstrip) * scanline; 949 (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, p0 + pos, p1 + pos, 950 p2 + pos, (alpha?(pa+pos):NULL)); 951 y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); 952 } 953 954 if (flip & FLIP_HORIZONTALLY) { 955 uint32 line; 956 957 for (line = 0; line < h; line++) { 958 uint32 *left = raster + (line * w); 959 uint32 *right = left + w - 1; 960 961 while ( left < right ) { 962 uint32 temp = *left; 963 *left = *right; 964 *right = temp; 965 left++, right--; 966 } 967 } 968 } 969 970 _TIFFfree(buf); 971 return (ret); 972} 973 974/* 975 * The following routines move decoded data returned 976 * from the TIFF library into rasters filled with packed 977 * ABGR pixels (i.e. suitable for passing to lrecwrite.) 978 * 979 * The routines have been created according to the most 980 * important cases and optimized. PickContigCase and 981 * PickSeparateCase analyze the parameters and select 982 * the appropriate "get" and "put" routine to use. 983 */ 984#define REPEAT8(op) REPEAT4(op); REPEAT4(op) 985#define REPEAT4(op) REPEAT2(op); REPEAT2(op) 986#define REPEAT2(op) op; op 987#define CASE8(x,op) \ 988 switch (x) { \ 989 case 7: op; case 6: op; case 5: op; \ 990 case 4: op; case 3: op; case 2: op; \ 991 case 1: op; \ 992 } 993#define CASE4(x,op) switch (x) { case 3: op; case 2: op; case 1: op; } 994#define NOP 995 996#define UNROLL8(w, op1, op2) { \ 997 uint32 _x; \ 998 for (_x = w; _x >= 8; _x -= 8) { \ 999 op1; \ 1000 REPEAT8(op2); \ 1001 } \ 1002 if (_x > 0) { \ 1003 op1; \ 1004 CASE8(_x,op2); \ 1005 } \ 1006} 1007#define UNROLL4(w, op1, op2) { \ 1008 uint32 _x; \ 1009 for (_x = w; _x >= 4; _x -= 4) { \ 1010 op1; \ 1011 REPEAT4(op2); \ 1012 } \ 1013 if (_x > 0) { \ 1014 op1; \ 1015 CASE4(_x,op2); \ 1016 } \ 1017} 1018#define UNROLL2(w, op1, op2) { \ 1019 uint32 _x; \ 1020 for (_x = w; _x >= 2; _x -= 2) { \ 1021 op1; \ 1022 REPEAT2(op2); \ 1023 } \ 1024 if (_x) { \ 1025 op1; \ 1026 op2; \ 1027 } \ 1028} 1029 1030#define SKEW(r,g,b,skew) { r += skew; g += skew; b += skew; } 1031#define SKEW4(r,g,b,a,skew) { r += skew; g += skew; b += skew; a+= skew; } 1032 1033#define A1 (((uint32)0xffL)<<24) 1034#define PACK(r,g,b) \ 1035 ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|A1) 1036#define PACK4(r,g,b,a) \ 1037 ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|((uint32)(a)<<24)) 1038#define W2B(v) (((v)>>8)&0xff) 1039#define PACKW(r,g,b) \ 1040 ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|A1) 1041#define PACKW4(r,g,b,a) \ 1042 ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|((uint32)W2B(a)<<24)) 1043 1044#define DECLAREContigPutFunc(name) \ 1045static void name(\ 1046 TIFFRGBAImage* img, \ 1047 uint32* cp, \ 1048 uint32 x, uint32 y, \ 1049 uint32 w, uint32 h, \ 1050 int32 fromskew, int32 toskew, \ 1051 unsigned char* pp \ 1052) 1053 1054/* 1055 * 8-bit palette => colormap/RGB 1056 */ 1057DECLAREContigPutFunc(put8bitcmaptile) 1058{ 1059 uint32** PALmap = img->PALmap; 1060 int samplesperpixel = img->samplesperpixel; 1061 1062 (void) y; 1063 while (h-- > 0) { 1064 for (x = w; x-- > 0;) 1065 { 1066 *cp++ = PALmap[*pp][0]; 1067 pp += samplesperpixel; 1068 } 1069 cp += toskew; 1070 pp += fromskew; 1071 } 1072} 1073 1074/* 1075 * 4-bit palette => colormap/RGB 1076 */ 1077DECLAREContigPutFunc(put4bitcmaptile) 1078{ 1079 uint32** PALmap = img->PALmap; 1080 1081 (void) x; (void) y; 1082 fromskew /= 2; 1083 while (h-- > 0) { 1084 uint32* bw; 1085 UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++); 1086 cp += toskew; 1087 pp += fromskew; 1088 } 1089} 1090 1091/* 1092 * 2-bit palette => colormap/RGB 1093 */ 1094DECLAREContigPutFunc(put2bitcmaptile) 1095{ 1096 uint32** PALmap = img->PALmap; 1097 1098 (void) x; (void) y; 1099 fromskew /= 4; 1100 while (h-- > 0) { 1101 uint32* bw; 1102 UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++); 1103 cp += toskew; 1104 pp += fromskew; 1105 } 1106} 1107 1108/* 1109 * 1-bit palette => colormap/RGB 1110 */ 1111DECLAREContigPutFunc(put1bitcmaptile) 1112{ 1113 uint32** PALmap = img->PALmap; 1114 1115 (void) x; (void) y; 1116 fromskew /= 8; 1117 while (h-- > 0) { 1118 uint32* bw; 1119 UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++); 1120 cp += toskew; 1121 pp += fromskew; 1122 } 1123} 1124 1125/* 1126 * 8-bit greyscale => colormap/RGB 1127 */ 1128DECLAREContigPutFunc(putgreytile) 1129{ 1130 int samplesperpixel = img->samplesperpixel; 1131 uint32** BWmap = img->BWmap; 1132 1133 (void) y; 1134 while (h-- > 0) { 1135 for (x = w; x-- > 0;) 1136 { 1137 *cp++ = BWmap[*pp][0]; 1138 pp += samplesperpixel; 1139 } 1140 cp += toskew; 1141 pp += fromskew; 1142 } 1143} 1144 1145/* 1146 * 16-bit greyscale => colormap/RGB 1147 */ 1148DECLAREContigPutFunc(put16bitbwtile) 1149{ 1150 int samplesperpixel = img->samplesperpixel; 1151 uint32** BWmap = img->BWmap; 1152 1153 (void) y; 1154 while (h-- > 0) { 1155 uint16 *wp = (uint16 *) pp; 1156 1157 for (x = w; x-- > 0;) 1158 { 1159 /* use high order byte of 16bit value */ 1160 1161 *cp++ = BWmap[*wp >> 8][0]; 1162 pp += 2 * samplesperpixel; 1163 wp += samplesperpixel; 1164 } 1165 cp += toskew; 1166 pp += fromskew; 1167 } 1168} 1169 1170/* 1171 * 1-bit bilevel => colormap/RGB 1172 */ 1173DECLAREContigPutFunc(put1bitbwtile) 1174{ 1175 uint32** BWmap = img->BWmap; 1176 1177 (void) x; (void) y; 1178 fromskew /= 8; 1179 while (h-- > 0) { 1180 uint32* bw; 1181 UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++); 1182 cp += toskew; 1183 pp += fromskew; 1184 } 1185} 1186 1187/* 1188 * 2-bit greyscale => colormap/RGB 1189 */ 1190DECLAREContigPutFunc(put2bitbwtile) 1191{ 1192 uint32** BWmap = img->BWmap; 1193 1194 (void) x; (void) y; 1195 fromskew /= 4; 1196 while (h-- > 0) { 1197 uint32* bw; 1198 UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++); 1199 cp += toskew; 1200 pp += fromskew; 1201 } 1202} 1203 1204/* 1205 * 4-bit greyscale => colormap/RGB 1206 */ 1207DECLAREContigPutFunc(put4bitbwtile) 1208{ 1209 uint32** BWmap = img->BWmap; 1210 1211 (void) x; (void) y; 1212 fromskew /= 2; 1213 while (h-- > 0) { 1214 uint32* bw; 1215 UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++); 1216 cp += toskew; 1217 pp += fromskew; 1218 } 1219} 1220 1221/* 1222 * 8-bit packed samples, no Map => RGB 1223 */ 1224DECLAREContigPutFunc(putRGBcontig8bittile) 1225{ 1226 int samplesperpixel = img->samplesperpixel; 1227 1228 (void) x; (void) y; 1229 fromskew *= samplesperpixel; 1230 while (h-- > 0) { 1231 UNROLL8(w, NOP, 1232 *cp++ = PACK(pp[0], pp[1], pp[2]); 1233 pp += samplesperpixel); 1234 cp += toskew; 1235 pp += fromskew; 1236 } 1237} 1238 1239/* 1240 * 8-bit packed samples => RGBA w/ associated alpha 1241 * (known to have Map == NULL) 1242 */ 1243DECLAREContigPutFunc(putRGBAAcontig8bittile) 1244{ 1245 int samplesperpixel = img->samplesperpixel; 1246 1247 (void) x; (void) y; 1248 fromskew *= samplesperpixel; 1249 while (h-- > 0) { 1250 UNROLL8(w, NOP, 1251 *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]); 1252 pp += samplesperpixel); 1253 cp += toskew; 1254 pp += fromskew; 1255 } 1256} 1257 1258/* 1259 * 8-bit packed samples => RGBA w/ unassociated alpha 1260 * (known to have Map == NULL) 1261 */ 1262DECLAREContigPutFunc(putRGBUAcontig8bittile) 1263{ 1264 int samplesperpixel = img->samplesperpixel; 1265 (void) y; 1266 fromskew *= samplesperpixel; 1267 while (h-- > 0) { 1268 uint32 r, g, b, a; 1269 for (x = w; x-- > 0;) { 1270 a = pp[3]; 1271 r = (a*pp[0] + 127) / 255; 1272 g = (a*pp[1] + 127) / 255; 1273 b = (a*pp[2] + 127) / 255; 1274 *cp++ = PACK4(r,g,b,a); 1275 pp += samplesperpixel; 1276 } 1277 cp += toskew; 1278 pp += fromskew; 1279 } 1280} 1281 1282/* 1283 * 16-bit packed samples => RGB 1284 */ 1285DECLAREContigPutFunc(putRGBcontig16bittile) 1286{ 1287 int samplesperpixel = img->samplesperpixel; 1288 uint16 *wp = (uint16 *)pp; 1289 (void) y; 1290 fromskew *= samplesperpixel; 1291 while (h-- > 0) { 1292 for (x = w; x-- > 0;) { 1293 *cp++ = PACKW(wp[0],wp[1],wp[2]); 1294 wp += samplesperpixel; 1295 } 1296 cp += toskew; 1297 wp += fromskew; 1298 } 1299} 1300 1301/* 1302 * 16-bit packed samples => RGBA w/ associated alpha 1303 * (known to have Map == NULL) 1304 */ 1305DECLAREContigPutFunc(putRGBAAcontig16bittile) 1306{ 1307 int samplesperpixel = img->samplesperpixel; 1308 uint16 *wp = (uint16 *)pp; 1309 (void) y; 1310 fromskew *= samplesperpixel; 1311 while (h-- > 0) { 1312 for (x = w; x-- > 0;) { 1313 *cp++ = PACKW4(wp[0],wp[1],wp[2],wp[3]); 1314 wp += samplesperpixel; 1315 } 1316 cp += toskew; 1317 wp += fromskew; 1318 } 1319} 1320 1321/* 1322 * 16-bit packed samples => RGBA w/ unassociated alpha 1323 * (known to have Map == NULL) 1324 */ 1325DECLAREContigPutFunc(putRGBUAcontig16bittile) 1326{ 1327 int samplesperpixel = img->samplesperpixel; 1328 uint16 *wp = (uint16 *)pp; 1329 (void) y; 1330 fromskew *= samplesperpixel; 1331 while (h-- > 0) { 1332 uint32 r,g,b,a; 1333 for (x = w; x-- > 0;) { 1334 a = W2B(wp[3]); 1335 r = (a*W2B(wp[0]) + 127) / 255; 1336 g = (a*W2B(wp[1]) + 127) / 255; 1337 b = (a*W2B(wp[2]) + 127) / 255; 1338 *cp++ = PACK4(r,g,b,a); 1339 wp += samplesperpixel; 1340 } 1341 cp += toskew; 1342 wp += fromskew; 1343 } 1344} 1345 1346/* 1347 * 8-bit packed CMYK samples w/o Map => RGB 1348 * 1349 * NB: The conversion of CMYK->RGB is *very* crude. 1350 */ 1351DECLAREContigPutFunc(putRGBcontig8bitCMYKtile) 1352{ 1353 int samplesperpixel = img->samplesperpixel; 1354 uint16 r, g, b, k; 1355 1356 (void) x; (void) y; 1357 fromskew *= samplesperpixel; 1358 while (h-- > 0) { 1359 UNROLL8(w, NOP, 1360 k = 255 - pp[3]; 1361 r = (k*(255-pp[0]))/255; 1362 g = (k*(255-pp[1]))/255; 1363 b = (k*(255-pp[2]))/255; 1364 *cp++ = PACK(r, g, b); 1365 pp += samplesperpixel); 1366 cp += toskew; 1367 pp += fromskew; 1368 } 1369} 1370 1371/* 1372 * 8-bit packed CMYK samples w/Map => RGB 1373 * 1374 * NB: The conversion of CMYK->RGB is *very* crude. 1375 */ 1376DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile) 1377{ 1378 int samplesperpixel = img->samplesperpixel; 1379 TIFFRGBValue* Map = img->Map; 1380 uint16 r, g, b, k; 1381 1382 (void) y; 1383 fromskew *= samplesperpixel; 1384 while (h-- > 0) { 1385 for (x = w; x-- > 0;) { 1386 k = 255 - pp[3]; 1387 r = (k*(255-pp[0]))/255; 1388 g = (k*(255-pp[1]))/255; 1389 b = (k*(255-pp[2]))/255; 1390 *cp++ = PACK(Map[r], Map[g], Map[b]); 1391 pp += samplesperpixel; 1392 } 1393 pp += fromskew; 1394 cp += toskew; 1395 } 1396} 1397 1398#define DECLARESepPutFunc(name) \ 1399static void name(\ 1400 TIFFRGBAImage* img,\ 1401 uint32* cp,\ 1402 uint32 x, uint32 y, \ 1403 uint32 w, uint32 h,\ 1404 int32 fromskew, int32 toskew,\ 1405 unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a\ 1406) 1407 1408/* 1409 * 8-bit unpacked samples => RGB 1410 */ 1411DECLARESepPutFunc(putRGBseparate8bittile) 1412{ 1413 (void) img; (void) x; (void) y; (void) a; 1414 while (h-- > 0) { 1415 UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++)); 1416 SKEW(r, g, b, fromskew); 1417 cp += toskew; 1418 } 1419} 1420 1421/* 1422 * 8-bit unpacked samples => RGBA w/ associated alpha 1423 */ 1424DECLARESepPutFunc(putRGBAAseparate8bittile) 1425{ 1426 (void) img; (void) x; (void) y; 1427 while (h-- > 0) { 1428 UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++)); 1429 SKEW4(r, g, b, a, fromskew); 1430 cp += toskew; 1431 } 1432} 1433 1434/* 1435 * 8-bit unpacked samples => RGBA w/ unassociated alpha 1436 */ 1437DECLARESepPutFunc(putRGBUAseparate8bittile) 1438{ 1439 (void) img; (void) y; 1440 while (h-- > 0) { 1441 uint32 rv, gv, bv, av; 1442 for (x = w; x-- > 0;) { 1443 av = *a++; 1444 rv = (av* *r++ + 127) / 255; 1445 gv = (av* *g++ + 127) / 255; 1446 bv = (av* *b++ + 127) / 255; 1447 *cp++ = PACK4(rv,gv,bv,av); 1448 } 1449 SKEW4(r, g, b, a, fromskew); 1450 cp += toskew; 1451 } 1452} 1453 1454/* 1455 * 16-bit unpacked samples => RGB 1456 */ 1457DECLARESepPutFunc(putRGBseparate16bittile) 1458{ 1459 uint16 *wr = (uint16*) r; 1460 uint16 *wg = (uint16*) g; 1461 uint16 *wb = (uint16*) b; 1462 (void) img; (void) y; (void) a; 1463 while (h-- > 0) { 1464 for (x = 0; x < w; x++) 1465 *cp++ = PACKW(*wr++,*wg++,*wb++); 1466 SKEW(wr, wg, wb, fromskew); 1467 cp += toskew; 1468 } 1469} 1470 1471/* 1472 * 16-bit unpacked samples => RGBA w/ associated alpha 1473 */ 1474DECLARESepPutFunc(putRGBAAseparate16bittile) 1475{ 1476 uint16 *wr = (uint16*) r; 1477 uint16 *wg = (uint16*) g; 1478 uint16 *wb = (uint16*) b; 1479 uint16 *wa = (uint16*) a; 1480 (void) img; (void) y; 1481 while (h-- > 0) { 1482 for (x = 0; x < w; x++) 1483 *cp++ = PACKW4(*wr++,*wg++,*wb++,*wa++); 1484 SKEW4(wr, wg, wb, wa, fromskew); 1485 cp += toskew; 1486 } 1487} 1488 1489/* 1490 * 16-bit unpacked samples => RGBA w/ unassociated alpha 1491 */ 1492DECLARESepPutFunc(putRGBUAseparate16bittile) 1493{ 1494 uint16 *wr = (uint16*) r; 1495 uint16 *wg = (uint16*) g; 1496 uint16 *wb = (uint16*) b; 1497 uint16 *wa = (uint16*) a; 1498 (void) img; (void) y; 1499 while (h-- > 0) { 1500 uint32 r,g,b,a; 1501 for (x = w; x-- > 0;) { 1502 a = W2B(*wa++); 1503 r = (a*W2B(*wr++) + 127) / 255; 1504 g = (a*W2B(*wg++) + 127) / 255; 1505 b = (a*W2B(*wb++) + 127) / 255; 1506 *cp++ = PACK4(r,g,b,a); 1507 } 1508 SKEW4(wr, wg, wb, wa, fromskew); 1509 cp += toskew; 1510 } 1511} 1512 1513/* 1514 * 8-bit packed CIE L*a*b 1976 samples => RGB 1515 */ 1516DECLAREContigPutFunc(putcontig8bitCIELab) 1517{ 1518 float X, Y, Z; 1519 uint32 r, g, b; 1520 (void) y; 1521 fromskew *= 3; 1522 while (h-- > 0) { 1523 for (x = w; x-- > 0;) { 1524 TIFFCIELabToXYZ(img->cielab, 1525 (unsigned char)pp[0], 1526 (signed char)pp[1], 1527 (signed char)pp[2], 1528 &X, &Y, &Z); 1529 TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b); 1530 *cp++ = PACK(r, g, b); 1531 pp += 3; 1532 } 1533 cp += toskew; 1534 pp += fromskew; 1535 } 1536} 1537 1538/* 1539 * YCbCr -> RGB conversion and packing routines. 1540 */ 1541 1542#define YCbCrtoRGB(dst, Y) { \ 1543 uint32 r, g, b; \ 1544 TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b); \ 1545 dst = PACK(r, g, b); \ 1546} 1547 1548/* 1549 * 8-bit packed YCbCr samples => RGB 1550 * This function is generic for different sampling sizes, 1551 * and can handle blocks sizes that aren't multiples of the 1552 * sampling size. However, it is substantially less optimized 1553 * than the specific sampling cases. It is used as a fallback 1554 * for difficult blocks. 1555 */ 1556#ifdef notdef 1557static void putcontig8bitYCbCrGenericTile( 1558 TIFFRGBAImage* img, 1559 uint32* cp, 1560 uint32 x, uint32 y, 1561 uint32 w, uint32 h, 1562 int32 fromskew, int32 toskew, 1563 unsigned char* pp, 1564 int h_group, 1565 int v_group ) 1566 1567{ 1568 uint32* cp1 = cp+w+toskew; 1569 uint32* cp2 = cp1+w+toskew; 1570 uint32* cp3 = cp2+w+toskew; 1571 int32 incr = 3*w+4*toskew; 1572 int32 Cb, Cr; 1573 int group_size = v_group * h_group + 2; 1574 1575 (void) y; 1576 fromskew = (fromskew * group_size) / h_group; 1577 1578 for( yy = 0; yy < h; yy++ ) 1579 { 1580 unsigned char *pp_line; 1581 int y_line_group = yy / v_group; 1582 int y_remainder = yy - y_line_group * v_group; 1583 1584 pp_line = pp + v_line_group * 1585 1586 1587 for( xx = 0; xx < w; xx++ ) 1588 { 1589 Cb = pp 1590 } 1591 } 1592 for (; h >= 4; h -= 4) { 1593 x = w>>2; 1594 do { 1595 Cb = pp[16]; 1596 Cr = pp[17]; 1597 1598 YCbCrtoRGB(cp [0], pp[ 0]); 1599 YCbCrtoRGB(cp [1], pp[ 1]); 1600 YCbCrtoRGB(cp [2], pp[ 2]); 1601 YCbCrtoRGB(cp [3], pp[ 3]); 1602 YCbCrtoRGB(cp1[0], pp[ 4]); 1603 YCbCrtoRGB(cp1[1], pp[ 5]); 1604 YCbCrtoRGB(cp1[2], pp[ 6]); 1605 YCbCrtoRGB(cp1[3], pp[ 7]); 1606 YCbCrtoRGB(cp2[0], pp[ 8]); 1607 YCbCrtoRGB(cp2[1], pp[ 9]); 1608 YCbCrtoRGB(cp2[2], pp[10]); 1609 YCbCrtoRGB(cp2[3], pp[11]); 1610 YCbCrtoRGB(cp3[0], pp[12]); 1611 YCbCrtoRGB(cp3[1], pp[13]); 1612 YCbCrtoRGB(cp3[2], pp[14]); 1613 YCbCrtoRGB(cp3[3], pp[15]); 1614 1615 cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; 1616 pp += 18; 1617 } while (--x); 1618 cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; 1619 pp += fromskew; 1620 } 1621} 1622#endif 1623 1624/* 1625 * 8-bit packed YCbCr samples w/ 4,4 subsampling => RGB 1626 */ 1627DECLAREContigPutFunc(putcontig8bitYCbCr44tile) 1628{ 1629 uint32* cp1 = cp+w+toskew; 1630 uint32* cp2 = cp1+w+toskew; 1631 uint32* cp3 = cp2+w+toskew; 1632 int32 incr = 3*w+4*toskew; 1633 1634 (void) y; 1635 /* adjust fromskew */ 1636 fromskew = (fromskew * 18) / 4; 1637 if ((h & 3) == 0 && (w & 3) == 0) { 1638 for (; h >= 4; h -= 4) { 1639 x = w>>2; 1640 do { 1641 int32 Cb = pp[16]; 1642 int32 Cr = pp[17]; 1643 1644 YCbCrtoRGB(cp [0], pp[ 0]); 1645 YCbCrtoRGB(cp [1], pp[ 1]); 1646 YCbCrtoRGB(cp [2], pp[ 2]); 1647 YCbCrtoRGB(cp [3], pp[ 3]); 1648 YCbCrtoRGB(cp1[0], pp[ 4]); 1649 YCbCrtoRGB(cp1[1], pp[ 5]); 1650 YCbCrtoRGB(cp1[2], pp[ 6]); 1651 YCbCrtoRGB(cp1[3], pp[ 7]); 1652 YCbCrtoRGB(cp2[0], pp[ 8]); 1653 YCbCrtoRGB(cp2[1], pp[ 9]); 1654 YCbCrtoRGB(cp2[2], pp[10]); 1655 YCbCrtoRGB(cp2[3], pp[11]); 1656 YCbCrtoRGB(cp3[0], pp[12]); 1657 YCbCrtoRGB(cp3[1], pp[13]); 1658 YCbCrtoRGB(cp3[2], pp[14]); 1659 YCbCrtoRGB(cp3[3], pp[15]); 1660 1661 cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; 1662 pp += 18; 1663 } while (--x); 1664 cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; 1665 pp += fromskew; 1666 } 1667 } else { 1668 while (h > 0) { 1669 for (x = w; x > 0;) { 1670 int32 Cb = pp[16]; 1671 int32 Cr = pp[17]; 1672 switch (x) { 1673 default: 1674 switch (h) { 1675 default: YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */ 1676 case 3: YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */ 1677 case 2: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ 1678 case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ 1679 } /* FALLTHROUGH */ 1680 case 3: 1681 switch (h) { 1682 default: YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */ 1683 case 3: YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */ 1684 case 2: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ 1685 case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ 1686 } /* FALLTHROUGH */ 1687 case 2: 1688 switch (h) { 1689 default: YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */ 1690 case 3: YCbCrtoRGB(cp2[1], pp[ 9]); /* FALLTHROUGH */ 1691 case 2: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ 1692 case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ 1693 } /* FALLTHROUGH */ 1694 case 1: 1695 switch (h) { 1696 default: YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */ 1697 case 3: YCbCrtoRGB(cp2[0], pp[ 8]); /* FALLTHROUGH */ 1698 case 2: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ 1699 case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ 1700 } /* FALLTHROUGH */ 1701 } 1702 if (x < 4) { 1703 cp += x; cp1 += x; cp2 += x; cp3 += x; 1704 x = 0; 1705 } 1706 else { 1707 cp += 4; cp1 += 4; cp2 += 4; cp3 += 4; 1708 x -= 4; 1709 } 1710 pp += 18; 1711 } 1712 if (h <= 4) 1713 break; 1714 h -= 4; 1715 cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; 1716 pp += fromskew; 1717 } 1718 } 1719} 1720 1721/* 1722 * 8-bit packed YCbCr samples w/ 4,2 subsampling => RGB 1723 */ 1724DECLAREContigPutFunc(putcontig8bitYCbCr42tile) 1725{ 1726 uint32* cp1 = cp+w+toskew; 1727 int32 incr = 2*toskew+w; 1728 1729 (void) y; 1730 fromskew = (fromskew * 10) / 4; 1731 if ((h & 3) == 0 && (w & 1) == 0) { 1732 for (; h >= 2; h -= 2) { 1733 x = w>>2; 1734 do { 1735 int32 Cb = pp[8]; 1736 int32 Cr = pp[9]; 1737 1738 YCbCrtoRGB(cp [0], pp[0]); 1739 YCbCrtoRGB(cp [1], pp[1]); 1740 YCbCrtoRGB(cp [2], pp[2]); 1741 YCbCrtoRGB(cp [3], pp[3]); 1742 YCbCrtoRGB(cp1[0], pp[4]); 1743 YCbCrtoRGB(cp1[1], pp[5]); 1744 YCbCrtoRGB(cp1[2], pp[6]); 1745 YCbCrtoRGB(cp1[3], pp[7]); 1746 1747 cp += 4, cp1 += 4; 1748 pp += 10; 1749 } while (--x); 1750 cp += incr, cp1 += incr; 1751 pp += fromskew; 1752 } 1753 } else { 1754 while (h > 0) { 1755 for (x = w; x > 0;) { 1756 int32 Cb = pp[8]; 1757 int32 Cr = pp[9]; 1758 switch (x) { 1759 default: 1760 switch (h) { 1761 default: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ 1762 case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ 1763 } /* FALLTHROUGH */ 1764 case 3: 1765 switch (h) { 1766 default: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ 1767 case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ 1768 } /* FALLTHROUGH */ 1769 case 2: 1770 switch (h) { 1771 default: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ 1772 case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ 1773 } /* FALLTHROUGH */ 1774 case 1: 1775 switch (h) { 1776 default: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ 1777 case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ 1778 } /* FALLTHROUGH */ 1779 } 1780 if (x < 4) { 1781 cp += x; cp1 += x; 1782 x = 0; 1783 } 1784 else { 1785 cp += 4; cp1 += 4; 1786 x -= 4; 1787 } 1788 pp += 10; 1789 } 1790 if (h <= 2) 1791 break; 1792 h -= 2; 1793 cp += incr, cp1 += incr; 1794 pp += fromskew; 1795 } 1796 } 1797} 1798 1799/* 1800 * 8-bit packed YCbCr samples w/ 4,1 subsampling => RGB 1801 */ 1802DECLAREContigPutFunc(putcontig8bitYCbCr41tile) 1803{ 1804 (void) y; 1805 /* XXX adjust fromskew */ 1806 do { 1807 x = w>>2; 1808 do { 1809 int32 Cb = pp[4]; 1810 int32 Cr = pp[5]; 1811 1812 YCbCrtoRGB(cp [0], pp[0]); 1813 YCbCrtoRGB(cp [1], pp[1]); 1814 YCbCrtoRGB(cp [2], pp[2]); 1815 YCbCrtoRGB(cp [3], pp[3]); 1816 1817 cp += 4; 1818 pp += 6; 1819 } while (--x); 1820 1821 if( (w&3) != 0 ) 1822 { 1823 int32 Cb = pp[4]; 1824 int32 Cr = pp[5]; 1825 1826 switch( (w&3) ) { 1827 case 3: YCbCrtoRGB(cp [2], pp[2]); 1828 case 2: YCbCrtoRGB(cp [1], pp[1]); 1829 case 1: YCbCrtoRGB(cp [0], pp[0]); 1830 case 0: break; 1831 } 1832 1833 cp += (w&3); 1834 pp += 6; 1835 } 1836 1837 cp += toskew; 1838 pp += fromskew; 1839 } while (--h); 1840 1841} 1842 1843/* 1844 * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB 1845 */ 1846DECLAREContigPutFunc(putcontig8bitYCbCr22tile) 1847{ 1848 uint32* cp2; 1849 (void) y; 1850 fromskew = (fromskew / 2) * 6; 1851 cp2 = cp+w+toskew; 1852 while (h>=2) { 1853 x = w; 1854 while (x>=2) { 1855 uint32 Cb = pp[4]; 1856 uint32 Cr = pp[5]; 1857 YCbCrtoRGB(cp[0], pp[0]); 1858 YCbCrtoRGB(cp[1], pp[1]); 1859 YCbCrtoRGB(cp2[0], pp[2]); 1860 YCbCrtoRGB(cp2[1], pp[3]); 1861 cp += 2; 1862 cp2 += 2; 1863 pp += 6; 1864 x -= 2; 1865 } 1866 if (x==1) { 1867 uint32 Cb = pp[4]; 1868 uint32 Cr = pp[5]; 1869 YCbCrtoRGB(cp[0], pp[0]); 1870 YCbCrtoRGB(cp2[0], pp[2]); 1871 cp ++ ; 1872 cp2 ++ ; 1873 pp += 6; 1874 } 1875 cp += toskew*2+w; 1876 cp2 += toskew*2+w; 1877 pp += fromskew; 1878 h-=2; 1879 } 1880 if (h==1) { 1881 x = w; 1882 while (x>=2) { 1883 uint32 Cb = pp[4]; 1884 uint32 Cr = pp[5]; 1885 YCbCrtoRGB(cp[0], pp[0]); 1886 YCbCrtoRGB(cp[1], pp[1]); 1887 cp += 2; 1888 cp2 += 2; 1889 pp += 6; 1890 x -= 2; 1891 } 1892 if (x==1) { 1893 uint32 Cb = pp[4]; 1894 uint32 Cr = pp[5]; 1895 YCbCrtoRGB(cp[0], pp[0]); 1896 } 1897 } 1898} 1899 1900/* 1901 * 8-bit packed YCbCr samples w/ 2,1 subsampling => RGB 1902 */ 1903DECLAREContigPutFunc(putcontig8bitYCbCr21tile) 1904{ 1905 (void) y; 1906 fromskew = (fromskew * 4) / 2; 1907 do { 1908 x = w>>1; 1909 do { 1910 int32 Cb = pp[2]; 1911 int32 Cr = pp[3]; 1912 1913 YCbCrtoRGB(cp[0], pp[0]); 1914 YCbCrtoRGB(cp[1], pp[1]); 1915 1916 cp += 2; 1917 pp += 4; 1918 } while (--x); 1919 1920 if( (w&1) != 0 ) 1921 { 1922 int32 Cb = pp[2]; 1923 int32 Cr = pp[3]; 1924 1925 YCbCrtoRGB(cp[0], pp[0]); 1926 1927 cp += 1; 1928 pp += 4; 1929 } 1930 1931 cp += toskew; 1932 pp += fromskew; 1933 } while (--h); 1934} 1935 1936/* 1937 * 8-bit packed YCbCr samples w/ 1,2 subsampling => RGB 1938 */ 1939DECLAREContigPutFunc(putcontig8bitYCbCr12tile) 1940{ 1941 uint32* cp2; 1942 (void) y; 1943 fromskew = (fromskew / 2) * 4; 1944 cp2 = cp+w+toskew; 1945 while (h>=2) { 1946 x = w; 1947 do { 1948 uint32 Cb = pp[2]; 1949 uint32 Cr = pp[3]; 1950 YCbCrtoRGB(cp[0], pp[0]); 1951 YCbCrtoRGB(cp2[0], pp[1]); 1952 cp ++; 1953 cp2 ++; 1954 pp += 4; 1955 } while (--x); 1956 cp += toskew*2+w; 1957 cp2 += toskew*2+w; 1958 pp += fromskew; 1959 h-=2; 1960 } 1961 if (h==1) { 1962 x = w; 1963 do { 1964 uint32 Cb = pp[2]; 1965 uint32 Cr = pp[3]; 1966 YCbCrtoRGB(cp[0], pp[0]); 1967 cp ++; 1968 pp += 4; 1969 } while (--x); 1970 } 1971} 1972 1973/* 1974 * 8-bit packed YCbCr samples w/ no subsampling => RGB 1975 */ 1976DECLAREContigPutFunc(putcontig8bitYCbCr11tile) 1977{ 1978 (void) y; 1979 fromskew *= 3; 1980 do { 1981 x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */ 1982 do { 1983 int32 Cb = pp[1]; 1984 int32 Cr = pp[2]; 1985 1986 YCbCrtoRGB(*cp++, pp[0]); 1987 1988 pp += 3; 1989 } while (--x); 1990 cp += toskew; 1991 pp += fromskew; 1992 } while (--h); 1993} 1994 1995/* 1996 * 8-bit packed YCbCr samples w/ no subsampling => RGB 1997 */ 1998DECLARESepPutFunc(putseparate8bitYCbCr11tile) 1999{ 2000 (void) y; 2001 (void) a; 2002 /* TODO: naming of input vars is still off, change obfuscating declaration inside define, or resolve obfuscation */ 2003 while (h-- > 0) { 2004 x = w; 2005 do { 2006 uint32 dr, dg, db; 2007 TIFFYCbCrtoRGB(img->ycbcr,*r++,*g++,*b++,&dr,&dg,&db); 2008 *cp++ = PACK(dr,dg,db); 2009 } while (--x); 2010 SKEW(r, g, b, fromskew); 2011 cp += toskew; 2012 } 2013} 2014#undef YCbCrtoRGB 2015 2016static int 2017initYCbCrConversion(TIFFRGBAImage* img) 2018{ 2019 static char module[] = "initYCbCrConversion"; 2020 2021 float *luma, *refBlackWhite; 2022 2023 if (img->ycbcr == NULL) { 2024 img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc( 2025 TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)) 2026 + 4*256*sizeof (TIFFRGBValue) 2027 + 2*256*sizeof (int) 2028 + 3*256*sizeof (int32) 2029 ); 2030 if (img->ycbcr == NULL) { 2031 TIFFErrorExt(img->tif->tif_clientdata, module, 2032 "No space for YCbCr->RGB conversion state"); 2033 return (0); 2034 } 2035 } 2036 2037 TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma); 2038 TIFFGetFieldDefaulted(img->tif, TIFFTAG_REFERENCEBLACKWHITE, 2039 &refBlackWhite); 2040 if (TIFFYCbCrToRGBInit(img->ycbcr, luma, refBlackWhite) < 0) 2041 return(0); 2042 return (1); 2043} 2044 2045static tileContigRoutine 2046initCIELabConversion(TIFFRGBAImage* img) 2047{ 2048 static char module[] = "initCIELabConversion"; 2049 2050 float *whitePoint; 2051 float refWhite[3]; 2052 2053 if (!img->cielab) { 2054 img->cielab = (TIFFCIELabToRGB *) 2055 _TIFFmalloc(sizeof(TIFFCIELabToRGB)); 2056 if (!img->cielab) { 2057 TIFFErrorExt(img->tif->tif_clientdata, module, 2058 "No space for CIE L*a*b*->RGB conversion state."); 2059 return NULL; 2060 } 2061 } 2062 2063 TIFFGetFieldDefaulted(img->tif, TIFFTAG_WHITEPOINT, &whitePoint); 2064 refWhite[1] = 100.0F; 2065 refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1]; 2066 refWhite[2] = (1.0F - whitePoint[0] - whitePoint[1]) 2067 / whitePoint[1] * refWhite[1]; 2068 if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB, refWhite) < 0) { 2069 TIFFErrorExt(img->tif->tif_clientdata, module, 2070 "Failed to initialize CIE L*a*b*->RGB conversion state."); 2071 _TIFFfree(img->cielab); 2072 return NULL; 2073 } 2074 2075 return putcontig8bitCIELab; 2076} 2077 2078/* 2079 * Greyscale images with less than 8 bits/sample are handled 2080 * with a table to avoid lots of shifts and masks. The table 2081 * is setup so that put*bwtile (below) can retrieve 8/bitspersample 2082 * pixel values simply by indexing into the table with one 2083 * number. 2084 */ 2085static int 2086makebwmap(TIFFRGBAImage* img) 2087{ 2088 TIFFRGBValue* Map = img->Map; 2089 int bitspersample = img->bitspersample; 2090 int nsamples = 8 / bitspersample; 2091 int i; 2092 uint32* p; 2093 2094 if( nsamples == 0 ) 2095 nsamples = 1; 2096 2097 img->BWmap = (uint32**) _TIFFmalloc( 2098 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); 2099 if (img->BWmap == NULL) { 2100 TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for B&W mapping table"); 2101 return (0); 2102 } 2103 p = (uint32*)(img->BWmap + 256); 2104 for (i = 0; i < 256; i++) { 2105 TIFFRGBValue c; 2106 img->BWmap[i] = p; 2107 switch (bitspersample) { 2108#define GREY(x) c = Map[x]; *p++ = PACK(c,c,c); 2109 case 1: 2110 GREY(i>>7); 2111 GREY((i>>6)&1); 2112 GREY((i>>5)&1); 2113 GREY((i>>4)&1); 2114 GREY((i>>3)&1); 2115 GREY((i>>2)&1); 2116 GREY((i>>1)&1); 2117 GREY(i&1); 2118 break; 2119 case 2: 2120 GREY(i>>6); 2121 GREY((i>>4)&3); 2122 GREY((i>>2)&3); 2123 GREY(i&3); 2124 break; 2125 case 4: 2126 GREY(i>>4); 2127 GREY(i&0xf); 2128 break; 2129 case 8: 2130 case 16: 2131 GREY(i); 2132 break; 2133 } 2134#undef GREY 2135 } 2136 return (1); 2137} 2138 2139/* 2140 * Construct a mapping table to convert from the range 2141 * of the data samples to [0,255] --for display. This 2142 * process also handles inverting B&W images when needed. 2143 */ 2144static int 2145setupMap(TIFFRGBAImage* img) 2146{ 2147 int32 x, range; 2148 2149 range = (int32)((1L<<img->bitspersample)-1); 2150 2151 /* treat 16 bit the same as eight bit */ 2152 if( img->bitspersample == 16 ) 2153 range = (int32) 255; 2154 2155 img->Map = (TIFFRGBValue*) _TIFFmalloc((range+1) * sizeof (TIFFRGBValue)); 2156 if (img->Map == NULL) { 2157 TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), 2158 "No space for photometric conversion table"); 2159 return (0); 2160 } 2161 if (img->photometric == PHOTOMETRIC_MINISWHITE) { 2162 for (x = 0; x <= range; x++) 2163 img->Map[x] = (TIFFRGBValue) (((range - x) * 255) / range); 2164 } else { 2165 for (x = 0; x <= range; x++) 2166 img->Map[x] = (TIFFRGBValue) ((x * 255) / range); 2167 } 2168 if (img->bitspersample <= 16 && 2169 (img->photometric == PHOTOMETRIC_MINISBLACK || 2170 img->photometric == PHOTOMETRIC_MINISWHITE)) { 2171 /* 2172 * Use photometric mapping table to construct 2173 * unpacking tables for samples <= 8 bits. 2174 */ 2175 if (!makebwmap(img)) 2176 return (0); 2177 /* no longer need Map, free it */ 2178 _TIFFfree(img->Map), img->Map = NULL; 2179 } 2180 return (1); 2181} 2182 2183static int 2184checkcmap(TIFFRGBAImage* img) 2185{ 2186 uint16* r = img->redcmap; 2187 uint16* g = img->greencmap; 2188 uint16* b = img->bluecmap; 2189 long n = 1L<<img->bitspersample; 2190 2191 while (n-- > 0) 2192 if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) 2193 return (16); 2194 return (8); 2195} 2196 2197static void 2198cvtcmap(TIFFRGBAImage* img) 2199{ 2200 uint16* r = img->redcmap; 2201 uint16* g = img->greencmap; 2202 uint16* b = img->bluecmap; 2203 long i; 2204 2205 for (i = (1L<<img->bitspersample)-1; i >= 0; i--) { 2206#define CVT(x) ((uint16)((x)>>8)) 2207 r[i] = CVT(r[i]); 2208 g[i] = CVT(g[i]); 2209 b[i] = CVT(b[i]); 2210#undef CVT 2211 } 2212} 2213 2214/* 2215 * Palette images with <= 8 bits/sample are handled 2216 * with a table to avoid lots of shifts and masks. The table 2217 * is setup so that put*cmaptile (below) can retrieve 8/bitspersample 2218 * pixel values simply by indexing into the table with one 2219 * number. 2220 */ 2221static int 2222makecmap(TIFFRGBAImage* img) 2223{ 2224 int bitspersample = img->bitspersample; 2225 int nsamples = 8 / bitspersample; 2226 uint16* r = img->redcmap; 2227 uint16* g = img->greencmap; 2228 uint16* b = img->bluecmap; 2229 uint32 *p; 2230 int i; 2231 2232 img->PALmap = (uint32**) _TIFFmalloc( 2233 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); 2234 if (img->PALmap == NULL) { 2235 TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for Palette mapping table"); 2236 return (0); 2237 } 2238 p = (uint32*)(img->PALmap + 256); 2239 for (i = 0; i < 256; i++) { 2240 TIFFRGBValue c; 2241 img->PALmap[i] = p; 2242#define CMAP(x) c = (TIFFRGBValue) x; *p++ = PACK(r[c]&0xff, g[c]&0xff, b[c]&0xff); 2243 switch (bitspersample) { 2244 case 1: 2245 CMAP(i>>7); 2246 CMAP((i>>6)&1); 2247 CMAP((i>>5)&1); 2248 CMAP((i>>4)&1); 2249 CMAP((i>>3)&1); 2250 CMAP((i>>2)&1); 2251 CMAP((i>>1)&1); 2252 CMAP(i&1); 2253 break; 2254 case 2: 2255 CMAP(i>>6); 2256 CMAP((i>>4)&3); 2257 CMAP((i>>2)&3); 2258 CMAP(i&3); 2259 break; 2260 case 4: 2261 CMAP(i>>4); 2262 CMAP(i&0xf); 2263 break; 2264 case 8: 2265 CMAP(i); 2266 break; 2267 } 2268#undef CMAP 2269 } 2270 return (1); 2271} 2272 2273/* 2274 * Construct any mapping table used 2275 * by the associated put routine. 2276 */ 2277static int 2278buildMap(TIFFRGBAImage* img) 2279{ 2280 switch (img->photometric) { 2281 case PHOTOMETRIC_RGB: 2282 case PHOTOMETRIC_YCBCR: 2283 case PHOTOMETRIC_SEPARATED: 2284 if (img->bitspersample == 8) 2285 break; 2286 /* fall thru... */ 2287 case PHOTOMETRIC_MINISBLACK: 2288 case PHOTOMETRIC_MINISWHITE: 2289 if (!setupMap(img)) 2290 return (0); 2291 break; 2292 case PHOTOMETRIC_PALETTE: 2293 /* 2294 * Convert 16-bit colormap to 8-bit (unless it looks 2295 * like an old-style 8-bit colormap). 2296 */ 2297 if (checkcmap(img) == 16) 2298 cvtcmap(img); 2299 else 2300 TIFFWarningExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "Assuming 8-bit colormap"); 2301 /* 2302 * Use mapping table and colormap to construct 2303 * unpacking tables for samples < 8 bits. 2304 */ 2305 if (img->bitspersample <= 8 && !makecmap(img)) 2306 return (0); 2307 break; 2308 } 2309 return (1); 2310} 2311 2312/* 2313 * Select the appropriate conversion routine for packed data. 2314 */ 2315static int 2316PickContigCase(TIFFRGBAImage* img) 2317{ 2318 img->get = TIFFIsTiled(img->tif) ? gtTileContig : gtStripContig; 2319 img->put.contig = NULL; 2320 switch (img->photometric) { 2321 case PHOTOMETRIC_RGB: 2322 switch (img->bitspersample) { 2323 case 8: 2324 if (img->alpha == EXTRASAMPLE_ASSOCALPHA) 2325 img->put.contig = putRGBAAcontig8bittile; 2326 else if (img->alpha == EXTRASAMPLE_UNASSALPHA) 2327 { 2328 img->put.contig = putRGBUAcontig8bittile; 2329 } 2330 else 2331 img->put.contig = putRGBcontig8bittile; 2332 break; 2333 case 16: 2334 if (img->alpha == EXTRASAMPLE_ASSOCALPHA) 2335 { 2336 img->put.contig = putRGBAAcontig16bittile; 2337 } 2338 else if (img->alpha == EXTRASAMPLE_UNASSALPHA) 2339 { 2340 img->put.contig = putRGBUAcontig16bittile; 2341 } 2342 else 2343 { 2344 img->put.contig = putRGBcontig16bittile; 2345 } 2346 break; 2347 } 2348 break; 2349 case PHOTOMETRIC_SEPARATED: 2350 if (buildMap(img)) { 2351 if (img->bitspersample == 8) { 2352 if (!img->Map) 2353 img->put.contig = putRGBcontig8bitCMYKtile; 2354 else 2355 img->put.contig = putRGBcontig8bitCMYKMaptile; 2356 } 2357 } 2358 break; 2359 case PHOTOMETRIC_PALETTE: 2360 if (buildMap(img)) { 2361 switch (img->bitspersample) { 2362 case 8: 2363 img->put.contig = put8bitcmaptile; 2364 break; 2365 case 4: 2366 img->put.contig = put4bitcmaptile; 2367 break; 2368 case 2: 2369 img->put.contig = put2bitcmaptile; 2370 break; 2371 case 1: 2372 img->put.contig = put1bitcmaptile; 2373 break; 2374 } 2375 } 2376 break; 2377 case PHOTOMETRIC_MINISWHITE: 2378 case PHOTOMETRIC_MINISBLACK: 2379 if (buildMap(img)) { 2380 switch (img->bitspersample) { 2381 case 16: 2382 img->put.contig = put16bitbwtile; 2383 break; 2384 case 8: 2385 img->put.contig = putgreytile; 2386 break; 2387 case 4: 2388 img->put.contig = put4bitbwtile; 2389 break; 2390 case 2: 2391 img->put.contig = put2bitbwtile; 2392 break; 2393 case 1: 2394 img->put.contig = put1bitbwtile; 2395 break; 2396 } 2397 } 2398 break; 2399 case PHOTOMETRIC_YCBCR: 2400 if (img->bitspersample == 8) 2401 { 2402 if (initYCbCrConversion(img)!=0) 2403 { 2404 /* 2405 * The 6.0 spec says that subsampling must be 2406 * one of 1, 2, or 4, and that vertical subsampling 2407 * must always be <= horizontal subsampling; so 2408 * there are only a few possibilities and we just 2409 * enumerate the cases. 2410 * Joris: added support for the [1,2] case, nonetheless, to accomodate 2411 * some OJPEG files 2412 */ 2413 uint16 SubsamplingHor; 2414 uint16 SubsamplingVer; 2415 TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &SubsamplingHor, &SubsamplingVer); 2416 switch ((SubsamplingHor<<4)|SubsamplingVer) { 2417 case 0x44: 2418 img->put.contig = putcontig8bitYCbCr44tile; 2419 break; 2420 case 0x42: 2421 img->put.contig = putcontig8bitYCbCr42tile; 2422 break; 2423 case 0x41: 2424 img->put.contig = putcontig8bitYCbCr41tile; 2425 break; 2426 case 0x22: 2427 img->put.contig = putcontig8bitYCbCr22tile; 2428 break; 2429 case 0x21: 2430 img->put.contig = putcontig8bitYCbCr21tile; 2431 break; 2432 case 0x12: 2433 img->put.contig = putcontig8bitYCbCr12tile; 2434 break; 2435 case 0x11: 2436 img->put.contig = putcontig8bitYCbCr11tile; 2437 break; 2438 } 2439 } 2440 } 2441 break; 2442 case PHOTOMETRIC_CIELAB: 2443 if (buildMap(img)) { 2444 if (img->bitspersample == 8) 2445 img->put.contig = initCIELabConversion(img); 2446 break; 2447 } 2448 } 2449 return ((img->get!=NULL) && (img->put.contig!=NULL)); 2450} 2451 2452/* 2453 * Select the appropriate conversion routine for unpacked data. 2454 * 2455 * NB: we assume that unpacked single channel data is directed 2456 * to the "packed routines. 2457 */ 2458static int 2459PickSeparateCase(TIFFRGBAImage* img) 2460{ 2461 img->get = TIFFIsTiled(img->tif) ? gtTileSeparate : gtStripSeparate; 2462 img->put.separate = NULL; 2463 switch (img->photometric) { 2464 case PHOTOMETRIC_RGB: 2465 switch (img->bitspersample) { 2466 case 8: 2467 if (img->alpha == EXTRASAMPLE_ASSOCALPHA) 2468 img->put.separate = putRGBAAseparate8bittile; 2469 else if (img->alpha == EXTRASAMPLE_UNASSALPHA) 2470 { 2471 img->put.separate = putRGBUAseparate8bittile; 2472 } 2473 else 2474 img->put.separate = putRGBseparate8bittile; 2475 break; 2476 case 16: 2477 if (img->alpha == EXTRASAMPLE_ASSOCALPHA) 2478 { 2479 img->put.separate = putRGBAAseparate16bittile; 2480 } 2481 else if (img->alpha == EXTRASAMPLE_UNASSALPHA) 2482 { 2483 img->put.separate = putRGBUAseparate16bittile; 2484 } 2485 else 2486 { 2487 img->put.separate = putRGBseparate16bittile; 2488 } 2489 break; 2490 } 2491 break; 2492 case PHOTOMETRIC_YCBCR: 2493 if ((img->bitspersample==8) && (img->samplesperpixel==3)) 2494 { 2495 if (initYCbCrConversion(img)!=0) 2496 { 2497 uint16 hs, vs; 2498 TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs); 2499 switch ((hs<<4)|vs) { 2500 case 0x11: 2501 img->put.separate = putseparate8bitYCbCr11tile; 2502 break; 2503 /* TODO: add other cases here */ 2504 } 2505 } 2506 } 2507 break; 2508 } 2509 return ((img->get!=NULL) && (img->put.separate!=NULL)); 2510} 2511 2512/* 2513 * Read a whole strip off data from the file, and convert to RGBA form. 2514 * If this is the last strip, then it will only contain the portion of 2515 * the strip that is actually within the image space. The result is 2516 * organized in bottom to top form. 2517 */ 2518 2519 2520int 2521TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster ) 2522 2523{ 2524 char emsg[1024] = ""; 2525 TIFFRGBAImage img; 2526 int ok; 2527 uint32 rowsperstrip, rows_to_read; 2528 2529 if( TIFFIsTiled( tif ) ) 2530 { 2531 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), 2532 "Can't use TIFFReadRGBAStrip() with tiled file."); 2533 return (0); 2534 } 2535 2536 TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); 2537 if( (row % rowsperstrip) != 0 ) 2538 { 2539 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), 2540 "Row passed to TIFFReadRGBAStrip() must be first in a strip."); 2541 return (0); 2542 } 2543 2544 if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, 0, emsg)) { 2545 2546 img.row_offset = row; 2547 img.col_offset = 0; 2548 2549 if( row + rowsperstrip > img.height ) 2550 rows_to_read = img.height - row; 2551 else 2552 rows_to_read = rowsperstrip; 2553 2554 ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read ); 2555 2556 TIFFRGBAImageEnd(&img); 2557 } else { 2558 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); 2559 ok = 0; 2560 } 2561 2562 return (ok); 2563} 2564 2565/* 2566 * Read a whole tile off data from the file, and convert to RGBA form. 2567 * The returned RGBA data is organized from bottom to top of tile, 2568 * and may include zeroed areas if the tile extends off the image. 2569 */ 2570 2571int 2572TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) 2573 2574{ 2575 char emsg[1024] = ""; 2576 TIFFRGBAImage img; 2577 int ok; 2578 uint32 tile_xsize, tile_ysize; 2579 uint32 read_xsize, read_ysize; 2580 uint32 i_row; 2581 2582 /* 2583 * Verify that our request is legal - on a tile file, and on a 2584 * tile boundary. 2585 */ 2586 2587 if( !TIFFIsTiled( tif ) ) 2588 { 2589 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), 2590 "Can't use TIFFReadRGBATile() with stripped file."); 2591 return (0); 2592 } 2593 2594 TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize); 2595 TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize); 2596 if( (col % tile_xsize) != 0 || (row % tile_ysize) != 0 ) 2597 { 2598 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), 2599 "Row/col passed to TIFFReadRGBATile() must be top" 2600 "left corner of a tile."); 2601 return (0); 2602 } 2603 2604 /* 2605 * Setup the RGBA reader. 2606 */ 2607 2608 if (!TIFFRGBAImageOK(tif, emsg) 2609 || !TIFFRGBAImageBegin(&img, tif, 0, emsg)) { 2610 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); 2611 return( 0 ); 2612 } 2613 2614 /* 2615 * The TIFFRGBAImageGet() function doesn't allow us to get off the 2616 * edge of the image, even to fill an otherwise valid tile. So we 2617 * figure out how much we can read, and fix up the tile buffer to 2618 * a full tile configuration afterwards. 2619 */ 2620 2621 if( row + tile_ysize > img.height ) 2622 read_ysize = img.height - row; 2623 else 2624 read_ysize = tile_ysize; 2625 2626 if( col + tile_xsize > img.width ) 2627 read_xsize = img.width - col; 2628 else 2629 read_xsize = tile_xsize; 2630 2631 /* 2632 * Read the chunk of imagery. 2633 */ 2634 2635 img.row_offset = row; 2636 img.col_offset = col; 2637 2638 ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize ); 2639 2640 TIFFRGBAImageEnd(&img); 2641 2642 /* 2643 * If our read was incomplete we will need to fix up the tile by 2644 * shifting the data around as if a full tile of data is being returned. 2645 * 2646 * This is all the more complicated because the image is organized in 2647 * bottom to top format. 2648 */ 2649 2650 if( read_xsize == tile_xsize && read_ysize == tile_ysize ) 2651 return( ok ); 2652 2653 for( i_row = 0; i_row < read_ysize; i_row++ ) { 2654 memmove( raster + (tile_ysize - i_row - 1) * tile_xsize, 2655 raster + (read_ysize - i_row - 1) * read_xsize, 2656 read_xsize * sizeof(uint32) ); 2657 _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize+read_xsize, 2658 0, sizeof(uint32) * (tile_xsize - read_xsize) ); 2659 } 2660 2661 for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) { 2662 _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize, 2663 0, sizeof(uint32) * tile_xsize ); 2664 } 2665 2666 return (ok); 2667} 2668 2669/* vim: set ts=8 sts=8 sw=8 noet: */ 2670/* 2671 * Local Variables: 2672 * mode: c 2673 * c-basic-offset: 8 2674 * fill-column: 78 2675 * End: 2676 */ 2677