1 /////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas 4 // Digital Ltd. LLC 5 // 6 // All rights reserved. 7 // 8 // Redistribution and use in source and binary forms, with or without 9 // modification, are permitted provided that the following conditions are 10 // met: 11 // * Redistributions of source code must retain the above copyright 12 // notice, this list of conditions and the following disclaimer. 13 // * Redistributions in binary form must reproduce the above 14 // copyright notice, this list of conditions and the following disclaimer 15 // in the documentation and/or other materials provided with the 16 // distribution. 17 // * Neither the name of Industrial Light & Magic nor the names of 18 // its contributors may be used to endorse or promote products derived 19 // from this software without specific prior written permission. 20 // 21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 // 33 /////////////////////////////////////////////////////////////////////////// 34 35 36 37 //----------------------------------------------------------------------------- 38 // 39 // Miscellaneous helper functions for OpenEXR image file I/O 40 // 41 //----------------------------------------------------------------------------- 42 43 #include <ImfMisc.h> 44 #include <ImfHeader.h> 45 #include <ImfCompressor.h> 46 #include <ImfChannelList.h> 47 #include <ImfXdr.h> 48 #include <ImathFun.h> 49 #include <Iex.h> 50 #include <ImfStdIO.h> 51 #include <ImfConvert.h> 52 53 namespace Imf { 54 55 using Imath::Box2i; 56 using Imath::divp; 57 using Imath::modp; 58 using std::vector; 59 60 int 61 pixelTypeSize (PixelType type) 62 { 63 int size; 64 65 switch (type) 66 { 67 case UINT: 68 69 size = Xdr::size <unsigned int> (); 70 break; 71 72 case HALF: 73 74 size = Xdr::size <half> (); 75 break; 76 77 case FLOAT: 78 79 size = Xdr::size <float> (); 80 break; 81 82 default: 83 84 throw Iex::ArgExc ("Unknown pixel type."); 85 } 86 87 return size; 88 } 89 90 91 int 92 numSamples (int s, int a, int b) 93 { 94 int a1 = divp (a, s); 95 int b1 = divp (b, s); 96 return b1 - a1 + ((a1 * s < a)? 0: 1); 97 } 98 99 100 size_t 101 bytesPerLineTable (const Header &header, 102 vector<size_t> &bytesPerLine) 103 { 104 const Box2i &dataWindow = header.dataWindow(); 105 const ChannelList &channels = header.channels(); 106 107 bytesPerLine.resize (dataWindow.max.y - dataWindow.min.y + 1); 108 109 for (ChannelList::ConstIterator c = channels.begin(); 110 c != channels.end(); 111 ++c) 112 { 113 int nBytes = pixelTypeSize (c.channel().type) * 114 (dataWindow.max.x - dataWindow.min.x + 1) / 115 c.channel().xSampling; 116 117 for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i) 118 if (modp (y, c.channel().ySampling) == 0) 119 bytesPerLine[i] += nBytes; 120 } 121 122 size_t maxBytesPerLine = 0; 123 124 for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i) 125 if (maxBytesPerLine < bytesPerLine[i]) 126 maxBytesPerLine = bytesPerLine[i]; 127 128 return maxBytesPerLine; 129 } 130 131 132 void 133 offsetInLineBufferTable (const vector<size_t> &bytesPerLine, 134 int linesInLineBuffer, 135 vector<size_t> &offsetInLineBuffer) 136 { 137 offsetInLineBuffer.resize (bytesPerLine.size()); 138 139 size_t offset = 0; 140 141 for (int i = 0; i < bytesPerLine.size(); ++i) 142 { 143 if (i % linesInLineBuffer == 0) 144 offset = 0; 145 146 offsetInLineBuffer[i] = offset; 147 offset += bytesPerLine[i]; 148 } 149 } 150 151 152 int 153 lineBufferMinY (int y, int minY, int linesInLineBuffer) 154 { 155 return ((y - minY) / linesInLineBuffer) * linesInLineBuffer + minY; 156 } 157 158 159 int 160 lineBufferMaxY (int y, int minY, int linesInLineBuffer) 161 { 162 return lineBufferMinY (y, minY, linesInLineBuffer) + linesInLineBuffer - 1; 163 } 164 165 166 Compressor::Format 167 defaultFormat (Compressor * compressor) 168 { 169 return compressor? compressor->format(): Compressor::XDR; 170 } 171 172 173 int 174 numLinesInBuffer (Compressor * compressor) 175 { 176 return compressor? compressor->numScanLines(): 1; 177 } 178 179 180 void 181 copyIntoFrameBuffer (const char *& readPtr, 182 char * writePtr, 183 char * endPtr, 184 size_t xStride, 185 bool fill, 186 double fillValue, 187 Compressor::Format format, 188 PixelType typeInFrameBuffer, 189 PixelType typeInFile) 190 { 191 // 192 // Copy a horizontal row of pixels from an input 193 // file's line or tile buffer to a frame buffer. 194 // 195 196 if (fill) 197 { 198 // 199 // The file contains no data for this channel. 200 // Store a default value in the frame buffer. 201 // 202 203 switch (typeInFrameBuffer) 204 { 205 case UINT: 206 207 { 208 unsigned int fillVal = (unsigned int) (fillValue); 209 210 while (writePtr <= endPtr) 211 { 212 *(unsigned int *) writePtr = fillVal; 213 writePtr += xStride; 214 } 215 } 216 break; 217 218 case HALF: 219 220 { 221 half fillVal = half (fillValue); 222 223 while (writePtr <= endPtr) 224 { 225 *(half *) writePtr = fillVal; 226 writePtr += xStride; 227 } 228 } 229 break; 230 231 case FLOAT: 232 233 { 234 float fillVal = float (fillValue); 235 236 while (writePtr <= endPtr) 237 { 238 *(float *) writePtr = fillVal; 239 writePtr += xStride; 240 } 241 } 242 break; 243 244 default: 245 246 throw Iex::ArgExc ("Unknown pixel data type."); 247 } 248 } 249 else if (format == Compressor::XDR) 250 { 251 // 252 // The the line or tile buffer is in XDR format. 253 // 254 // Convert the pixels from the file's machine- 255 // independent representation, and store the 256 // results in the frame buffer. 257 // 258 259 switch (typeInFrameBuffer) 260 { 261 case UINT: 262 263 switch (typeInFile) 264 { 265 case UINT: 266 267 while (writePtr <= endPtr) 268 { 269 Xdr::read <CharPtrIO> (readPtr, *(unsigned int *) writePtr); 270 writePtr += xStride; 271 } 272 break; 273 274 case HALF: 275 276 while (writePtr <= endPtr) 277 { 278 half h; 279 Xdr::read <CharPtrIO> (readPtr, h); 280 *(unsigned int *) writePtr = halfToUint (h); 281 writePtr += xStride; 282 } 283 break; 284 285 case FLOAT: 286 287 while (writePtr <= endPtr) 288 { 289 float f; 290 Xdr::read <CharPtrIO> (readPtr, f); 291 *(unsigned int *)writePtr = floatToUint (f); 292 writePtr += xStride; 293 } 294 break; 295 } 296 break; 297 298 case HALF: 299 300 switch (typeInFile) 301 { 302 case UINT: 303 304 while (writePtr <= endPtr) 305 { 306 unsigned int ui; 307 Xdr::read <CharPtrIO> (readPtr, ui); 308 *(half *) writePtr = uintToHalf (ui); 309 writePtr += xStride; 310 } 311 break; 312 313 case HALF: 314 315 while (writePtr <= endPtr) 316 { 317 Xdr::read <CharPtrIO> (readPtr, *(half *) writePtr); 318 writePtr += xStride; 319 } 320 break; 321 322 case FLOAT: 323 324 while (writePtr <= endPtr) 325 { 326 float f; 327 Xdr::read <CharPtrIO> (readPtr, f); 328 *(half *) writePtr = floatToHalf (f); 329 writePtr += xStride; 330 } 331 break; 332 } 333 break; 334 335 case FLOAT: 336 337 switch (typeInFile) 338 { 339 case UINT: 340 341 while (writePtr <= endPtr) 342 { 343 unsigned int ui; 344 Xdr::read <CharPtrIO> (readPtr, ui); 345 *(float *) writePtr = float (ui); 346 writePtr += xStride; 347 } 348 break; 349 350 case HALF: 351 352 while (writePtr <= endPtr) 353 { 354 half h; 355 Xdr::read <CharPtrIO> (readPtr, h); 356 *(float *) writePtr = float (h); 357 writePtr += xStride; 358 } 359 break; 360 361 case FLOAT: 362 363 while (writePtr <= endPtr) 364 { 365 Xdr::read <CharPtrIO> (readPtr, *(float *) writePtr); 366 writePtr += xStride; 367 } 368 break; 369 } 370 break; 371 372 default: 373 374 throw Iex::ArgExc ("Unknown pixel data type."); 375 } 376 } 377 else 378 { 379 // 380 // The the line or tile buffer is in NATIVE format. 381 // Copy the results into the frame buffer. 382 // 383 384 switch (typeInFrameBuffer) 385 { 386 case UINT: 387 388 switch (typeInFile) 389 { 390 case UINT: 391 392 while (writePtr <= endPtr) 393 { 394 for (size_t i = 0; i < sizeof (unsigned int); ++i) 395 writePtr[i] = readPtr[i]; 396 397 readPtr += sizeof (unsigned int); 398 writePtr += xStride; 399 } 400 break; 401 402 case HALF: 403 404 while (writePtr <= endPtr) 405 { 406 half h = *(half *) readPtr; 407 *(unsigned int *) writePtr = halfToUint (h); 408 readPtr += sizeof (half); 409 writePtr += xStride; 410 } 411 break; 412 413 case FLOAT: 414 415 while (writePtr <= endPtr) 416 { 417 float f; 418 419 for (size_t i = 0; i < sizeof (float); ++i) 420 ((char *)&f)[i] = readPtr[i]; 421 422 *(unsigned int *)writePtr = floatToUint (f); 423 readPtr += sizeof (float); 424 writePtr += xStride; 425 } 426 break; 427 } 428 break; 429 430 case HALF: 431 432 switch (typeInFile) 433 { 434 case UINT: 435 436 while (writePtr <= endPtr) 437 { 438 unsigned int ui; 439 440 for (size_t i = 0; i < sizeof (unsigned int); ++i) 441 ((char *)&ui)[i] = readPtr[i]; 442 443 *(half *) writePtr = uintToHalf (ui); 444 readPtr += sizeof (unsigned int); 445 writePtr += xStride; 446 } 447 break; 448 449 case HALF: 450 451 while (writePtr <= endPtr) 452 { 453 *(half *) writePtr = *(half *)readPtr; 454 readPtr += sizeof (half); 455 writePtr += xStride; 456 } 457 break; 458 459 case FLOAT: 460 461 while (writePtr <= endPtr) 462 { 463 float f; 464 465 for (size_t i = 0; i < sizeof (float); ++i) 466 ((char *)&f)[i] = readPtr[i]; 467 468 *(half *) writePtr = floatToHalf (f); 469 readPtr += sizeof (float); 470 writePtr += xStride; 471 } 472 break; 473 } 474 break; 475 476 case FLOAT: 477 478 switch (typeInFile) 479 { 480 case UINT: 481 482 while (writePtr <= endPtr) 483 { 484 unsigned int ui; 485 486 for (size_t i = 0; i < sizeof (unsigned int); ++i) 487 ((char *)&ui)[i] = readPtr[i]; 488 489 *(float *) writePtr = float (ui); 490 readPtr += sizeof (unsigned int); 491 writePtr += xStride; 492 } 493 break; 494 495 case HALF: 496 497 while (writePtr <= endPtr) 498 { 499 half h = *(half *) readPtr; 500 *(float *) writePtr = float (h); 501 readPtr += sizeof (half); 502 writePtr += xStride; 503 } 504 break; 505 506 case FLOAT: 507 508 while (writePtr <= endPtr) 509 { 510 for (size_t i = 0; i < sizeof (float); ++i) 511 writePtr[i] = readPtr[i]; 512 513 readPtr += sizeof (float); 514 writePtr += xStride; 515 } 516 break; 517 } 518 break; 519 520 default: 521 522 throw Iex::ArgExc ("Unknown pixel data type."); 523 } 524 } 525 } 526 527 528 void 529 skipChannel (const char *& readPtr, 530 PixelType typeInFile, 531 size_t xSize) 532 { 533 switch (typeInFile) 534 { 535 case UINT: 536 537 Xdr::skip <CharPtrIO> (readPtr, Xdr::size <unsigned int> () * xSize); 538 break; 539 540 case HALF: 541 542 Xdr::skip <CharPtrIO> (readPtr, Xdr::size <half> () * xSize); 543 break; 544 545 case FLOAT: 546 547 Xdr::skip <CharPtrIO> (readPtr, Xdr::size <float> () * xSize); 548 break; 549 550 default: 551 552 throw Iex::ArgExc ("Unknown pixel data type."); 553 } 554 } 555 556 557 void 558 convertInPlace (char *& writePtr, 559 const char *& readPtr, 560 PixelType type, 561 size_t numPixels) 562 { 563 switch (type) 564 { 565 case UINT: 566 567 for (int j = 0; j < numPixels; ++j) 568 { 569 Xdr::write <CharPtrIO> (writePtr, *(const unsigned int *) readPtr); 570 readPtr += sizeof(unsigned int); 571 } 572 break; 573 574 case HALF: 575 576 for (int j = 0; j < numPixels; ++j) 577 { 578 Xdr::write <CharPtrIO> (writePtr, *(const half *) readPtr); 579 readPtr += sizeof(half); 580 } 581 break; 582 583 case FLOAT: 584 585 for (int j = 0; j < numPixels; ++j) 586 { 587 Xdr::write <CharPtrIO> (writePtr, *(const float *) readPtr); 588 readPtr += sizeof(float); 589 } 590 break; 591 592 default: 593 594 throw Iex::ArgExc ("Unknown pixel data type."); 595 } 596 } 597 598 599 void 600 copyFromFrameBuffer (char *& writePtr, 601 const char *& readPtr, 602 const char * endPtr, 603 size_t xStride, 604 Compressor::Format format, 605 PixelType type) 606 { 607 // 608 // Copy a horizontal row of pixels from a frame 609 // buffer to an output file's line or tile buffer. 610 // 611 612 if (format == Compressor::XDR) 613 { 614 // 615 // The the line or tile buffer is in XDR format. 616 // 617 618 switch (type) 619 { 620 case UINT: 621 622 while (readPtr <= endPtr) 623 { 624 Xdr::write <CharPtrIO> (writePtr, 625 *(const unsigned int *) readPtr); 626 readPtr += xStride; 627 } 628 break; 629 630 case HALF: 631 632 while (readPtr <= endPtr) 633 { 634 Xdr::write <CharPtrIO> (writePtr, *(const half *) readPtr); 635 readPtr += xStride; 636 } 637 break; 638 639 case FLOAT: 640 641 while (readPtr <= endPtr) 642 { 643 Xdr::write <CharPtrIO> (writePtr, *(const float *) readPtr); 644 readPtr += xStride; 645 } 646 break; 647 648 default: 649 650 throw Iex::ArgExc ("Unknown pixel data type."); 651 } 652 } 653 else 654 { 655 // 656 // The the line or tile buffer is in NATIVE format. 657 // 658 659 switch (type) 660 { 661 case UINT: 662 663 while (readPtr <= endPtr) 664 { 665 for (size_t i = 0; i < sizeof (unsigned int); ++i) 666 *writePtr++ = readPtr[i]; 667 668 readPtr += xStride; 669 } 670 break; 671 672 case HALF: 673 674 while (readPtr <= endPtr) 675 { 676 *(half *) writePtr = *(const half *) readPtr; 677 writePtr += sizeof (half); 678 readPtr += xStride; 679 } 680 break; 681 682 case FLOAT: 683 684 while (readPtr <= endPtr) 685 { 686 for (size_t i = 0; i < sizeof (float); ++i) 687 *writePtr++ = readPtr[i]; 688 689 readPtr += xStride; 690 } 691 break; 692 693 default: 694 695 throw Iex::ArgExc ("Unknown pixel data type."); 696 } 697 } 698 } 699 700 701 void 702 fillChannelWithZeroes (char *& writePtr, 703 Compressor::Format format, 704 PixelType type, 705 size_t xSize) 706 { 707 if (format == Compressor::XDR) 708 { 709 // 710 // Fill with data in XDR format. 711 // 712 713 switch (type) 714 { 715 case UINT: 716 717 for (int j = 0; j < xSize; ++j) 718 Xdr::write <CharPtrIO> (writePtr, (unsigned int) 0); 719 720 break; 721 722 case HALF: 723 724 for (int j = 0; j < xSize; ++j) 725 Xdr::write <CharPtrIO> (writePtr, (half) 0); 726 727 break; 728 729 case FLOAT: 730 731 for (int j = 0; j < xSize; ++j) 732 Xdr::write <CharPtrIO> (writePtr, (float) 0); 733 734 break; 735 736 default: 737 738 throw Iex::ArgExc ("Unknown pixel data type."); 739 } 740 } 741 else 742 { 743 // 744 // Fill with data in NATIVE format. 745 // 746 747 switch (type) 748 { 749 case UINT: 750 751 for (int j = 0; j < xSize; ++j) 752 { 753 static const unsigned int ui = 0; 754 755 for (size_t i = 0; i < sizeof (ui); ++i) 756 *writePtr++ = ((char *) &ui)[i]; 757 } 758 break; 759 760 case HALF: 761 762 for (int j = 0; j < xSize; ++j) 763 { 764 *(half *) writePtr = half (0); 765 writePtr += sizeof (half); 766 } 767 break; 768 769 case FLOAT: 770 771 for (int j = 0; j < xSize; ++j) 772 { 773 static const float f = 0; 774 775 for (size_t i = 0; i < sizeof (f); ++i) 776 *writePtr++ = ((char *) &f)[i]; 777 } 778 break; 779 780 default: 781 782 throw Iex::ArgExc ("Unknown pixel data type."); 783 } 784 } 785 } 786 787 } // namespace Imf 788