// Test Fill() with different combinations of dimensions, alignment, and padding
DEF_TEST(SwizzlerFill, r) {
    // Test on an invalid width and representative widths
    const uint32_t widths[] = { 0, 10, 50 };

    // In order to call Fill(), there must be at least one row to fill
    // Test on the smallest possible height and representative heights
    const uint32_t heights[] = { 1, 5, 10 };

    // Test on interesting possibilities for row padding
    const uint32_t paddings[] = { 0, 4 };

    // Iterate over test dimensions
    for (uint32_t width : widths) {
        for (uint32_t height : heights) {

            // Create image info objects
            const SkImageInfo colorInfo = SkImageInfo::MakeN32(width, height, kUnknown_SkAlphaType);
            const SkImageInfo grayInfo = colorInfo.makeColorType(kGray_8_SkColorType);
            const SkImageInfo indexInfo = colorInfo.makeColorType(kIndex_8_SkColorType);
            const SkImageInfo color565Info = colorInfo.makeColorType(kRGB_565_SkColorType);

            for (uint32_t padding : paddings) {

                // Calculate row bytes
                const size_t colorRowBytes = SkColorTypeBytesPerPixel(kN32_SkColorType) * width
                        + padding;
                const size_t indexRowBytes = width + padding;
                const size_t grayRowBytes = indexRowBytes;
                const size_t color565RowBytes =
                        SkColorTypeBytesPerPixel(kRGB_565_SkColorType) * width + padding;

                // If there is padding, we can invent an offset to change the memory alignment
                for (uint32_t offset = 0; offset <= padding; offset += 4) {

                    // Test all possible start rows with all possible end rows
                    for (uint32_t startRow = 0; startRow < height; startRow++) {
                        for (uint32_t endRow = startRow; endRow < height; endRow++) {

                            // Test fill with each color type
                            check_fill(r, colorInfo, startRow, endRow, colorRowBytes, offset,
                                    kFillColor);
                            check_fill(r, indexInfo, startRow, endRow, indexRowBytes, offset,
                                    kFillIndex);
                            check_fill(r, grayInfo, startRow, endRow, grayRowBytes, offset,
                                    kFillGray);
                            check_fill(r, color565Info, startRow, endRow, color565RowBytes, offset,
                                    kFill565);
                        }
                    }
                }
            }
        }
    }
}
static void draw_image(SkCanvas* canvas, SkImage* image, SkColorType dstColorType,
                       SkAlphaType dstAlphaType, sk_sp<SkColorSpace> dstColorSpace,
                       SkImage::CachingHint hint) {
    size_t rowBytes = image->width() * SkColorTypeBytesPerPixel(dstColorType);
    sk_sp<SkData> data = SkData::MakeUninitialized(rowBytes * image->height());
    dstColorSpace = fix_for_colortype(dstColorSpace.get(), dstColorType);
    SkImageInfo dstInfo = SkImageInfo::Make(image->width(), image->height(), dstColorType,
                                            dstAlphaType, dstColorSpace);
    if (!image->readPixels(dstInfo, data->writable_data(), rowBytes, 0, 0, hint)) {
        memset(data->writable_data(), 0, rowBytes * image->height());
    }

    // SkImage must be premul, so manually premul the data if we unpremul'd during readPixels
    if (kUnpremul_SkAlphaType == dstAlphaType) {
        auto xform = SkColorSpaceXform::New(dstColorSpace.get(), dstColorSpace.get());
        if (!xform->apply(select_xform_format(dstColorType), data->writable_data(),
                          select_xform_format(dstColorType), data->data(),
                          image->width() * image->height(), kPremul_SkAlphaType)) {
            memset(data->writable_data(), 0, rowBytes * image->height());
        }
        dstInfo = dstInfo.makeAlphaType(kPremul_SkAlphaType);
    }

    // readPixels() does not always clamp F16.  The drawing code expects pixels in the 0-1 range.
    clamp_if_necessary(dstInfo, data->writable_data());

    // Now that we have called readPixels(), dump the raw pixels into an srgb image.
    sk_sp<SkColorSpace> srgb = fix_for_colortype(
            SkColorSpace::MakeSRGB().get(), dstColorType);
    sk_sp<SkImage> raw = SkImage::MakeRasterData(dstInfo.makeColorSpace(srgb), data, rowBytes);
    canvas->drawImage(raw.get(), 0.0f, 0.0f, nullptr);
}
Example #3
0
// Test Fill() with different combinations of dimensions, alignment, and padding
DEF_TEST(SwizzlerFill, r) {
    // Set up a color table
    SkPMColor colorTable[kFillIndex + 1];
    colorTable[kFillIndex] = kFillColor;
    // Apart from the fill index, we will leave the other colors in the color table uninitialized.
    // If we incorrectly try to fill with this uninitialized memory, the bots will catch it.

    // Test on an invalid width and representative widths
    const uint32_t widths[] = { 0, 10, 50 };

    // In order to call Fill(), there must be at least one row to fill
    // Test on the smallest possible height and representative heights
    const uint32_t heights[] = { 1, 5, 10 };

    // Test on interesting possibilities for row padding
    const uint32_t paddings[] = { 0, 1, 2, 3, 4 };

    // Iterate over test dimensions
    for (uint32_t width : widths) {
        for (uint32_t height : heights) {

            // Create image info objects
            const SkImageInfo colorInfo = SkImageInfo::MakeN32(width, height,
                kUnknown_SkAlphaType);
            const SkImageInfo indexInfo = colorInfo.makeColorType(kIndex_8_SkColorType);

            for (uint32_t padding : paddings) {

                // Calculate row bytes
                size_t colorRowBytes = SkColorTypeBytesPerPixel(kN32_SkColorType) * width +
                        padding;
                size_t indexRowBytes = width + padding;

                // If there is padding, we can invent an offset to change the memory alignment
                for (uint32_t offset = 0; offset <= padding; offset++) {

                    // Test all possible start rows with all possible end rows
                    for (uint32_t startRow = 0; startRow < height; startRow++) {
                        for (uint32_t endRow = startRow; endRow < height; endRow++) {

                            // Fill with an index that we use to look up a color
                            check_fill(r, colorInfo, startRow, endRow, colorRowBytes, offset,
                                    kFillIndex, colorTable);

                            // Fill with a color
                            check_fill(r, colorInfo, startRow, endRow, colorRowBytes, offset,
                                    kFillColor, NULL);

                            // Fill with an index
                            check_fill(r, indexInfo, startRow, endRow, indexRowBytes, offset,
                                    kFillIndex, NULL);
                        }
                    }
                }
            }
        }
    }
}
Example #4
0
/*
 * Initiates the gif decode
 */
SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
                                        void* dst, size_t dstRowBytes,
                                        const Options& opts,
                                        SkPMColor* inputColorPtr,
                                        int* inputColorCount,
                                        int* rowsDecoded) {
    Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts);
    if (kSuccess != result) {
        return result;
    }

    if (dstInfo.dimensions() != this->getInfo().dimensions()) {
        return gif_error("Scaling not supported.\n", kInvalidScale);
    }

    // Initialize the swizzler
    if (fFrameIsSubset) {
        const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFrameRect.height());
        if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) {
            return gif_error("Could not initialize swizzler.\n", kUnimplemented);
        }

        // Fill the background
        SkSampler::Fill(dstInfo, dst, dstRowBytes,
                this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()),
                opts.fZeroInitialized);

        // Modify the dst pointer
        const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorType());
        dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() +
                dstBytesPerPixel * fFrameRect.left());
    } else {
        if (kSuccess != this->initializeSwizzler(dstInfo, opts)) {
            return gif_error("Could not initialize swizzler.\n", kUnimplemented);
        }
    }

    // Iterate over rows of the input
    uint32_t height = fFrameRect.height();
    for (uint32_t y = 0; y < height; y++) {
        if (!this->readRow()) {
            *rowsDecoded = y;
            return gif_error("Could not decode line.\n", kIncompleteInput);
        }
        void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanline(y));
        fSwizzler->swizzle(dstRow, fSrcBuffer.get());
    }
    return kSuccess;
}
Example #5
0
static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
        jint width, jint height, jint configHandle, jint allocSize,
        jboolean requestPremul) {
    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);

    // ARGB_4444 is a deprecated format, convert automatically to 8888
    if (colorType == kARGB_4444_SkColorType) {
        colorType = kN32_SkColorType;
    }

    if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) {
        // done in native as there's no way to get BytesPerPixel in Java
        doThrowIAE(env, "Bitmap not large enough to support new configuration");
        return;
    }
    SkPixelRef* ref = bitmap->pixelRef();
    ref->ref();
    SkAlphaType alphaType;
    if (bitmap->colorType() != kRGB_565_SkColorType
            && bitmap->alphaType() == kOpaque_SkAlphaType) {
        // If the original bitmap was set to opaque, keep that setting, unless it
        // was 565, which is required to be opaque.
        alphaType = kOpaque_SkAlphaType;
    } else {
        // Otherwise respect the premultiplied request.
        alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
    }
    bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType));
    // FIXME: Skia thinks of an SkPixelRef as having a constant SkImageInfo (except for
    // its alphatype), so it would make more sense from Skia's perspective to create a
    // new SkPixelRef. That said, libhwui uses the pointer to the SkPixelRef as a key
    // for its cache, so it won't realize this is the same Java Bitmap.
    SkImageInfo& info = const_cast<SkImageInfo&>(ref->info());
    // Use the updated from the SkBitmap, which may have corrected an invalid alphatype.
    // (e.g. 565 non-opaque)
    info = bitmap->info();
    bitmap->setPixelRef(ref);

    // notifyPixelsChanged will increment the generation ID even though the actual pixel data
    // hasn't been touched. This signals the renderer that the bitmap (including width, height,
    // colortype and alphatype) has changed.
    ref->notifyPixelsChanged();
    ref->unref();
}
void draw(SkCanvas* canvas) {
    const char* colors[] = { "Unknown", "Alpha_8", "RGB_565", "ARGB_4444", "RGBA_8888", "RGB_888x",
                             "BGRA_8888", "RGBA_1010102", "RGB_101010x", "Gray_8", "RGBA_F16Norm",
                             "RGBA_F16" };
    SkPaint paint;
    SkFont font(SkTypeface::MakeFromName("monospace", SkFontStyle()), 10);
    int y = 15;
    canvas->drawString("    colorType  bytes", 10, y, font, paint);
    for (SkColorType colorType : {
    kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
    kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
    kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType,
    kGray_8_SkColorType, kRGBA_F16_SkColorType
                                 } ) {
        int result = SkColorTypeBytesPerPixel(colorType);
        SkString string;
        string.printf("%13s %4d", colors[(int) colorType], result);
        canvas->drawString(string, 10, y += 14, font, paint);
    }
}
Example #7
0
bool SkPngEncoder::onEncodeRows(int numRows) {
    if (setjmp(png_jmpbuf(fEncoderMgr->pngPtr()))) {
        return false;
    }

    const void* srcRow = fSrc.addr(0, fCurrRow);
    for (int y = 0; y < numRows; y++) {
        fEncoderMgr->proc()((char*) fStorage.get(), (const char*) srcRow, fSrc.width(),
                            SkColorTypeBytesPerPixel(fSrc.colorType()), nullptr);

        png_bytep rowPtr = (png_bytep) fStorage.get();
        png_write_rows(fEncoderMgr->pngPtr(), &rowPtr, 1);
        srcRow = SkTAddOffset<const void>(srcRow, fSrc.rowBytes());
    }

    fCurrRow += numRows;
    if (fCurrRow == fSrc.height()) {
        png_write_end(fEncoderMgr->pngPtr(), fEncoderMgr->infoPtr());
    }

    return true;
}
Example #8
0
int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
    int rowsBeforeFrame = 0;
    int rowsAfterFrame = 0;
    int rowsInFrame = count;
    if (fFrameIsSubset) {
        // Fill the requested rows
        SkImageInfo fillInfo = this->dstInfo().makeWH(this->dstInfo().width(), count);
        uint32_t fillValue = this->onGetFillValue(this->dstInfo().colorType(),
                this->dstInfo().alphaType());
        SkSampler::Fill(fillInfo, dst, rowBytes, fillValue, this->options().fZeroInitialized);

        // Do nothing for rows before the image frame
        rowsBeforeFrame = SkTMax(0, fFrameRect.top() - this->INHERITED::nextScanline());
        rowsInFrame = SkTMax(0, rowsInFrame - rowsBeforeFrame);
        dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame);

        // Do nothing for rows after the image frame
        rowsAfterFrame = SkTMax(0,
                this->INHERITED::nextScanline() + rowsInFrame - fFrameRect.bottom());
        rowsInFrame = SkTMax(0, rowsInFrame - rowsAfterFrame);

        // Adjust dst pointer for left offset
        int offset = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFrameRect.left();
        dst = SkTAddOffset<void>(dst, offset);
    }

    for (int i = 0; i < rowsInFrame; i++) {
        if (!this->readRow()) {
            return i + rowsBeforeFrame;
        }
        fSwizzler->swizzle(dst, fSrcBuffer.get());
        dst = SkTAddOffset<void>(dst, rowBytes);
    }

    return count;
}
int SkImageInfo::bytesPerPixel() const { return SkColorTypeBytesPerPixel(fColorType); }