Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright 2015 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #include "SkBitmapRegionCanvas.h" | |
| 9 #include "SkCanvas.h" | |
| 10 #include "SkScanlineDecoder.h" | |
| 11 | |
| 12 SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkScanlineDecoder* decoder) | |
| 13 : INHERITED(decoder->getInfo().width(), decoder->getInfo().height()) | |
| 14 , fDecoder(decoder) | |
| 15 {} | |
| 16 | |
| 17 /* | |
| 18 * Adjusts the image subset dimensions to safely fit within the original image, | |
| 19 * and to safely fit within the requested region size. | |
| 20 */ | |
| 21 static int get_safe_subset_dimension(int imageOffset, int imageDim, int regionOf fset, | |
|
scroggo
2015/09/03 20:07:41
These names are pretty opaque to me. They describe
msarett
2015/09/03 22:10:30
I'll add comments, I was hoping the names would ma
| |
| 22 int regionDim) { | |
| 23 int safeImageDim = imageDim - imageOffset; | |
| 24 int safeRegionDim = regionDim - regionOffset; | |
| 25 return SkTMin(safeImageDim, safeRegionDim); | |
| 26 } | |
| 27 | |
| 28 static int get_scaled_dimension(int dimension, int sampleSize) { | |
| 29 return SkTMax(1, dimension / sampleSize); | |
|
scroggo
2015/09/03 20:07:41
It seems like this is logically the same as SkScal
msarett
2015/09/03 22:10:30
Yeah I tried to share it in SkCodecPriv.h but that
scroggo
2015/09/04 17:55:06
Ah, because this is in utils? maybe declare it as
msarett
2015/09/04 18:54:10
I'll go with the original implementation in SkScal
| |
| 30 } | |
| 31 | |
| 32 /* | |
| 33 * This has several key differences from the Android version: | |
| 34 * Returns a Skia bitmap instead of an Android bitmap. | |
| 35 * Android version attempts to reuse a recycled bitmap. | |
| 36 */ | |
| 37 SkBitmap* SkBitmapRegionCanvas::decodeRegion(int input_x, int input_y, | |
| 38 int input_w, int input_h, | |
| 39 int sampleSize, | |
| 40 SkColorType dstColorType) { | |
| 41 // Reject color types not supported by this method | |
| 42 if (kIndex_8_SkColorType == dstColorType || kGray_8_SkColorType == dstColorT ype) { | |
| 43 SkDebugf("Error: Color type not supported.\n"); | |
| 44 return nullptr; | |
| 45 } | |
| 46 | |
| 47 // Correct the output region if necessary | |
| 48 const int left = SkTMax(0, input_x); | |
| 49 const int leftOffset = left - input_x; | |
| 50 const int top = SkTMax(0, input_y); | |
| 51 const int topOffset = top - input_y; | |
| 52 const int width = get_safe_subset_dimension(left, this->width(), leftOffset, input_w); | |
| 53 const int height = get_safe_subset_dimension(top, this->height(), topOffset, input_h); | |
| 54 if (width <= 0 || height <= 0) { | |
| 55 SkDebugf("Error: Region must intersect part of the image.\n"); | |
| 56 return nullptr; | |
| 57 } | |
| 58 | |
| 59 // Create the image info for the decode | |
| 60 SkAlphaType dstAlphaType = fDecoder->getInfo().alphaType(); | |
| 61 if (kUnpremul_SkAlphaType == dstAlphaType) { | |
| 62 dstAlphaType = kPremul_SkAlphaType; | |
| 63 } | |
| 64 SkImageInfo decodeInfo = SkImageInfo::Make(this->width(), this->height(), | |
| 65 dstColorType, dstAlphaType); | |
| 66 | |
| 67 // Start the scanline decoder | |
| 68 SkCodec::Result r = fDecoder->start(decodeInfo); | |
| 69 if (SkCodec::kSuccess != r) { | |
| 70 SkDebugf("Error: Could not start scanline decoder.\n"); | |
| 71 return nullptr; | |
| 72 } | |
| 73 | |
| 74 // Allocate a bitmap for the unscaled decode | |
| 75 SkBitmap tmp; | |
| 76 SkImageInfo tmpInfo = decodeInfo.makeWH(this->width(), height); | |
| 77 if (!tmp.tryAllocPixels(tmpInfo)) { | |
| 78 SkDebugf("Error: Could not allocate pixels.\n"); | |
| 79 return nullptr; | |
| 80 } | |
| 81 | |
| 82 // Skip the unneeded rows | |
| 83 if (SkCodec::kSuccess != fDecoder->skipScanlines(top)) { | |
| 84 SkDebugf("Error: Failed to skip scanlines.\n"); | |
| 85 return nullptr; | |
| 86 } | |
| 87 | |
| 88 // Decode the necessary rows | |
| 89 SkCodec::Result result = fDecoder->getScanlines(tmp.getAddr(0, 0), height, | |
| 90 tmp.rowBytes()); | |
| 91 switch (result) { | |
| 92 case SkCodec::kSuccess: | |
| 93 case SkCodec::kIncompleteInput: | |
| 94 break; | |
| 95 default: | |
| 96 SkDebugf("Error: Failed to get scanlines.\n"); | |
| 97 return nullptr; | |
| 98 } | |
| 99 | |
| 100 // Calculate the size of the output | |
| 101 const int outWidth = get_scaled_dimension(input_w, sampleSize); | |
| 102 const int outHeight = get_scaled_dimension(input_h, sampleSize); | |
| 103 | |
| 104 // Initialize the destination bitmap | |
| 105 SkAutoTDelete<SkBitmap> bitmap(new SkBitmap()); | |
| 106 SkImageInfo dstInfo = decodeInfo.makeWH(outWidth, outHeight); | |
| 107 if (!bitmap->tryAllocPixels(dstInfo)) { | |
| 108 SkDebugf("Error: Could not allocate pixels.\n"); | |
| 109 return nullptr; | |
| 110 } | |
| 111 | |
| 112 // Zero the bitmap if the region is not completely within the image. | |
| 113 // TODO (msarett): Can we make this faster by implementing it to only | |
| 114 // zero parts of the image that we won't overwrite with | |
| 115 // pixels? | |
| 116 // TODO (msarett): This could be skipped if memory is zero initialized. | |
| 117 // This would matter if this code is moved to Android and | |
| 118 // uses Android bitmaps. | |
| 119 if (0 != leftOffset || 0 != topOffset || | |
| 120 input_x + input_w > this->width() || | |
| 121 input_y + input_h > this->height()) { | |
| 122 bitmap->eraseColor(0); | |
| 123 } | |
| 124 | |
| 125 // Use a canvas to crop and scale to the destination bitmap | |
| 126 SkCanvas canvas(*bitmap); | |
| 127 SkRect src = SkRect::MakeXYWH(left, 0, width, height); | |
| 128 SkRect dst = SkRect::MakeXYWH(leftOffset / sampleSize, topOffset / sampleSiz e, | |
| 129 get_scaled_dimension(width, sampleSize), get_scaled_dimension(height , sampleSize)); | |
| 130 SkPaint paint; | |
| 131 // Overwrite the dst with the src pixels | |
| 132 paint.setXfermodeMode(SkXfermode::kSrc_Mode); | |
| 133 // TODO (msarett): Test multiple filter qualities. kNone is the default. | |
| 134 canvas.drawBitmapRect(tmp, src, dst, &paint); | |
| 135 | |
| 136 return bitmap.detach(); | |
| 137 } | |
| OLD | NEW |