1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gfx/skbitmap_operations.h"
10 #include "base/logging.h"
11 #include "third_party/skia/include/core/SkBitmap.h"
12 #include "third_party/skia/include/core/SkCanvas.h"
13 #include "third_party/skia/include/core/SkColorPriv.h"
14 #include "third_party/skia/include/core/SkUnPreMultiply.h"
17 SkBitmap
SkBitmapOperations::CreateInvertedBitmap(const SkBitmap
& image
) {
18 DCHECK(image
.config() == SkBitmap::kARGB_8888_Config
);
20 SkAutoLockPixels
lock_image(image
);
23 inverted
.setConfig(SkBitmap::kARGB_8888_Config
, image
.width(), image
.height(),
25 inverted
.allocPixels();
26 inverted
.eraseARGB(0, 0, 0, 0);
28 for (int y
= 0; y
< image
.height(); ++y
) {
29 uint32
* image_row
= image
.getAddr32(0, y
);
30 uint32
* dst_row
= inverted
.getAddr32(0, y
);
32 for (int x
= 0; x
< image
.width(); ++x
) {
33 uint32 image_pixel
= image_row
[x
];
34 dst_row
[x
] = (image_pixel
& 0xFF000000) |
35 (0x00FFFFFF - (image_pixel
& 0x00FFFFFF));
43 SkBitmap
SkBitmapOperations::CreateSuperimposedBitmap(const SkBitmap
& first
,
44 const SkBitmap
& second
) {
45 DCHECK(first
.width() == second
.width());
46 DCHECK(first
.height() == second
.height());
47 DCHECK(first
.bytesPerPixel() == second
.bytesPerPixel());
48 DCHECK(first
.config() == SkBitmap::kARGB_8888_Config
);
50 SkAutoLockPixels
lock_first(first
);
51 SkAutoLockPixels
lock_second(second
);
53 SkBitmap superimposed
;
54 superimposed
.setConfig(SkBitmap::kARGB_8888_Config
,
55 first
.width(), first
.height());
56 superimposed
.allocPixels();
57 superimposed
.eraseARGB(0, 0, 0, 0);
59 SkCanvas
canvas(superimposed
);
64 rect
.fRight
= SkIntToScalar(first
.width());
65 rect
.fBottom
= SkIntToScalar(first
.height());
67 canvas
.drawBitmapRect(first
, NULL
, rect
);
68 canvas
.drawBitmapRect(second
, NULL
, rect
);
74 SkBitmap
SkBitmapOperations::CreateBlendedBitmap(const SkBitmap
& first
,
75 const SkBitmap
& second
,
77 DCHECK((alpha
>= 0) && (alpha
<= 1));
78 DCHECK(first
.width() == second
.width());
79 DCHECK(first
.height() == second
.height());
80 DCHECK(first
.bytesPerPixel() == second
.bytesPerPixel());
81 DCHECK(first
.config() == SkBitmap::kARGB_8888_Config
);
83 // Optimize for case where we won't need to blend anything.
84 static const double alpha_min
= 1.0 / 255;
85 static const double alpha_max
= 254.0 / 255;
86 if (alpha
< alpha_min
)
88 else if (alpha
> alpha_max
)
91 SkAutoLockPixels
lock_first(first
);
92 SkAutoLockPixels
lock_second(second
);
95 blended
.setConfig(SkBitmap::kARGB_8888_Config
, first
.width(), first
.height(),
97 blended
.allocPixels();
98 blended
.eraseARGB(0, 0, 0, 0);
100 double first_alpha
= 1 - alpha
;
102 for (int y
= 0; y
< first
.height(); ++y
) {
103 uint32
* first_row
= first
.getAddr32(0, y
);
104 uint32
* second_row
= second
.getAddr32(0, y
);
105 uint32
* dst_row
= blended
.getAddr32(0, y
);
107 for (int x
= 0; x
< first
.width(); ++x
) {
108 uint32 first_pixel
= first_row
[x
];
109 uint32 second_pixel
= second_row
[x
];
111 int a
= static_cast<int>((SkColorGetA(first_pixel
) * first_alpha
) +
112 (SkColorGetA(second_pixel
) * alpha
));
113 int r
= static_cast<int>((SkColorGetR(first_pixel
) * first_alpha
) +
114 (SkColorGetR(second_pixel
) * alpha
));
115 int g
= static_cast<int>((SkColorGetG(first_pixel
) * first_alpha
) +
116 (SkColorGetG(second_pixel
) * alpha
));
117 int b
= static_cast<int>((SkColorGetB(first_pixel
) * first_alpha
) +
118 (SkColorGetB(second_pixel
) * alpha
));
120 dst_row
[x
] = SkColorSetARGB(a
, r
, g
, b
);
128 SkBitmap
SkBitmapOperations::CreateMaskedBitmap(const SkBitmap
& rgb
,
129 const SkBitmap
& alpha
) {
130 DCHECK(rgb
.width() == alpha
.width());
131 DCHECK(rgb
.height() == alpha
.height());
132 DCHECK(rgb
.bytesPerPixel() == alpha
.bytesPerPixel());
133 DCHECK(rgb
.config() == SkBitmap::kARGB_8888_Config
);
134 DCHECK(alpha
.config() == SkBitmap::kARGB_8888_Config
);
137 masked
.setConfig(SkBitmap::kARGB_8888_Config
, rgb
.width(), rgb
.height(), 0);
138 masked
.allocPixels();
139 masked
.eraseARGB(0, 0, 0, 0);
141 SkAutoLockPixels
lock_rgb(rgb
);
142 SkAutoLockPixels
lock_alpha(alpha
);
143 SkAutoLockPixels
lock_masked(masked
);
145 for (int y
= 0; y
< masked
.height(); ++y
) {
146 uint32
* rgb_row
= rgb
.getAddr32(0, y
);
147 uint32
* alpha_row
= alpha
.getAddr32(0, y
);
148 uint32
* dst_row
= masked
.getAddr32(0, y
);
150 for (int x
= 0; x
< masked
.width(); ++x
) {
151 SkColor rgb_pixel
= SkUnPreMultiply::PMColorToColor(rgb_row
[x
]);
152 int alpha
= SkAlphaMul(SkColorGetA(rgb_pixel
), SkColorGetA(alpha_row
[x
]));
153 dst_row
[x
] = SkColorSetARGB(alpha
,
154 SkAlphaMul(SkColorGetR(rgb_pixel
), alpha
),
155 SkAlphaMul(SkColorGetG(rgb_pixel
), alpha
),
156 SkAlphaMul(SkColorGetB(rgb_pixel
), alpha
));
164 SkBitmap
SkBitmapOperations::CreateButtonBackground(SkColor color
,
165 const SkBitmap
& image
,
166 const SkBitmap
& mask
) {
167 DCHECK(image
.config() == SkBitmap::kARGB_8888_Config
);
168 DCHECK(mask
.config() == SkBitmap::kARGB_8888_Config
);
171 background
.setConfig(
172 SkBitmap::kARGB_8888_Config
, mask
.width(), mask
.height(), 0);
173 background
.allocPixels();
175 double bg_a
= SkColorGetA(color
);
176 double bg_r
= SkColorGetR(color
);
177 double bg_g
= SkColorGetG(color
);
178 double bg_b
= SkColorGetB(color
);
180 SkAutoLockPixels
lock_mask(mask
);
181 SkAutoLockPixels
lock_image(image
);
182 SkAutoLockPixels
lock_background(background
);
184 for (int y
= 0; y
< mask
.height(); ++y
) {
185 uint32
* dst_row
= background
.getAddr32(0, y
);
186 uint32
* image_row
= image
.getAddr32(0, y
% image
.height());
187 uint32
* mask_row
= mask
.getAddr32(0, y
);
189 for (int x
= 0; x
< mask
.width(); ++x
) {
190 uint32 image_pixel
= image_row
[x
% image
.width()];
192 double img_a
= SkColorGetA(image_pixel
);
193 double img_r
= SkColorGetR(image_pixel
);
194 double img_g
= SkColorGetG(image_pixel
);
195 double img_b
= SkColorGetB(image_pixel
);
197 double img_alpha
= static_cast<double>(img_a
) / 255.0;
198 double img_inv
= 1 - img_alpha
;
200 double mask_a
= static_cast<double>(SkColorGetA(mask_row
[x
])) / 255.0;
202 dst_row
[x
] = SkColorSetARGB(
203 static_cast<int>(std::min(255.0, bg_a
+ img_a
) * mask_a
),
204 static_cast<int>(((bg_r
* img_inv
) + (img_r
* img_alpha
)) * mask_a
),
205 static_cast<int>(((bg_g
* img_inv
) + (img_g
* img_alpha
)) * mask_a
),
206 static_cast<int>(((bg_b
* img_inv
) + (img_b
* img_alpha
)) * mask_a
));
216 // TODO(viettrungluu): Some things have yet to be optimized at all.
218 // Notes on and conventions used in the following code
221 // - R, G, B, A = obvious; as variables: |r|, |g|, |b|, |a| (see also below)
222 // - H, S, L = obvious; as variables: |h|, |s|, |l| (see also below)
223 // - variables derived from S, L shift parameters: |sdec| and |sinc| for S
224 // increase and decrease factors, |ldec| and |linc| for L (see also below)
226 // To try to optimize HSL shifts, we do several things:
227 // - Avoid unpremultiplying (then processing) then premultiplying. This means
228 // that R, G, B values (and also L, but not H and S) should be treated as
229 // having a range of 0..A (where A is alpha).
230 // - Do things in integer/fixed-point. This avoids costly conversions between
231 // floating-point and integer, though I should study the tradeoff more
232 // carefully (presumably, at some point of processing complexity, converting
233 // and processing using simpler floating-point code will begin to win in
234 // performance). Also to be studied is the speed/type of floating point
235 // conversions; see, e.g., <http://www.stereopsis.com/sree/fpu2006.html>.
237 // Conventions for fixed-point arithmetic
238 // - Each function has a constant denominator (called |den|, which should be a
239 // power of 2), appropriate for the computations done in that function.
240 // - A value |x| is then typically represented by a numerator, named |x_num|,
241 // so that its actual value is |x_num / den| (casting to floating-point
243 // - To obtain |x_num| from |x|, simply multiply by |den|, i.e., |x_num = x *
244 // den| (casting appropriately).
245 // - When necessary, a value |x| may also be represented as a numerator over
246 // the denominator squared (set |den2 = den * den|). In such a case, the
247 // corresponding variable is called |x_num2| (so that its actual value is
249 // - The representation of the product of |x| and |y| is be called |x_y_num| if
250 // |x * y == x_y_num / den|, and |xy_num2| if |x * y == x_y_num2 / den2|. In
251 // the latter case, notice that one can calculate |x_y_num2 = x_num * y_num|.
253 // Routine used to process a line; typically specialized for specific kinds of
254 // HSL shifts (to optimize).
255 typedef void (*LineProcessor
)(color_utils::HSL
,
260 enum OperationOnH
{ kOpHNone
= 0, kOpHShift
, kNumHOps
};
261 enum OperationOnS
{ kOpSNone
= 0, kOpSDec
, kOpSInc
, kNumSOps
};
262 enum OperationOnL
{ kOpLNone
= 0, kOpLDec
, kOpLInc
, kNumLOps
};
264 // Epsilon used to judge when shift values are close enough to various critical
265 // values (typically 0.5, which yields a no-op for S and L shifts. 1/256 should
266 // be small enough, but let's play it safe>
267 const double epsilon
= 0.0005;
269 // Line processor: default/universal (i.e., old-school).
270 void LineProcDefault(color_utils::HSL hsl_shift
, const SkPMColor
* in
,
271 SkPMColor
* out
, int width
) {
272 for (int x
= 0; x
< width
; x
++) {
273 out
[x
] = SkPreMultiplyColor(color_utils::HSLShift(
274 SkUnPreMultiply::PMColorToColor(in
[x
]), hsl_shift
));
278 // Line processor: no-op (i.e., copy).
279 void LineProcCopy(color_utils::HSL hsl_shift
, const SkPMColor
* in
,
280 SkPMColor
* out
, int width
) {
281 DCHECK(hsl_shift
.h
< 0);
282 DCHECK(hsl_shift
.s
< 0 || fabs(hsl_shift
.s
- 0.5) < HSLShift::epsilon
);
283 DCHECK(hsl_shift
.l
< 0 || fabs(hsl_shift
.l
- 0.5) < HSLShift::epsilon
);
284 memcpy(out
, in
, static_cast<size_t>(width
) * sizeof(out
[0]));
287 // Line processor: H no-op, S no-op, L decrease.
288 void LineProcHnopSnopLdec(color_utils::HSL hsl_shift
, const SkPMColor
* in
,
289 SkPMColor
* out
, int width
) {
290 const uint32_t den
= 65536;
292 DCHECK(hsl_shift
.h
< 0);
293 DCHECK(hsl_shift
.s
< 0 || fabs(hsl_shift
.s
- 0.5) < HSLShift::epsilon
);
294 DCHECK(hsl_shift
.l
<= 0.5 - HSLShift::epsilon
&& hsl_shift
.l
>= 0);
296 uint32_t ldec_num
= static_cast<uint32_t>(hsl_shift
.l
* 2 * den
);
297 for (int x
= 0; x
< width
; x
++) {
298 uint32_t a
= SkGetPackedA32(in
[x
]);
299 uint32_t r
= SkGetPackedR32(in
[x
]);
300 uint32_t g
= SkGetPackedG32(in
[x
]);
301 uint32_t b
= SkGetPackedB32(in
[x
]);
302 r
= r
* ldec_num
/ den
;
303 g
= g
* ldec_num
/ den
;
304 b
= b
* ldec_num
/ den
;
305 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
309 // Line processor: H no-op, S no-op, L increase.
310 void LineProcHnopSnopLinc(color_utils::HSL hsl_shift
, const SkPMColor
* in
,
311 SkPMColor
* out
, int width
) {
312 const uint32_t den
= 65536;
314 DCHECK(hsl_shift
.h
< 0);
315 DCHECK(hsl_shift
.s
< 0 || fabs(hsl_shift
.s
- 0.5) < HSLShift::epsilon
);
316 DCHECK(hsl_shift
.l
>= 0.5 + HSLShift::epsilon
&& hsl_shift
.l
<= 1);
318 uint32_t linc_num
= static_cast<uint32_t>((hsl_shift
.l
- 0.5) * 2 * den
);
319 for (int x
= 0; x
< width
; x
++) {
320 uint32_t a
= SkGetPackedA32(in
[x
]);
321 uint32_t r
= SkGetPackedR32(in
[x
]);
322 uint32_t g
= SkGetPackedG32(in
[x
]);
323 uint32_t b
= SkGetPackedB32(in
[x
]);
324 r
+= (a
- r
) * linc_num
/ den
;
325 g
+= (a
- g
) * linc_num
/ den
;
326 b
+= (a
- b
) * linc_num
/ den
;
327 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
331 // Saturation changes modifications in RGB
333 // (Note that as a further complication, the values we deal in are
334 // premultiplied, so R/G/B values must be in the range 0..A. For mathematical
335 // purposes, one may as well use r=R/A, g=G/A, b=B/A. Without loss of
336 // generality, assume that R/G/B values are in the range 0..1.)
338 // Let Max = max(R,G,B), Min = min(R,G,B), and Med be the median value. Then L =
339 // (Max+Min)/2. If L is to remain constant, Max+Min must also remain constant.
341 // For H to remain constant, first, the (numerical) order of R/G/B (from
342 // smallest to largest) must remain the same. Second, all the ratios
343 // (R-G)/(Max-Min), (R-B)/(Max-Min), (G-B)/(Max-Min) must remain constant (of
344 // course, if Max = Min, then S = 0 and no saturation change is well-defined,
345 // since H is not well-defined).
347 // Let C_max be a colour with value Max, C_min be one with value Min, and C_med
348 // the remaining colour. Increasing saturation (to the maximum) is accomplished
349 // by increasing the value of C_max while simultaneously decreasing C_min and
350 // changing C_med so that the ratios are maintained; for the latter, it suffices
351 // to keep (C_med-C_min)/(C_max-C_min) constant (and equal to
352 // (Med-Min)/(Max-Min)).
354 // Line processor: H no-op, S decrease, L no-op.
355 void LineProcHnopSdecLnop(color_utils::HSL hsl_shift
, const SkPMColor
* in
,
356 SkPMColor
* out
, int width
) {
357 DCHECK(hsl_shift
.h
< 0);
358 DCHECK(hsl_shift
.s
>= 0 && hsl_shift
.s
<= 0.5 - HSLShift::epsilon
);
359 DCHECK(hsl_shift
.l
< 0 || fabs(hsl_shift
.l
- 0.5) < HSLShift::epsilon
);
361 const int32_t denom
= 65536;
362 int32_t s_numer
= static_cast<int32_t>(hsl_shift
.s
* 2 * denom
);
363 for (int x
= 0; x
< width
; x
++) {
364 int32_t a
= static_cast<int32_t>(SkGetPackedA32(in
[x
]));
365 int32_t r
= static_cast<int32_t>(SkGetPackedR32(in
[x
]));
366 int32_t g
= static_cast<int32_t>(SkGetPackedG32(in
[x
]));
367 int32_t b
= static_cast<int32_t>(SkGetPackedB32(in
[x
]));
370 if (r
> g
) { // This uses 3 compares rather than 4.
371 vmax
= std::max(r
, b
);
372 vmin
= std::min(g
, b
);
374 vmax
= std::max(g
, b
);
375 vmin
= std::min(r
, b
);
378 // Use denom * L to avoid rounding.
379 int32_t denom_l
= (vmax
+ vmin
) * (denom
/ 2);
380 int32_t s_numer_l
= (vmax
+ vmin
) * s_numer
/ 2;
382 r
= (denom_l
+ r
* s_numer
- s_numer_l
) / denom
;
383 g
= (denom_l
+ g
* s_numer
- s_numer_l
) / denom
;
384 b
= (denom_l
+ b
* s_numer
- s_numer_l
) / denom
;
385 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
389 // Line processor: H no-op, S decrease, L decrease.
390 void LineProcHnopSdecLdec(color_utils::HSL hsl_shift
, const SkPMColor
* in
,
391 SkPMColor
* out
, int width
) {
392 DCHECK(hsl_shift
.h
< 0);
393 DCHECK(hsl_shift
.s
>= 0 && hsl_shift
.s
<= 0.5 - HSLShift::epsilon
);
394 DCHECK(hsl_shift
.l
>= 0 && hsl_shift
.l
<= 0.5 - HSLShift::epsilon
);
396 // Can't be too big since we need room for denom*denom and a bit for sign.
397 const int32_t denom
= 1024;
398 int32_t l_numer
= static_cast<int32_t>(hsl_shift
.l
* 2 * denom
);
399 int32_t s_numer
= static_cast<int32_t>(hsl_shift
.s
* 2 * denom
);
400 for (int x
= 0; x
< width
; x
++) {
401 int32_t a
= static_cast<int32_t>(SkGetPackedA32(in
[x
]));
402 int32_t r
= static_cast<int32_t>(SkGetPackedR32(in
[x
]));
403 int32_t g
= static_cast<int32_t>(SkGetPackedG32(in
[x
]));
404 int32_t b
= static_cast<int32_t>(SkGetPackedB32(in
[x
]));
407 if (r
> g
) { // This uses 3 compares rather than 4.
408 vmax
= std::max(r
, b
);
409 vmin
= std::min(g
, b
);
411 vmax
= std::max(g
, b
);
412 vmin
= std::min(r
, b
);
415 // Use denom * L to avoid rounding.
416 int32_t denom_l
= (vmax
+ vmin
) * (denom
/ 2);
417 int32_t s_numer_l
= (vmax
+ vmin
) * s_numer
/ 2;
419 r
= (denom_l
+ r
* s_numer
- s_numer_l
) * l_numer
/ (denom
* denom
);
420 g
= (denom_l
+ g
* s_numer
- s_numer_l
) * l_numer
/ (denom
* denom
);
421 b
= (denom_l
+ b
* s_numer
- s_numer_l
) * l_numer
/ (denom
* denom
);
422 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
426 // Line processor: H no-op, S decrease, L increase.
427 void LineProcHnopSdecLinc(color_utils::HSL hsl_shift
, const SkPMColor
* in
,
428 SkPMColor
* out
, int width
) {
429 DCHECK(hsl_shift
.h
< 0);
430 DCHECK(hsl_shift
.s
>= 0 && hsl_shift
.s
<= 0.5 - HSLShift::epsilon
);
431 DCHECK(hsl_shift
.l
>= 0.5 + HSLShift::epsilon
&& hsl_shift
.l
<= 1);
433 // Can't be too big since we need room for denom*denom and a bit for sign.
434 const int32_t denom
= 1024;
435 int32_t l_numer
= static_cast<int32_t>((hsl_shift
.l
- 0.5) * 2 * denom
);
436 int32_t s_numer
= static_cast<int32_t>(hsl_shift
.s
* 2 * denom
);
437 for (int x
= 0; x
< width
; x
++) {
438 int32_t a
= static_cast<int32_t>(SkGetPackedA32(in
[x
]));
439 int32_t r
= static_cast<int32_t>(SkGetPackedR32(in
[x
]));
440 int32_t g
= static_cast<int32_t>(SkGetPackedG32(in
[x
]));
441 int32_t b
= static_cast<int32_t>(SkGetPackedB32(in
[x
]));
444 if (r
> g
) { // This uses 3 compares rather than 4.
445 vmax
= std::max(r
, b
);
446 vmin
= std::min(g
, b
);
448 vmax
= std::max(g
, b
);
449 vmin
= std::min(r
, b
);
452 // Use denom * L to avoid rounding.
453 int32_t denom_l
= (vmax
+ vmin
) * (denom
/ 2);
454 int32_t s_numer_l
= (vmax
+ vmin
) * s_numer
/ 2;
456 r
= denom_l
+ r
* s_numer
- s_numer_l
;
457 g
= denom_l
+ g
* s_numer
- s_numer_l
;
458 b
= denom_l
+ b
* s_numer
- s_numer_l
;
460 r
= (r
* denom
+ (a
* denom
- r
) * l_numer
) / (denom
* denom
);
461 g
= (g
* denom
+ (a
* denom
- g
) * l_numer
) / (denom
* denom
);
462 b
= (b
* denom
+ (a
* denom
- b
) * l_numer
) / (denom
* denom
);
463 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
467 const LineProcessor kLineProcessors
[kNumHOps
][kNumSOps
][kNumLOps
] = {
470 LineProcCopy
, // L: kOpLNone
471 LineProcHnopSnopLdec
, // L: kOpLDec
472 LineProcHnopSnopLinc
// L: kOpLInc
475 LineProcHnopSdecLnop
, // L: kOpLNone
476 LineProcHnopSdecLdec
, // L: kOpLDec
477 LineProcHnopSdecLinc
// L: kOpLInc
480 LineProcDefault
, // L: kOpLNone
481 LineProcDefault
, // L: kOpLDec
482 LineProcDefault
// L: kOpLInc
487 LineProcDefault
, // L: kOpLNone
488 LineProcDefault
, // L: kOpLDec
489 LineProcDefault
// L: kOpLInc
492 LineProcDefault
, // L: kOpLNone
493 LineProcDefault
, // L: kOpLDec
494 LineProcDefault
// L: kOpLInc
497 LineProcDefault
, // L: kOpLNone
498 LineProcDefault
, // L: kOpLDec
499 LineProcDefault
// L: kOpLInc
504 } // namespace HSLShift
508 SkBitmap
SkBitmapOperations::CreateHSLShiftedBitmap(
509 const SkBitmap
& bitmap
,
510 color_utils::HSL hsl_shift
) {
512 HSLShift::OperationOnH H_op
= HSLShift::kOpHNone
;
513 HSLShift::OperationOnS S_op
= HSLShift::kOpSNone
;
514 HSLShift::OperationOnL L_op
= HSLShift::kOpLNone
;
516 if (hsl_shift
.h
>= 0 && hsl_shift
.h
<= 1)
517 H_op
= HSLShift::kOpHShift
;
519 // Saturation shift: 0 -> fully desaturate, 0.5 -> NOP, 1 -> fully saturate.
520 if (hsl_shift
.s
>= 0 && hsl_shift
.s
<= (0.5 - HSLShift::epsilon
))
521 S_op
= HSLShift::kOpSDec
;
522 else if (hsl_shift
.s
>= (0.5 + HSLShift::epsilon
))
523 S_op
= HSLShift::kOpSInc
;
525 // Lightness shift: 0 -> black, 0.5 -> NOP, 1 -> white.
526 if (hsl_shift
.l
>= 0 && hsl_shift
.l
<= (0.5 - HSLShift::epsilon
))
527 L_op
= HSLShift::kOpLDec
;
528 else if (hsl_shift
.l
>= (0.5 + HSLShift::epsilon
))
529 L_op
= HSLShift::kOpLInc
;
531 HSLShift::LineProcessor line_proc
=
532 HSLShift::kLineProcessors
[H_op
][S_op
][L_op
];
534 DCHECK(bitmap
.empty() == false);
535 DCHECK(bitmap
.config() == SkBitmap::kARGB_8888_Config
);
538 shifted
.setConfig(SkBitmap::kARGB_8888_Config
, bitmap
.width(),
540 shifted
.allocPixels();
541 shifted
.eraseARGB(0, 0, 0, 0);
542 shifted
.setIsOpaque(false);
544 SkAutoLockPixels
lock_bitmap(bitmap
);
545 SkAutoLockPixels
lock_shifted(shifted
);
547 // Loop through the pixels of the original bitmap.
548 for (int y
= 0; y
< bitmap
.height(); ++y
) {
549 SkPMColor
* pixels
= bitmap
.getAddr32(0, y
);
550 SkPMColor
* tinted_pixels
= shifted
.getAddr32(0, y
);
552 (*line_proc
)(hsl_shift
, pixels
, tinted_pixels
, bitmap
.width());
559 SkBitmap
SkBitmapOperations::CreateTiledBitmap(const SkBitmap
& source
,
560 int src_x
, int src_y
,
561 int dst_w
, int dst_h
) {
562 DCHECK(source
.getConfig() == SkBitmap::kARGB_8888_Config
);
565 cropped
.setConfig(SkBitmap::kARGB_8888_Config
, dst_w
, dst_h
, 0);
566 cropped
.allocPixels();
567 cropped
.eraseARGB(0, 0, 0, 0);
569 SkAutoLockPixels
lock_source(source
);
570 SkAutoLockPixels
lock_cropped(cropped
);
572 // Loop through the pixels of the original bitmap.
573 for (int y
= 0; y
< dst_h
; ++y
) {
574 int y_pix
= (src_y
+ y
) % source
.height();
576 y_pix
+= source
.height();
578 uint32
* source_row
= source
.getAddr32(0, y_pix
);
579 uint32
* dst_row
= cropped
.getAddr32(0, y
);
581 for (int x
= 0; x
< dst_w
; ++x
) {
582 int x_pix
= (src_x
+ x
) % source
.width();
584 x_pix
+= source
.width();
586 dst_row
[x
] = source_row
[x_pix
];
594 SkBitmap
SkBitmapOperations::DownsampleByTwoUntilSize(const SkBitmap
& bitmap
,
595 int min_w
, int min_h
) {
596 if ((bitmap
.width() <= min_w
) || (bitmap
.height() <= min_h
) ||
597 (min_w
< 0) || (min_h
< 0))
600 // Since bitmaps are refcounted, this copy will be fast.
601 SkBitmap current
= bitmap
;
602 while ((current
.width() >= min_w
* 2) && (current
.height() >= min_h
* 2) &&
603 (current
.width() > 1) && (current
.height() > 1))
604 current
= DownsampleByTwo(current
);
609 SkBitmap
SkBitmapOperations::DownsampleByTwo(const SkBitmap
& bitmap
) {
610 // Handle the nop case.
611 if ((bitmap
.width() <= 1) || (bitmap
.height() <= 1))
615 result
.setConfig(SkBitmap::kARGB_8888_Config
,
616 (bitmap
.width() + 1) / 2, (bitmap
.height() + 1) / 2);
617 result
.allocPixels();
619 SkAutoLockPixels
lock(bitmap
);
620 for (int dest_y
= 0; dest_y
< result
.height(); ++dest_y
) {
621 for (int dest_x
= 0; dest_x
< result
.width(); ++dest_x
) {
622 // This code is based on downsampleby2_proc32 in SkBitmap.cpp. It is very
623 // clever in that it does two channels at once: alpha and green ("ag")
624 // and red and blue ("rb"). Each channel gets averaged across 4 pixels
625 // to get the result.
626 int src_x
= dest_x
<< 1;
627 int src_y
= dest_y
<< 1;
628 const SkPMColor
* cur_src
= bitmap
.getAddr32(src_x
, src_y
);
629 SkPMColor tmp
, ag
, rb
;
631 // Top left pixel of the 2x2 block.
633 ag
= (tmp
>> 8) & 0xFF00FF;
635 if (src_x
< (bitmap
.width() - 1))
638 // Top right pixel of the 2x2 block.
640 ag
+= (tmp
>> 8) & 0xFF00FF;
641 rb
+= tmp
& 0xFF00FF;
642 if (src_y
< (bitmap
.height() - 1))
643 cur_src
= bitmap
.getAddr32(src_x
, src_y
+ 1);
645 cur_src
= bitmap
.getAddr32(src_x
, src_y
); // Move back to the first.
647 // Bottom left pixel of the 2x2 block.
649 ag
+= (tmp
>> 8) & 0xFF00FF;
650 rb
+= tmp
& 0xFF00FF;
651 if (src_x
< (bitmap
.width() - 1))
654 // Bottom right pixel of the 2x2 block.
656 ag
+= (tmp
>> 8) & 0xFF00FF;
657 rb
+= tmp
& 0xFF00FF;
659 // Put the channels back together, dividing each by 4 to get the average.
660 // |ag| has the alpha and green channels shifted right by 8 bits from
661 // there they should end up, so shifting left by 6 gives them in the
662 // correct position divided by 4.
663 *result
.getAddr32(dest_x
, dest_y
) =
664 ((rb
>> 2) & 0xFF00FF) | ((ag
<< 6) & 0xFF00FF00);
672 SkBitmap
SkBitmapOperations::UnPreMultiply(const SkBitmap
& bitmap
) {
675 if (bitmap
.isOpaque())
678 SkBitmap opaque_bitmap
;
679 opaque_bitmap
.setConfig(bitmap
.config(), bitmap
.width(), bitmap
.height());
680 opaque_bitmap
.allocPixels();
683 SkAutoLockPixels
bitmap_lock(bitmap
);
684 SkAutoLockPixels
opaque_bitmap_lock(opaque_bitmap
);
685 for (int y
= 0; y
< opaque_bitmap
.height(); y
++) {
686 for (int x
= 0; x
< opaque_bitmap
.width(); x
++) {
687 uint32 src_pixel
= *bitmap
.getAddr32(x
, y
);
688 uint32
* dst_pixel
= opaque_bitmap
.getAddr32(x
, y
);
689 SkColor unmultiplied
= SkUnPreMultiply::PMColorToColor(src_pixel
);
690 *dst_pixel
= unmultiplied
;
695 opaque_bitmap
.setIsOpaque(true);
696 return opaque_bitmap
;
700 SkBitmap
SkBitmapOperations::CreateTransposedBtmap(const SkBitmap
& image
) {
701 DCHECK(image
.config() == SkBitmap::kARGB_8888_Config
);
703 SkAutoLockPixels
lock_image(image
);
706 transposed
.setConfig(
707 SkBitmap::kARGB_8888_Config
, image
.height(), image
.width(), 0);
708 transposed
.allocPixels();
709 transposed
.eraseARGB(0, 0, 0, 0);
711 for (int y
= 0; y
< image
.height(); ++y
) {
712 uint32
* image_row
= image
.getAddr32(0, y
);
713 for (int x
= 0; x
< image
.width(); ++x
) {
714 uint32
* dst
= transposed
.getAddr32(y
, x
);