bool TIFFOutput::write_scanline (int y, int z, TypeDesc format, const void *data, stride_t xstride) { m_spec.auto_stride (xstride, format, spec().nchannels); const void *origdata = data; data = to_native_scanline (format, data, xstride, m_scratch, m_dither, y, z); y -= m_spec.y; if (m_planarconfig == PLANARCONFIG_SEPARATE) { // Convert from contiguous (RGBRGBRGB) to separate (RRRGGGBBB) int plane_bytes = m_spec.width * m_spec.format.size(); std::vector<unsigned char> scratch2 (m_spec.scanline_bytes()); std::swap (m_scratch, scratch2); m_scratch.resize (m_spec.scanline_bytes()); contig_to_separate (m_spec.width, (const char *)data, (char *)&m_scratch[0]); for (int c = 0; c < m_spec.nchannels; ++c) { if (TIFFWriteScanline (m_tif, (tdata_t)&m_scratch[plane_bytes*c], y, c) < 0) { std::string err = oiio_tiff_last_error(); error ("TIFFWriteScanline failed writing line y=%d,z=%d (%s)", y, z, err.size() ? err.c_str() : "unknown error"); return false; } } } else { // No contig->separate is necessary. But we still use scratch // space since TIFFWriteScanline is destructive when // TIFFTAG_PREDICTOR is used. if (data == origdata) { m_scratch.assign ((unsigned char *)data, (unsigned char *)data+m_spec.scanline_bytes()); data = &m_scratch[0]; } if (TIFFWriteScanline (m_tif, (tdata_t)data, y) < 0) { std::string err = oiio_tiff_last_error(); error ("TIFFWriteScanline failed writing line y=%d,z=%d (%s)", y, z, err.size() ? err.c_str() : "unknown error"); return false; } } // Should we checkpoint? Only if we have enough scanlines and enough // time has passed (or if using JPEG compression, for which it seems // necessary). ++m_checkpointItems; if ((m_checkpointTimer() > DEFAULT_CHECKPOINT_INTERVAL_SECONDS || m_compression == COMPRESSION_JPEG) && m_checkpointItems >= MIN_SCANLINES_OR_TILES_PER_CHECKPOINT) { TIFFCheckpointDirectory (m_tif); m_checkpointTimer.lap(); m_checkpointItems = 0; } return true; }
bool TIFFOutput::write_scanline (int y, int z, TypeDesc format, const void *data, stride_t xstride) { m_spec.auto_stride (xstride, format, spec().nchannels); const void *origdata = data; data = to_native_scanline (format, data, xstride, m_scratch, m_dither, y, z); // Handle weird photometric/color spaces if (m_photometric == PHOTOMETRIC_SEPARATED) data = convert_to_cmyk (spec().width, data); // Handle weird bit depths if (spec().format.size()*8 != m_bitspersample) { // Move to scratch area if not already there imagesize_t nbytes = spec().scanline_bytes(); int nvals = spec().width * m_outputchans; if (data == origdata) { m_scratch.assign ((unsigned char *)data, (unsigned char *)data+nbytes); data = &m_scratch[0]; } if (spec().format == TypeDesc::UINT16 && m_bitspersample == 10) { convert_pack_bits<unsigned short, 10> ((unsigned short *)data, nvals); } else if (spec().format == TypeDesc::UINT16 && m_bitspersample == 12) { convert_pack_bits<unsigned short, 12> ((unsigned short *)data, nvals); } else if (spec().format == TypeDesc::UINT8 && m_bitspersample == 4) { convert_pack_bits<unsigned char, 4> ((unsigned char *)data, nvals); } else if (spec().format == TypeDesc::UINT8 && m_bitspersample == 2) { convert_pack_bits<unsigned char, 2> ((unsigned char *)data, nvals); } else { ASSERT (0 && "unsupported bit conversion -- shouldn't reach here"); } } y -= m_spec.y; if (m_planarconfig == PLANARCONFIG_SEPARATE) { // Convert from contiguous (RGBRGBRGB) to separate (RRRGGGBBB) int plane_bytes = m_spec.width * m_spec.format.size(); std::vector<unsigned char> scratch2 (m_spec.scanline_bytes()); std::swap (m_scratch, scratch2); m_scratch.resize (m_spec.scanline_bytes()); contig_to_separate (m_spec.width, (const char *)data, (char *)&m_scratch[0]); for (int c = 0; c < m_spec.nchannels; ++c) { if (TIFFWriteScanline (m_tif, (tdata_t)&m_scratch[plane_bytes*c], y, c) < 0) { std::string err = oiio_tiff_last_error(); error ("TIFFWriteScanline failed writing line y=%d,z=%d (%s)", y, z, err.size() ? err.c_str() : "unknown error"); return false; } } } else { // No contig->separate is necessary. But we still use scratch // space since TIFFWriteScanline is destructive when // TIFFTAG_PREDICTOR is used. if (data == origdata) { m_scratch.assign ((unsigned char *)data, (unsigned char *)data+m_spec.scanline_bytes()); data = &m_scratch[0]; } if (TIFFWriteScanline (m_tif, (tdata_t)data, y) < 0) { std::string err = oiio_tiff_last_error(); error ("TIFFWriteScanline failed writing line y=%d,z=%d (%s)", y, z, err.size() ? err.c_str() : "unknown error"); return false; } } // Should we checkpoint? Only if we have enough scanlines and enough // time has passed (or if using JPEG compression, for which it seems // necessary). ++m_checkpointItems; if ((m_checkpointTimer() > DEFAULT_CHECKPOINT_INTERVAL_SECONDS || m_compression == COMPRESSION_JPEG) && m_checkpointItems >= MIN_SCANLINES_OR_TILES_PER_CHECKPOINT) { TIFFCheckpointDirectory (m_tif); m_checkpointTimer.lap(); m_checkpointItems = 0; } return true; }