1 // Copyright (c) 2012 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 "ui/gfx/skbitmap_operations.h"
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "third_party/skia/include/core/SkBitmap.h"
9 #include "third_party/skia/include/core/SkCanvas.h"
10 #include "third_party/skia/include/core/SkColorPriv.h"
11 #include "third_party/skia/include/core/SkRect.h"
12 #include "third_party/skia/include/core/SkRegion.h"
13 #include "third_party/skia/include/core/SkUnPreMultiply.h"
17 // Returns true if each channel of the given two colors are "close." This is
18 // used for comparing colors where rounding errors may cause off-by-one.
19 inline bool ColorsClose(uint32_t a
, uint32_t b
) {
20 return abs(static_cast<int>(SkColorGetB(a
) - SkColorGetB(b
))) <= 2 &&
21 abs(static_cast<int>(SkColorGetG(a
) - SkColorGetG(b
))) <= 2 &&
22 abs(static_cast<int>(SkColorGetR(a
) - SkColorGetR(b
))) <= 2 &&
23 abs(static_cast<int>(SkColorGetA(a
) - SkColorGetA(b
))) <= 2;
26 inline bool MultipliedColorsClose(uint32_t a
, uint32_t b
) {
27 return ColorsClose(SkUnPreMultiply::PMColorToColor(a
),
28 SkUnPreMultiply::PMColorToColor(b
));
31 bool BitmapsClose(const SkBitmap
& a
, const SkBitmap
& b
) {
32 SkAutoLockPixels
a_lock(a
);
33 SkAutoLockPixels
b_lock(b
);
35 for (int y
= 0; y
< a
.height(); y
++) {
36 for (int x
= 0; x
< a
.width(); x
++) {
37 SkColor a_pixel
= *a
.getAddr32(x
, y
);
38 SkColor b_pixel
= *b
.getAddr32(x
, y
);
39 if (!ColorsClose(a_pixel
, b_pixel
))
46 void FillDataToBitmap(int w
, int h
, SkBitmap
* bmp
) {
47 bmp
->allocN32Pixels(w
, h
);
49 unsigned char* src_data
=
50 reinterpret_cast<unsigned char*>(bmp
->getAddr32(0, 0));
51 for (int i
= 0; i
< w
* h
; i
++) {
52 src_data
[i
* 4 + 0] = static_cast<unsigned char>(i
% 255);
53 src_data
[i
* 4 + 1] = static_cast<unsigned char>(i
% 255);
54 src_data
[i
* 4 + 2] = static_cast<unsigned char>(i
% 255);
55 src_data
[i
* 4 + 3] = static_cast<unsigned char>(i
% 255);
59 // The reference (i.e., old) implementation of |CreateHSLShiftedBitmap()|.
60 SkBitmap
ReferenceCreateHSLShiftedBitmap(
61 const SkBitmap
& bitmap
,
62 color_utils::HSL hsl_shift
) {
64 shifted
.allocN32Pixels(bitmap
.width(), bitmap
.height());
65 shifted
.eraseARGB(0, 0, 0, 0);
67 SkAutoLockPixels
lock_bitmap(bitmap
);
68 SkAutoLockPixels
lock_shifted(shifted
);
70 // Loop through the pixels of the original bitmap.
71 for (int y
= 0; y
< bitmap
.height(); ++y
) {
72 SkPMColor
* pixels
= bitmap
.getAddr32(0, y
);
73 SkPMColor
* tinted_pixels
= shifted
.getAddr32(0, y
);
75 for (int x
= 0; x
< bitmap
.width(); ++x
) {
76 tinted_pixels
[x
] = SkPreMultiplyColor(color_utils::HSLShift(
77 SkUnPreMultiply::PMColorToColor(pixels
[x
]), hsl_shift
));
86 // Invert bitmap and verify the each pixel is inverted and the alpha value is
88 TEST(SkBitmapOperationsTest
, CreateInvertedBitmap
) {
89 int src_w
= 16, src_h
= 16;
91 src
.allocN32Pixels(src_w
, src_h
);
93 for (int y
= 0; y
< src_h
; y
++) {
94 for (int x
= 0; x
< src_w
; x
++) {
95 int i
= y
* src_w
+ x
;
96 *src
.getAddr32(x
, y
) =
97 SkColorSetARGB((255 - i
) % 255, i
% 255, i
* 4 % 255, 0);
101 SkBitmap inverted
= SkBitmapOperations::CreateInvertedBitmap(src
);
102 SkAutoLockPixels
src_lock(src
);
103 SkAutoLockPixels
inverted_lock(inverted
);
105 for (int y
= 0; y
< src_h
; y
++) {
106 for (int x
= 0; x
< src_w
; x
++) {
107 int i
= y
* src_w
+ x
;
108 EXPECT_EQ(static_cast<unsigned int>((255 - i
) % 255),
109 SkColorGetA(*inverted
.getAddr32(x
, y
)));
110 EXPECT_EQ(static_cast<unsigned int>(255 - (i
% 255)),
111 SkColorGetR(*inverted
.getAddr32(x
, y
)));
112 EXPECT_EQ(static_cast<unsigned int>(255 - (i
* 4 % 255)),
113 SkColorGetG(*inverted
.getAddr32(x
, y
)));
114 EXPECT_EQ(static_cast<unsigned int>(255),
115 SkColorGetB(*inverted
.getAddr32(x
, y
)));
120 // Blend two bitmaps together at 50% alpha and verify that the result
121 // is the middle-blend of the two.
122 TEST(SkBitmapOperationsTest
, CreateBlendedBitmap
) {
123 int src_w
= 16, src_h
= 16;
125 src_a
.allocN32Pixels(src_w
, src_h
);
128 src_b
.allocN32Pixels(src_w
, src_h
);
130 for (int y
= 0, i
= 0; y
< src_h
; y
++) {
131 for (int x
= 0; x
< src_w
; x
++) {
132 *src_a
.getAddr32(x
, y
) = SkColorSetARGB(255, 0, i
* 2 % 255, i
% 255);
133 *src_b
.getAddr32(x
, y
) =
134 SkColorSetARGB((255 - i
) % 255, i
% 255, i
* 4 % 255, 0);
140 SkBitmap blended
= SkBitmapOperations::CreateBlendedBitmap(
142 SkAutoLockPixels
srca_lock(src_a
);
143 SkAutoLockPixels
srcb_lock(src_b
);
144 SkAutoLockPixels
blended_lock(blended
);
146 for (int y
= 0; y
< src_h
; y
++) {
147 for (int x
= 0; x
< src_w
; x
++) {
148 int i
= y
* src_w
+ x
;
149 EXPECT_EQ(static_cast<unsigned int>((255 + ((255 - i
) % 255)) / 2),
150 SkColorGetA(*blended
.getAddr32(x
, y
)));
151 EXPECT_EQ(static_cast<unsigned int>(i
% 255 / 2),
152 SkColorGetR(*blended
.getAddr32(x
, y
)));
153 EXPECT_EQ((static_cast<unsigned int>((i
* 2) % 255 + (i
* 4) % 255) / 2),
154 SkColorGetG(*blended
.getAddr32(x
, y
)));
155 EXPECT_EQ(static_cast<unsigned int>(i
% 255 / 2),
156 SkColorGetB(*blended
.getAddr32(x
, y
)));
161 // Test our masking functions.
162 TEST(SkBitmapOperationsTest
, CreateMaskedBitmap
) {
163 int src_w
= 16, src_h
= 16;
166 FillDataToBitmap(src_w
, src_h
, &src
);
168 // Generate alpha mask
170 alpha
.allocN32Pixels(src_w
, src_h
);
171 for (int y
= 0, i
= 0; y
< src_h
; y
++) {
172 for (int x
= 0; x
< src_w
; x
++) {
173 *alpha
.getAddr32(x
, y
) = SkColorSetARGB((i
+ 128) % 255,
181 SkBitmap masked
= SkBitmapOperations::CreateMaskedBitmap(src
, alpha
);
183 SkAutoLockPixels
src_lock(src
);
184 SkAutoLockPixels
alpha_lock(alpha
);
185 SkAutoLockPixels
masked_lock(masked
);
186 for (int y
= 0; y
< src_h
; y
++) {
187 for (int x
= 0; x
< src_w
; x
++) {
188 // Test that the alpha is equal.
189 SkColor src_pixel
= SkUnPreMultiply::PMColorToColor(*src
.getAddr32(x
, y
));
190 SkColor alpha_pixel
=
191 SkUnPreMultiply::PMColorToColor(*alpha
.getAddr32(x
, y
));
192 SkColor masked_pixel
= *masked
.getAddr32(x
, y
);
194 int alpha_value
= SkAlphaMul(SkColorGetA(src_pixel
),
195 SkAlpha255To256(SkColorGetA(alpha_pixel
)));
196 int alpha_value_256
= SkAlpha255To256(alpha_value
);
197 SkColor expected_pixel
= SkColorSetARGB(
199 SkAlphaMul(SkColorGetR(src_pixel
), alpha_value_256
),
200 SkAlphaMul(SkColorGetG(src_pixel
), alpha_value_256
),
201 SkAlphaMul(SkColorGetB(src_pixel
), alpha_value_256
));
203 EXPECT_EQ(expected_pixel
, masked_pixel
);
208 // Make sure that when shifting a bitmap without any shift parameters,
209 // the end result is close enough to the original (rounding errors
211 TEST(SkBitmapOperationsTest
, CreateHSLShiftedBitmapToSame
) {
212 int src_w
= 16, src_h
= 16;
214 src
.allocN32Pixels(src_w
, src_h
);
216 for (int y
= 0, i
= 0; y
< src_h
; y
++) {
217 for (int x
= 0; x
< src_w
; x
++) {
218 *src
.getAddr32(x
, y
) = SkPreMultiplyColor(SkColorSetARGB((i
+ 128) % 255,
219 (i
+ 128) % 255, (i
+ 64) % 255, (i
+ 0) % 255));
224 color_utils::HSL hsl
= { -1, -1, -1 };
225 SkBitmap shifted
= ReferenceCreateHSLShiftedBitmap(src
, hsl
);
227 SkAutoLockPixels
src_lock(src
);
228 SkAutoLockPixels
shifted_lock(shifted
);
230 for (int y
= 0; y
< src_h
; y
++) {
231 for (int x
= 0; x
< src_w
; x
++) {
232 SkColor src_pixel
= *src
.getAddr32(x
, y
);
233 SkColor shifted_pixel
= *shifted
.getAddr32(x
, y
);
234 EXPECT_TRUE(MultipliedColorsClose(src_pixel
, shifted_pixel
)) <<
235 "source: (a,r,g,b) = (" << SkColorGetA(src_pixel
) << "," <<
236 SkColorGetR(src_pixel
) << "," <<
237 SkColorGetG(src_pixel
) << "," <<
238 SkColorGetB(src_pixel
) << "); " <<
239 "shifted: (a,r,g,b) = (" << SkColorGetA(shifted_pixel
) << "," <<
240 SkColorGetR(shifted_pixel
) << "," <<
241 SkColorGetG(shifted_pixel
) << "," <<
242 SkColorGetB(shifted_pixel
) << ")";
247 // Shift a blue bitmap to red.
248 TEST(SkBitmapOperationsTest
, CreateHSLShiftedBitmapHueOnly
) {
249 int src_w
= 16, src_h
= 16;
251 src
.allocN32Pixels(src_w
, src_h
);
253 for (int y
= 0, i
= 0; y
< src_h
; y
++) {
254 for (int x
= 0; x
< src_w
; x
++) {
255 *src
.getAddr32(x
, y
) = SkColorSetARGB(255, 0, 0, i
% 255);
261 color_utils::HSL hsl
= { 0, -1, -1 };
263 SkBitmap shifted
= SkBitmapOperations::CreateHSLShiftedBitmap(src
, hsl
);
265 SkAutoLockPixels
src_lock(src
);
266 SkAutoLockPixels
shifted_lock(shifted
);
268 for (int y
= 0, i
= 0; y
< src_h
; y
++) {
269 for (int x
= 0; x
< src_w
; x
++) {
270 EXPECT_TRUE(ColorsClose(shifted
.getColor(x
, y
),
271 SkColorSetARGB(255, i
% 255, 0, 0)));
277 // Validate HSL shift.
278 TEST(SkBitmapOperationsTest
, ValidateHSLShift
) {
279 // Note: 255/51 = 5 (exactly) => 6 including 0!
281 const int dim
= 255 / inc
+ 1;
283 src
.allocN32Pixels(dim
*dim
, dim
*dim
);
285 for (int a
= 0, y
= 0; a
<= 255; a
+= inc
) {
286 for (int r
= 0; r
<= 255; r
+= inc
, y
++) {
287 for (int g
= 0, x
= 0; g
<= 255; g
+= inc
) {
288 for (int b
= 0; b
<= 255; b
+= inc
, x
++) {
289 *src
.getAddr32(x
, y
) =
290 SkPreMultiplyColor(SkColorSetARGB(a
, r
, g
, b
));
296 // Shhhh. The spec says I should set things to -1 for "no change", but
297 // actually -0.1 will do. Don't tell anyone I did this.
298 for (double h
= -0.1; h
<= 1.0001; h
+= 0.1) {
299 for (double s
= -0.1; s
<= 1.0001; s
+= 0.1) {
300 for (double l
= -0.1; l
<= 1.0001; l
+= 0.1) {
301 color_utils::HSL hsl
= { h
, s
, l
};
302 SkBitmap ref_shifted
= ReferenceCreateHSLShiftedBitmap(src
, hsl
);
303 SkBitmap shifted
= SkBitmapOperations::CreateHSLShiftedBitmap(src
, hsl
);
304 EXPECT_TRUE(BitmapsClose(ref_shifted
, shifted
))
305 << "h = " << h
<< ", s = " << s
<< ", l = " << l
;
311 // Test our cropping.
312 TEST(SkBitmapOperationsTest
, CreateCroppedBitmap
) {
313 int src_w
= 16, src_h
= 16;
315 FillDataToBitmap(src_w
, src_h
, &src
);
317 SkBitmap cropped
= SkBitmapOperations::CreateTiledBitmap(src
, 4, 4,
319 ASSERT_EQ(8, cropped
.width());
320 ASSERT_EQ(8, cropped
.height());
322 SkAutoLockPixels
src_lock(src
);
323 SkAutoLockPixels
cropped_lock(cropped
);
324 for (int y
= 4; y
< 12; y
++) {
325 for (int x
= 4; x
< 12; x
++) {
326 EXPECT_EQ(*src
.getAddr32(x
, y
),
327 *cropped
.getAddr32(x
- 4, y
- 4));
332 // Test whether our cropping correctly wraps across image boundaries.
333 TEST(SkBitmapOperationsTest
, CreateCroppedBitmapWrapping
) {
334 int src_w
= 16, src_h
= 16;
336 FillDataToBitmap(src_w
, src_h
, &src
);
338 SkBitmap cropped
= SkBitmapOperations::CreateTiledBitmap(
339 src
, src_w
/ 2, src_h
/ 2, src_w
, src_h
);
340 ASSERT_EQ(src_w
, cropped
.width());
341 ASSERT_EQ(src_h
, cropped
.height());
343 SkAutoLockPixels
src_lock(src
);
344 SkAutoLockPixels
cropped_lock(cropped
);
345 for (int y
= 0; y
< src_h
; y
++) {
346 for (int x
= 0; x
< src_w
; x
++) {
347 EXPECT_EQ(*src
.getAddr32(x
, y
),
348 *cropped
.getAddr32((x
+ src_w
/ 2) % src_w
,
349 (y
+ src_h
/ 2) % src_h
));
354 TEST(SkBitmapOperationsTest
, DownsampleByTwo
) {
355 // Use an odd-sized bitmap to make sure the edge cases where there isn't a
356 // 2x2 block of pixels is handled correctly.
357 // Here's the ARGB example
359 // 50% transparent green opaque 50% blue white
360 // 80008000 FF000080 FFFFFFFF
362 // 50% transparent red opaque 50% gray black
363 // 80800000 80808080 FF000000
365 // black white 50% gray
366 // FF000000 FFFFFFFF FF808080
368 // The result of this computation should be:
372 input
.allocN32Pixels(3, 3);
374 // The color order may be different, but we don't care (the channels are
376 *input
.getAddr32(0, 0) = 0x80008000;
377 *input
.getAddr32(1, 0) = 0xFF000080;
378 *input
.getAddr32(2, 0) = 0xFFFFFFFF;
379 *input
.getAddr32(0, 1) = 0x80800000;
380 *input
.getAddr32(1, 1) = 0x80808080;
381 *input
.getAddr32(2, 1) = 0xFF000000;
382 *input
.getAddr32(0, 2) = 0xFF000000;
383 *input
.getAddr32(1, 2) = 0xFFFFFFFF;
384 *input
.getAddr32(2, 2) = 0xFF808080;
386 SkBitmap result
= SkBitmapOperations::DownsampleByTwo(input
);
387 EXPECT_EQ(2, result
.width());
388 EXPECT_EQ(2, result
.height());
390 // Some of the values are off-by-one due to rounding.
391 SkAutoLockPixels
lock(result
);
392 EXPECT_EQ(0x9f404040, *result
.getAddr32(0, 0));
393 EXPECT_EQ(0xFF7f7f7f, *result
.getAddr32(1, 0));
394 EXPECT_EQ(0xFF7f7f7f, *result
.getAddr32(0, 1));
395 EXPECT_EQ(0xFF808080, *result
.getAddr32(1, 1));
398 // Test edge cases for DownsampleByTwo.
399 TEST(SkBitmapOperationsTest
, DownsampleByTwoSmall
) {
400 SkPMColor reference
= 0xFF4080FF;
402 // Test a 1x1 bitmap.
404 one_by_one
.allocN32Pixels(1, 1);
405 *one_by_one
.getAddr32(0, 0) = reference
;
406 SkBitmap result
= SkBitmapOperations::DownsampleByTwo(one_by_one
);
407 SkAutoLockPixels
lock1(result
);
408 EXPECT_EQ(1, result
.width());
409 EXPECT_EQ(1, result
.height());
410 EXPECT_EQ(reference
, *result
.getAddr32(0, 0));
412 // Test an n by 1 bitmap.
414 one_by_n
.allocN32Pixels(300, 1);
415 result
= SkBitmapOperations::DownsampleByTwo(one_by_n
);
416 SkAutoLockPixels
lock2(result
);
417 EXPECT_EQ(300, result
.width());
418 EXPECT_EQ(1, result
.height());
420 // Test a 1 by n bitmap.
422 n_by_one
.allocN32Pixels(1, 300);
423 result
= SkBitmapOperations::DownsampleByTwo(n_by_one
);
424 SkAutoLockPixels
lock3(result
);
425 EXPECT_EQ(1, result
.width());
426 EXPECT_EQ(300, result
.height());
428 // Test an empty bitmap
430 result
= SkBitmapOperations::DownsampleByTwo(empty
);
431 EXPECT_TRUE(result
.isNull());
432 EXPECT_EQ(0, result
.width());
433 EXPECT_EQ(0, result
.height());
436 // Here we assume DownsampleByTwo works correctly (it's tested above) and
437 // just make sure that the wrapper function does the right thing.
438 TEST(SkBitmapOperationsTest
, DownsampleByTwoUntilSize
) {
439 // First make sure a "too small" bitmap doesn't get modified at all.
441 too_small
.allocN32Pixels(10, 10);
442 SkBitmap result
= SkBitmapOperations::DownsampleByTwoUntilSize(
444 EXPECT_EQ(10, result
.width());
445 EXPECT_EQ(10, result
.height());
447 // Now make sure giving it a 0x0 target returns something reasonable.
448 result
= SkBitmapOperations::DownsampleByTwoUntilSize(too_small
, 0, 0);
449 EXPECT_EQ(1, result
.width());
450 EXPECT_EQ(1, result
.height());
452 // Test multiple steps of downsampling.
454 large
.allocN32Pixels(100, 43);
455 result
= SkBitmapOperations::DownsampleByTwoUntilSize(large
, 6, 6);
457 // The result should be divided in half 100x43 -> 50x22 -> 25x11
458 EXPECT_EQ(25, result
.width());
459 EXPECT_EQ(11, result
.height());
462 TEST(SkBitmapOperationsTest
, UnPreMultiply
) {
464 input
.allocN32Pixels(2, 2);
466 // Set PMColors into the bitmap
467 *input
.getAddr32(0, 0) = SkPackARGB32NoCheck(0x80, 0x00, 0x00, 0x00);
468 *input
.getAddr32(1, 0) = SkPackARGB32NoCheck(0x80, 0x80, 0x80, 0x80);
469 *input
.getAddr32(0, 1) = SkPackARGB32NoCheck(0xFF, 0x00, 0xCC, 0x88);
470 *input
.getAddr32(1, 1) = SkPackARGB32NoCheck(0x00, 0x00, 0xCC, 0x88);
472 SkBitmap result
= SkBitmapOperations::UnPreMultiply(input
);
473 EXPECT_EQ(2, result
.width());
474 EXPECT_EQ(2, result
.height());
476 SkAutoLockPixels
lock(result
);
477 EXPECT_EQ(0x80000000, *result
.getAddr32(0, 0));
478 EXPECT_EQ(0x80FFFFFF, *result
.getAddr32(1, 0));
479 EXPECT_EQ(0xFF00CC88, *result
.getAddr32(0, 1));
480 EXPECT_EQ(0x00000000u
, *result
.getAddr32(1, 1)); // "Division by zero".
483 TEST(SkBitmapOperationsTest
, CreateTransposedBitmap
) {
485 input
.allocN32Pixels(2, 3);
487 for (int x
= 0; x
< input
.width(); ++x
) {
488 for (int y
= 0; y
< input
.height(); ++y
) {
489 *input
.getAddr32(x
, y
) = x
* input
.width() + y
;
493 SkBitmap result
= SkBitmapOperations::CreateTransposedBitmap(input
);
494 EXPECT_EQ(3, result
.width());
495 EXPECT_EQ(2, result
.height());
497 SkAutoLockPixels
lock(result
);
498 for (int x
= 0; x
< input
.width(); ++x
) {
499 for (int y
= 0; y
< input
.height(); ++y
) {
500 EXPECT_EQ(*input
.getAddr32(x
, y
), *result
.getAddr32(y
, x
));
505 // Check that Rotate provides the desired results
506 TEST(SkBitmapOperationsTest
, RotateImage
) {
507 const int src_w
= 6, src_h
= 4;
509 // Create a simple 4 color bitmap:
514 src
.allocN32Pixels(src_w
, src_h
);
516 SkCanvas
canvas(src
);
517 src
.eraseARGB(0, 0, 0, 0);
520 region
.setRect(0, 0, src_w
/ 2, src_h
/ 2);
521 canvas
.setClipRegion(region
);
522 // This region is a semi-transparent red to test non-opaque pixels.
523 canvas
.drawColor(0x1FFF0000, SkXfermode::kSrc_Mode
);
524 region
.setRect(src_w
/ 2, 0, src_w
, src_h
/ 2);
525 canvas
.setClipRegion(region
);
526 canvas
.drawColor(SK_ColorBLUE
, SkXfermode::kSrc_Mode
);
527 region
.setRect(0, src_h
/ 2, src_w
/ 2, src_h
);
528 canvas
.setClipRegion(region
);
529 canvas
.drawColor(SK_ColorGREEN
, SkXfermode::kSrc_Mode
);
530 region
.setRect(src_w
/ 2, src_h
/ 2, src_w
, src_h
);
531 canvas
.setClipRegion(region
);
532 canvas
.drawColor(SK_ColorYELLOW
, SkXfermode::kSrc_Mode
);
535 SkBitmap rotate90
, rotate180
, rotate270
;
536 rotate90
= SkBitmapOperations::Rotate(src
,
537 SkBitmapOperations::ROTATION_90_CW
);
538 rotate180
= SkBitmapOperations::Rotate(src
,
539 SkBitmapOperations::ROTATION_180_CW
);
540 rotate270
= SkBitmapOperations::Rotate(src
,
541 SkBitmapOperations::ROTATION_270_CW
);
543 ASSERT_EQ(rotate90
.width(), src
.height());
544 ASSERT_EQ(rotate90
.height(), src
.width());
545 ASSERT_EQ(rotate180
.width(), src
.width());
546 ASSERT_EQ(rotate180
.height(), src
.height());
547 ASSERT_EQ(rotate270
.width(), src
.height());
548 ASSERT_EQ(rotate270
.height(), src
.width());
550 SkAutoLockPixels
lock_src(src
);
551 SkAutoLockPixels
lock_90(rotate90
);
552 SkAutoLockPixels
lock_180(rotate180
);
553 SkAutoLockPixels
lock_270(rotate270
);
555 for (int x
=0; x
< src_w
; ++x
) {
556 for (int y
=0; y
< src_h
; ++y
) {
557 ASSERT_EQ(*src
.getAddr32(x
,y
), *rotate90
.getAddr32(src_h
- (y
+1),x
));
558 ASSERT_EQ(*src
.getAddr32(x
,y
), *rotate270
.getAddr32(y
, src_w
- (x
+1)));
559 ASSERT_EQ(*src
.getAddr32(x
,y
),
560 *rotate180
.getAddr32(src_w
- (x
+1), src_h
- (y
+1)));