Esempio n. 1
0
bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width,
        int *height) {
    png_structp png_ptr;
    png_infop   info_ptr;

    this->index = new SkPNGImageIndex();

    if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) {
        return false;
    }

// 2013.02.07, jiseon.kwon, set error handling in onBuildTileIndex [START]
    if (setjmp(png_jmpbuf(png_ptr))) {
        return false;
    }
// 2013.02.07, jiseon.kwon, set error handling in onBuildTileIndex [END]

    int bit_depth, color_type, interlace_type;
    png_uint_32 origWidth, origHeight;
    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
            &color_type, &interlace_type, int_p_NULL, int_p_NULL);

    *width = origWidth;
    *height = origHeight;

    png_build_index(png_ptr);
    this->index->png_ptr = png_ptr;
    this->index->info_ptr = info_ptr;
    return true;
}
bool SkPNGImageDecoder::buildTileIndex(SkStream* sk_stream,
                int *width, int *height, bool isShareable) {
    png_structp png_ptr;
    png_infop   info_ptr;

    this->index = new SkPNGImageIndex();

    if (!isShareable) {
        size_t len, inputLen = 0;
        size_t bufferSize = 4096;
        void *tmp = sk_malloc_throw(bufferSize);

        while ((len = sk_stream->read((char*) tmp + inputLen,
                        bufferSize - inputLen)) != 0) {
            inputLen += len;
            if (inputLen == bufferSize) {
                bufferSize *= 2;
                tmp = sk_realloc_throw(tmp, bufferSize);
            }
        }
        tmp = sk_realloc_throw(tmp, inputLen);

        SkMemoryStream *mem_stream = new SkMemoryStream(tmp, inputLen, true);
        this->index->inputStream = mem_stream;
        sk_stream = mem_stream;
    }

    if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) {
        return false;
    }

    int bit_depth, color_type, interlace_type;
    png_uint_32 origWidth, origHeight;
    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
            &color_type, &interlace_type, int_p_NULL, int_p_NULL);

    *width = origWidth;
    *height = origHeight;

    png_build_index(png_ptr);
    this->index->png_ptr = png_ptr;
    this->index->info_ptr = info_ptr;
    return true;
}
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
                                 Mode mode) {
    png_structp png_ptr;
    png_infop info_ptr;

    if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) {
        return false;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        return false;
    }

    PNGAutoClean autoClean(png_ptr, info_ptr);

    png_uint_32 origWidth, origHeight;
    int bit_depth, color_type, interlace_type;
    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
            &color_type, &interlace_type, int_p_NULL, int_p_NULL);

    SkBitmap::Config    config;
    bool                hasAlpha = false;
    bool                doDither = this->getDitherImage();
    SkPMColor           theTranspColor = 0; // 0 tells us not to try to match

    if (getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha,
                &doDither, &theTranspColor) == false) {
        return false;
    }

    const int sampleSize = this->getSampleSize();
    SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);

    decodedBitmap->setConfig(config, sampler.scaledWidth(),
                             sampler.scaledHeight(), 0);
    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
        return true;
    }

    // from here down we are concerned with colortables and pixels

    // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
    // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
    // draw lots faster if we can flag the bitmap has being opaque
    bool reallyHasAlpha = false;
    SkColorTable* colorTable = NULL;

    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        decodePalette(png_ptr, info_ptr, &hasAlpha,
                &reallyHasAlpha, &colorTable);
    }

    SkAutoUnref aur(colorTable);

    if (!this->allocPixelRef(decodedBitmap,
                             SkBitmap::kIndex8_Config == config ?
                                colorTable : NULL)) {
        return false;
    }

    SkAutoLockPixels alp(*decodedBitmap);

    /* Add filler (or alpha) byte (before/after each RGB triplet) */
    if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) {
        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
    }

    /* Turn on interlace handling.  REQUIRED if you are not using
    * png_read_image().  To see how to handle interlacing passes,
    * see the png_read_row() method below:
    */
    const int number_passes = interlace_type != PNG_INTERLACE_NONE ?
                        png_set_interlace_handling(png_ptr) : 1;

    /* Optional call to gamma correct and add the background to the palette
    * and update info structure.  REQUIRED if you are expecting libpng to
    * update the palette for you (ie you selected such a transform above).
    */
    png_read_update_info(png_ptr, info_ptr);

    if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
        for (int i = 0; i < number_passes; i++) {
            for (png_uint_32 y = 0; y < origHeight; y++) {
                uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
            }
        }
    } else {
        SkScaledBitmapSampler::SrcConfig sc;
        int srcBytesPerPixel = 4;

        if (colorTable != NULL) {
            sc = SkScaledBitmapSampler::kIndex;
            srcBytesPerPixel = 1;
        } else if (hasAlpha) {
            sc = SkScaledBitmapSampler::kRGBA;
        } else {
            sc = SkScaledBitmapSampler::kRGBX;
        }

        /*  We have to pass the colortable explicitly, since we may have one
            even if our decodedBitmap doesn't, due to the request that we
            upscale png's palette to a direct model
         */
        SkAutoLockColors ctLock(colorTable);
        if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) {
            return false;
        }
        const int height = decodedBitmap->height();

        if (number_passes > 1) {
            SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
            uint8_t* base = (uint8_t*)storage.get();
            size_t rb = origWidth * srcBytesPerPixel;

            for (int i = 0; i < number_passes; i++) {
                uint8_t* row = base;
                for (png_uint_32 y = 0; y < origHeight; y++) {
                    uint8_t* bmRow = row;
                    png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
                    row += rb;
                }
            }
            // now sample it
            base += sampler.srcY0() * rb;
            for (int y = 0; y < height; y++) {
                reallyHasAlpha |= sampler.next(base);
                base += sampler.srcDY() * rb;
            }
        } else {
            SkAutoMalloc storage(origWidth * srcBytesPerPixel);
            uint8_t* srcRow = (uint8_t*)storage.get();
            skip_src_rows(png_ptr, srcRow, sampler.srcY0());

            for (int y = 0; y < height; y++) {
                uint8_t* tmp = srcRow;
                png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
                reallyHasAlpha |= sampler.next(srcRow);
                if (y < height - 1) {
                    skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
                }
            }

            // skip the rest of the rows (if any)
            png_uint_32 read = (height - 1) * sampler.srcDY() +
                               sampler.srcY0() + 1;
            SkASSERT(read <= origHeight);
            skip_src_rows(png_ptr, srcRow, origHeight - read);
        }
    }

    /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
    png_read_end(png_ptr, info_ptr);

    if (0 != theTranspColor) {
        reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
    }
    decodedBitmap->setIsOpaque(!reallyHasAlpha);
    return true;
}