| 309 | } |
| 310 | |
| 311 | void ImageTargetFileTinyExr::finalize() |
| 312 | { |
| 313 | // turn interleaved data into a series of planar channels |
| 314 | vector<Channel32f> channels; |
| 315 | channels.reserve( mNumComponents ); |
| 316 | unsigned char * imagePtr[4]; |
| 317 | for( int c = 0; c < mNumComponents; ++c ) { |
| 318 | channels.emplace_back( getWidth(), getHeight() ); |
| 319 | Channel32f srcChannel( getWidth(), getHeight(), mNumComponents * mWidth * sizeof(float), mNumComponents, mData.data() + c ); |
| 320 | channels.back().copyFrom( srcChannel, srcChannel.getBounds() ); |
| 321 | |
| 322 | imagePtr[c] = reinterpret_cast<unsigned char *>( channels[c].getData() ); |
| 323 | } |
| 324 | |
| 325 | int pixelTypes[4], requested_pixel_types[4]; |
| 326 | for( int i = 0; i < mNumComponents; i++ ) { |
| 327 | pixelTypes[i] = TINYEXR_PIXELTYPE_FLOAT; |
| 328 | requested_pixel_types[i] = TINYEXR_PIXELTYPE_HALF; // export as half-floats to reduce file size |
| 329 | } |
| 330 | |
| 331 | std::vector<EXRChannelInfo> info( mNumComponents ); |
| 332 | |
| 333 | // create image descriptor |
| 334 | EXRImage exrImage; |
| 335 | InitEXRImage( &exrImage ); |
| 336 | |
| 337 | exrImage.num_channels = mNumComponents; |
| 338 | exrImage.width = mWidth; |
| 339 | exrImage.height = mHeight; |
| 340 | exrImage.images = imagePtr; |
| 341 | |
| 342 | // create header descriptor |
| 343 | EXRHeader exrHeader; |
| 344 | InitEXRHeader( &exrHeader ); |
| 345 | |
| 346 | exrHeader.num_channels = mNumComponents; |
| 347 | exrHeader.channels = info.data(); |
| 348 | for( int i = 0; i < mNumComponents; ++i ) { |
| 349 | strncpy( exrHeader.channels[i].name, mChannelNames[i].data(), mChannelNames[i].size() ); |
| 350 | } |
| 351 | exrHeader.pixel_types = pixelTypes; |
| 352 | exrHeader.requested_pixel_types = requested_pixel_types; |
| 353 | // Use ZIP compression by default for better file sizes while maintaining good performance |
| 354 | exrHeader.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP; |
| 355 | |
| 356 | const char *error = nullptr; |
| 357 | |
| 358 | const int status = SaveEXRImageToFile( &exrImage, &exrHeader, mFilePath.string().c_str(), &error ); |
| 359 | if( status != TINYEXR_SUCCESS ) { |
| 360 | string errorMsg = error ? string( "TinyExr: failed to write. Error: " ) + error : "TinyExr: failed to write"; |
| 361 | if( error ) |
| 362 | FreeEXRErrorMessage( error ); |
| 363 | throw ImageIoExceptionFailedWriteTinyExr( errorMsg ); |
| 364 | } |
| 365 | |
| 366 | // Note: since header and image descriptors do not own any data, we explicitely do not call FreeEXRHeader and FreeEXRImage here! |
| 367 | } |
| 368 |
no test coverage detected