Пример #1
0
void GIFImageDecoder::prepEmptyFrameBuffer(RGBA32Buffer* buffer) 
{
    //+ 7/13/09 CSidhall - Added for alloc fail handling and cache space arranging.
    if(!buffer)
        return;
    buffer->setHasAlpha(true);   
    int size = m_size.width() * m_size.height();        
    setImagePruneLockStatus(true);  // Lock against pruning this resource   
#ifdef _DEBUG   
    static bool overflowFlag = false;    // Avoid too many asserts
    bool cachePrune = cache()->pruneImages(size << 2);
    if(cachePrune == false){
        if(!overflowFlag){
            char buffer[256];
            sprintf(buffer, "RAM Cache Overflow: cache is too small to decode GIF image: %d bytes\n", (size << 2));
            EAW_ASSERT_MSG(cachePrune, buffer);        
            overflowFlag = true;
        }
        // Could exit here but we get into image skipping issues that still need to be worked out.
        // return false;
    }
#else
    cache()->pruneImages(size << 2);
#endif
    setImagePruneLockStatus(false);  // Unlock

    buffer->bytes().resize(size);
    if(buffer->bytes().data())      
        buffer->bytes().fill(0);
   
}
Пример #2
0
void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass)
{
    // Resize to the width and height of the image.
    RGBA32Buffer& buffer = m_frameBufferCache[0];

    //+ 7/13/09 CSidhall - Added buffer size check
    RGBA32Array& bytes = buffer.bytes(); 
    int curSize = bytes.size(); // Verify that buffer is actually there
    int size = m_size.width() * m_size.height();
    if ((buffer.status() == RGBA32Buffer::FrameEmpty) || (size != curSize)) {
    setImagePruneLockStatus(true);  // Lock against pruning this resource   
#ifdef _DEBUG   
    static bool overflowFlag = false;    // Avoid too many asserts
    bool cachePrune = cache()->pruneImages(size << 2);
    if(cachePrune == false) {
        if(!overflowFlag) {
            char buffer[256];
            sprintf(buffer, "RAM Cache Overflow: cache is too small to decode PNG image: %d bytes\n", (size<<2) );
            EAW_ASSERT_MSG(cachePrune, buffer);                       
            overflowFlag = true;    
        }
        // Could exit here but we get into image skipping issues that still need to be worked out.
        // return false;
    }
#else
    cache()->pruneImages(size << 2);
#endif
    setImagePruneLockStatus(false); 

        // Let's resize our buffer now to the correct width/height.
        bytes.resize(size);
        if(!bytes.data())
            return;
        //- CS
        
        // Update our status to be partially complete.
        buffer.setStatus(RGBA32Buffer::FramePartial);

        // For PNGs, the frame always fills the entire image.
        buffer.setRect(IntRect(0, 0, m_size.width(), m_size.height()));

        if (reader()->pngPtr()->interlaced)
            reader()->createInterlaceBuffer((reader()->hasAlpha() ? 4 : 3) * m_size.width() * m_size.height());
    }

    if (rowBuffer == 0)
        return;

   /* libpng comments (pasted in here to explain what follows)
    *
    * this function is called for every row in the image.  If the
    * image is interlacing, and you turned on the interlace handler,
    * this function will be called for every row in every pass.
    * Some of these rows will not be changed from the previous pass.
    * When the row is not changed, the new_row variable will be NULL.
    * The rows and passes are called in order, so you don't really
    * need the row_num and pass, but I'm supplying them because it
    * may make your life easier.
    *
    * For the non-NULL rows of interlaced images, you must call
    * png_progressive_combine_row() passing in the row and the
    * old row.  You can call this function for NULL rows (it will
    * just return) and for non-interlaced images (it just does the
    * memcpy for you) if it will make the code easier.  Thus, you
    * can just do this for all cases:
    *
    *    png_progressive_combine_row(png_ptr, old_row, new_row);
    *
    * where old_row is what was displayed for previous rows.  Note
    * that the first pass (pass == 0 really) will completely cover
    * the old row, so the rows do not have to be initialized.  After
    * the first pass (and only for interlaced images), you will have
    * to pass the current row, and the function will combine the
    * old row and the new row.
    */
 
    png_structp png = reader()->pngPtr();
    bool hasAlpha = reader()->hasAlpha();
    unsigned colorChannels = hasAlpha ? 4 : 3;
    png_bytep row;
    png_bytep interlaceBuffer = reader()->interlaceBuffer();
    if (interlaceBuffer) {
        row = interlaceBuffer + (rowIndex * colorChannels * m_size.width());
        png_progressive_combine_row(png, row, rowBuffer);
    }
    else
        row = rowBuffer;

    // Old code for reference:
/*
    // Copy the data into our buffer.
    int width = m_size.width();
    unsigned* dst = buffer.bytes().data() + rowIndex * width;
    bool sawAlpha = false;
    for (int i = 0; i < width; i++) {
        unsigned red = *row++;
        unsigned green = *row++;
        unsigned blue = *row++;
        unsigned alpha = (hasAlpha ? *row++ : 255);
        RGBA32Buffer::setRGBA(*dst++, red, green, blue, alpha);
        if (!sawAlpha && alpha < 255) {
            sawAlpha = true;
          buffer.setHasAlpha(true);
        }
    }
*/

    // New code:
    // EA/Alex Mole: don't check for alpha at 
    //every single pixel, only do it once per row
    if( hasAlpha )
    {
        // Copy the data into our buffer.
        int width = m_size.width();
        unsigned* dst = buffer.bytes().data() + rowIndex * width;

        // EA/Alex Mole: instead of testing whether we've seen any alpha at each pixel,
        //               we can AND together all of the alpha values and see if we end up
        //               with 255 or not.
        unsigned minalpha = 255;

        for (int i = 0; i < width; i++) {
            unsigned red = *row++;
            unsigned green = *row++;
            unsigned blue = *row++;

            // EA/Alex Mole
            unsigned alpha = *row++;
            minalpha = minalpha & alpha;

            RGBA32Buffer::setRGBA(*dst++, red, green, blue, alpha);
        }
        
        // EA/Alex Mole: see comment above minalpha declaration
        if (minalpha != 255) {
            buffer.setHasAlpha(true);
        }
    }
    else
    {
        // Copy the data into our buffer.
        int width = m_size.width();
        unsigned* dst = buffer.bytes().data() + rowIndex * width;
        for (int i = 0; i < width; i++) {
            unsigned red = *row++;
            unsigned green = *row++;
            unsigned blue = *row++;
            RGBA32Buffer::setRGBWithPresetAlpha(*dst++, red, green, blue);
        }
    }

    buffer.ensureHeight(rowIndex + 1);
}