Beispiel #1
0
static bool
colorconvert_impl (ImageBuf &R, const ImageBuf &A,
                   const ColorProcessor* processor, bool unpremult,
                   ROI roi, int nthreads)
{
    if (nthreads != 1 && roi.npixels() >= 1000) {
        // Possible multiple thread case -- recurse via parallel_image
        ImageBufAlgo::parallel_image (
            OIIO::bind(colorconvert_impl<Rtype,Atype>,
                        OIIO::ref(R), OIIO::cref(A), processor, unpremult,
                        _1 /*roi*/, 1 /*nthreads*/),
            roi, nthreads);
        return true;
    }

    // Serial case

    int width = roi.width();
    // Temporary space to hold one RGBA scanline
    std::vector<float> scanline(width*4, 0.0f);
    
    // Only process up to, and including, the first 4 channels.  This
    // does let us process images with fewer than 4 channels, which is
    // the intent.
    // FIXME: Instead of loading the first 4 channels, obey
    //        Rspec.alpha_channel index (but first validate that the
    //        index is set properly for normal formats)
    
    int channelsToCopy = std::min (4, roi.nchannels());
    
    // Walk through all data in our buffer. (i.e., crop or overscan)
    // FIXME: What about the display window?  Should this actually promote
    // the datawindow to be union of data + display? This is useful if
    // the color of black moves.  (In which case non-zero sections should
    // now be promoted).  Consider the lin->log of a roto element, where
    // black now moves to non-black.
    
    float * dstPtr = NULL;
    const float fltmin = std::numeric_limits<float>::min();
    
    // If the processor has crosstalk, and we'll be using it, we should
    // reset the channels to 0 before loading each scanline.
    bool clearScanline = (channelsToCopy<4 && 
                          (processor->hasChannelCrosstalk() || unpremult));
    
    ImageBuf::ConstIterator<Atype> a (A, roi);
    ImageBuf::Iterator<Rtype> r (R, roi);
    for (int k = roi.zbegin; k < roi.zend; ++k) {
        for (int j = roi.ybegin; j < roi.yend; ++j) {
            // Clear the scanline
            if (clearScanline)
                memset (&scanline[0], 0, sizeof(float)*scanline.size());
            
            // Load the scanline
            dstPtr = &scanline[0];
            a.rerange (roi.xbegin, roi.xend, j, j+1, k, k+1);
            for ( ; !a.done(); ++a, dstPtr += 4)
                for (int c = 0; c < channelsToCopy; ++c)
                    dstPtr[c] = a[c];

            // Optionally unpremult
            if ((channelsToCopy >= 4) && unpremult) {
                for (int i = 0; i < width; ++i) {
                    float alpha = scanline[4*i+3];
                    if (alpha > fltmin) {
                        scanline[4*i+0] /= alpha;
                        scanline[4*i+1] /= alpha;
                        scanline[4*i+2] /= alpha;
                    }
                }
            }
            
            // Apply the color transformation in place
            processor->apply (&scanline[0], width, 1, 4,
                              sizeof(float), 4*sizeof(float),
                              width*4*sizeof(float));
            
            // Optionally premult
            if ((channelsToCopy >= 4) && unpremult) {
                for (int i = 0; i < width; ++i) {
                    float alpha = scanline[4*i+3];
                    if (alpha > fltmin) {
                        scanline[4*i+0] *= alpha;
                        scanline[4*i+1] *= alpha;
                        scanline[4*i+2] *= alpha;
                    }
                }
            }

            // Store the scanline
            dstPtr = &scanline[0];
            r.rerange (roi.xbegin, roi.xend, j, j+1, k, k+1);
            for ( ; !r.done(); ++r, dstPtr += 4)
                for (int c = 0; c < channelsToCopy; ++c)
                    r[c] = dstPtr[c];
        }
    }
    return true;
}