Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: src/utils/SkBitmapRegionCanvas.cpp

Issue 1288963002: Provides multiple implementations of Android's SkBitmapRegionDecoder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Response to comments Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698