예제 #1
0
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;
}
예제 #2
0
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;
}