2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "utc-image-loading-common.h"
20 #include "platform-abstractions/portable/image-operations.h"
22 using Dali::Internal::Platform::ApplyAttributesToBitmap;
24 #define ANSI_BLACK "\x1B[0m"
25 #define ANSI_RED "\x1B[31m"
26 #define ANSI_GREEN "\x1B[32m"
27 #define ANSI_YELLOW "\x1B[33m"
28 #define ANSI_BLUE "\x1B[34m"
29 #define ANSI_MAGENTA "\x1B[35m"
30 #define ANSI_CYAN "\x1B[36m"
31 #define ANSI_WHITE "\x1B[37m"
32 #define ANSI_RESET "\033[0m"
34 const unsigned char BORDER_FILL_VALUE = 0xff;
35 const char* ASCII_FILL_VALUE = ANSI_YELLOW "#";
36 const char* ASCII_PAD_VALUE = ANSI_BLUE "#";
37 typedef unsigned char PixelBuffer;
40 void FillBitmap( BitmapPtr bitmap )
42 // Fill the given bitmap fully.
43 const Pixel::Format pixelFormat = bitmap->GetPixelFormat();
44 const unsigned int bytesPerPixel = Pixel::GetBytesPerPixel( pixelFormat );
45 PixelBuffer * const targetPixels = bitmap->GetBuffer();
46 const int bytesToFill = bitmap.Get()->GetImageWidth() * bitmap.Get()->GetImageHeight() * bytesPerPixel;
48 memset( targetPixels, BORDER_FILL_VALUE, bytesToFill );
51 typedef Rect< int > ActiveArea;
53 // This struct defines all information for one test.
54 struct ImageFittingTestParameters
56 unsigned int sourceWidth;
57 unsigned int sourceHeight;
58 unsigned int desiredWidth;
59 unsigned int desiredHeight;
60 FittingMode::Type fittingMode;
62 unsigned int expectedWidth;
63 unsigned int expectedHeight;
64 ActiveArea expectedActiveImageArea;
66 ImageFittingTestParameters( unsigned int newSourceWidth, unsigned int newSourceHeight, unsigned int newDesiredWidth, unsigned int newDesiredHeight, FittingMode::Type newFittingMode,
67 unsigned int newExpectedWidth, unsigned int newExpectedHeight, ActiveArea newExpectedActiveImageArea )
68 : sourceWidth( newSourceWidth ),
69 sourceHeight( newSourceHeight ),
70 desiredWidth( newDesiredWidth ),
71 desiredHeight( newDesiredHeight ),
72 fittingMode( newFittingMode ),
73 expectedWidth( newExpectedWidth ),
74 expectedHeight( newExpectedHeight ),
75 expectedActiveImageArea( newExpectedActiveImageArea )
80 typedef std::vector< ImageFittingTestParameters > TestContainer;
83 void PerformFittingTests( TestContainer& tests )
85 // Iterate through all pre-defined tests.
86 for( unsigned int testNumber = 0; testNumber < tests.size(); ++testNumber )
88 // Gather info for this test.
89 ImageFittingTestParameters &test = tests[ testNumber ];
91 unsigned int sourceWidth = test.sourceWidth;
92 unsigned int sourceHeight = test.sourceHeight;
93 unsigned int desiredWidth = test.desiredWidth;
94 unsigned int desiredHeight = test.desiredHeight;
95 FittingMode::Type fittingMode = test.fittingMode;
97 // Create a source bitmap.
98 ImageDimensions desiredDimensions( desiredWidth, desiredHeight );
99 SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR;
100 BitmapPtr sourceBitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
101 Integration::Bitmap::PackedPixelsProfile *packedView = sourceBitmap->GetPackedPixelsProfile();
102 const Pixel::Format pixelFormat = sourceBitmap->GetPixelFormat();
103 packedView->ReserveBuffer( pixelFormat, sourceWidth, sourceHeight, sourceWidth, sourceHeight );
105 // Completely fill the source bitmap (with white).
106 FillBitmap( sourceBitmap );
108 // Perform fitting operations (this is the method we are testing).
109 BitmapPtr newBitmap = ApplyAttributesToBitmap( sourceBitmap, desiredDimensions, fittingMode, samplingMode );
111 DALI_TEST_CHECK( newBitmap );
113 // As we do not need performance within this test, we branch to exit here (for readability, maintainability).
119 Bitmap *bitmap = newBitmap.Get();
121 unsigned int resultWidth = bitmap->GetImageWidth();
122 unsigned int resultHeight = bitmap->GetImageHeight();
124 // Check the dimensions of the modified image match against the expected values defined in the test.
125 DALI_TEST_EQUALS( resultWidth, test.expectedWidth, TEST_LOCATION );
126 DALI_TEST_EQUALS( resultHeight, test.expectedHeight, TEST_LOCATION );
128 PixelBuffer* resultBuffer = bitmap->GetBuffer();
129 const unsigned int bytesPerPixel = Pixel::GetBytesPerPixel( pixelFormat );
131 // We generate an ASCII representation of the source, desired and result images to log, purely as a debugging aid.
132 // (0 = border, 1 = active image area - from the source image).
133 std::string xSourceImageString( sourceWidth, '#' );
134 std::string xDesiredSizeString( desiredWidth - 2, '-' );
135 std::string xDesiredSizePadString( desiredWidth - 2, ' ' );
136 tet_printf( "%sRunning test: %d%s\n", ANSI_RED, testNumber + 1, ANSI_RESET );
137 tet_printf( "Source image: %s%s%s\n", ANSI_YELLOW, xSourceImageString.c_str(), ANSI_RESET );
138 for( unsigned int i = 0; i < sourceHeight - 1; ++i )
140 tet_printf( " %s%s%s\n", ANSI_YELLOW, xSourceImageString.c_str(), ANSI_RESET );
142 tet_printf( "Desired size: %s+%s+%s\n", ANSI_YELLOW, xDesiredSizeString.c_str(), ANSI_RESET );
143 for( unsigned int i = 0; i < desiredHeight - 2; ++i )
145 tet_printf( " %s|%s|%s\n", ANSI_YELLOW, xDesiredSizePadString.c_str(), ANSI_RESET );
147 tet_printf( " %s+%s+%s\n", ANSI_YELLOW, xDesiredSizeString.c_str(), ANSI_RESET );
149 // We want to calculate the active image area (the area filled with image data as opposed to borders).
150 // This is so we can determine if the fitting modes worked correctly.
151 ActiveArea resultActiveArea( -1, -1, -1, -1 );
153 // Iterate over the result image data to find the active area.
154 for( unsigned int y = 0; y < resultHeight; ++y )
156 int activeStartX = -1;
158 std::string xResultImageString;
160 for( unsigned int x = 0; x < resultWidth; ++x )
162 bool pixelPopulated = resultBuffer[ x * bytesPerPixel ] != 0x00;
164 // If the pixel is filled AND we haven't found a filled pixel yet,
165 // this is the horizontal start of the active pixel area (for this line).
166 if( pixelPopulated && ( activeStartX == -1 ) )
170 else if( !pixelPopulated && ( activeStartX != -1 ) && ( activeEndX == -1 ) )
172 // If the pixel is NOT filled AND we HAVE rpeviously found a filled pixel,
173 // then this is the horizontal end of the active pixel area (for this line).
177 // Populate a string with the filled state of the result pixels, to facilitate debugging.
178 xResultImageString += pixelPopulated ? ASCII_FILL_VALUE : ASCII_PAD_VALUE;
181 // First calculate the X-end span value, if we ran out of image before reaching the end of active image area.
182 if( ( activeStartX != -1 ) && ( activeEndX == -1 ) )
184 activeEndX = resultWidth - activeStartX;
187 // If the X-start pixel on this line is earlier than other lines, the overall active area starts earlier.
188 // Note: This is ignored if there was no pixels found.
189 if( ( activeStartX != -1 ) && ( ( activeStartX < resultActiveArea.x ) || ( resultActiveArea.x == -1 ) ) )
191 resultActiveArea.x = activeStartX;
194 // If the X-end pixel on this line is later than other lines, the overall active area starts later.
195 // Note: This is ignored if there was no pixels found.
196 if( ( activeEndX != -1 ) && ( ( activeEndX > resultActiveArea.width ) || ( resultActiveArea.width == -1 ) ) )
198 resultActiveArea.width = activeEndX;
201 // If there was an X-start pixel on this line AND we don't yet have a Y-start, this line IS the Y-start.
202 if( ( activeStartX != -1 ) && ( resultActiveArea.y == -1 ) )
204 resultActiveArea.y = y;
207 // If there was no X-start pixel on this line AND we already have a Y-start value,
208 // then the last Y becomes the new Y-end value.
209 if( ( activeStartX == -1 ) && ( resultActiveArea.y != -1 ) && ( resultActiveArea.height == -1 ) )
211 resultActiveArea.height = y - 1;
216 tet_printf( "Result image: %s\n", xResultImageString.c_str() );
220 tet_printf( " %s\n", xResultImageString.c_str() );
223 resultBuffer += resultWidth * bytesPerPixel;
226 // Calculate the Y-end value, if we ran out of image before reaching the end of active image area.
227 if( ( resultActiveArea.y != -1 ) && ( resultActiveArea.height == -1 ) )
229 resultActiveArea.height = resultHeight - resultActiveArea.y;
232 tet_printf( "%s", ANSI_RESET );
233 tet_printf( "Test: %d Result image dimensions: %d,%d ActiveArea: %d,%d,%d,%d\n",
234 testNumber + 1, resultWidth, resultHeight, resultActiveArea.x, resultActiveArea.y, resultActiveArea.width, resultActiveArea.height );
236 // Test the result images active area matches the expected active area defined in the test.
237 DALI_TEST_EQUALS( resultActiveArea, test.expectedActiveImageArea, TEST_LOCATION );
243 // Positive test case for fitting mode: FIT_WIDTH.
244 int UtcDaliFittingModesFitWidth(void)
246 tet_printf("Running fitting mode test for: FIT_WIDTH\n");
250 // Here we can define the input and expected output of each test on a single line.
251 // Source Width, Source Height, Desired Width, Desired Height, Fitting Mode, Expected Width, Expected Height, ActiveArea: X-start, Y-start, width, height
253 // Test Image source size = desired size. Output should be the same.
254 tests.push_back( ImageFittingTestParameters( 4, 4, 4, 4, FittingMode::FIT_WIDTH, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
255 // Test Image source size > desired size, but aspect same. Should scale size down.
256 tests.push_back( ImageFittingTestParameters( 4, 4, 2, 2, FittingMode::FIT_WIDTH, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
257 // Test Image source size < desired size, but aspect same. Should not scale size up.
258 tests.push_back( ImageFittingTestParameters( 2, 2, 4, 4, FittingMode::FIT_WIDTH, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
259 // Test Image source size < desired size, but aspect different. Should crop height, so no borders. No scale up as result has same aspect after crop.
260 tests.push_back( ImageFittingTestParameters( 2, 4, 8, 8, FittingMode::FIT_WIDTH, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
261 // Test Image source size > desired size, but aspect different (w < h). Should crop height, so no borders. No scale as result is same size as desired size.
262 tests.push_back( ImageFittingTestParameters( 4, 8, 4, 4, FittingMode::FIT_WIDTH, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
263 // Test Image source size > desired size, but aspect different (w > h). Should add borders, AND scale down to desired size.
264 tests.push_back( ImageFittingTestParameters( 8, 4, 4, 4, FittingMode::FIT_WIDTH, 4, 4, ActiveArea( 0, 1, 4, 2 ) ) );
266 PerformFittingTests( tests );
271 // Positive test case for fitting mode: FIT_HEIGHT.
272 int UtcDaliFittingModesFitHeight(void)
274 tet_printf("Running fitting mode test for: FIT_HEIGHT\n");
278 // Here we can define the input and expected output of each test on a single line.
279 // Source Width, Source Height, Desired Width, Desired Height, Fitting Mode, Expected Width, Expected Height, ActiveArea: X-start, Y-start, width, height
281 // Test Image source size = desired size. Output should be the same.
282 tests.push_back( ImageFittingTestParameters( 4, 4, 4, 4, FittingMode::FIT_HEIGHT, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
283 // Test Image source size > desired size, but aspect same. Should scale size down.
284 tests.push_back( ImageFittingTestParameters( 4, 4, 2, 2, FittingMode::FIT_HEIGHT, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
285 // Test Image source size < desired size, but aspect same. Should not scale size up.
286 tests.push_back( ImageFittingTestParameters( 2, 2, 4, 4, FittingMode::FIT_HEIGHT, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
287 // Test Image source size < desired size, but aspect different. Should add borders, but not scale overall size up.
288 tests.push_back( ImageFittingTestParameters( 2, 4, 8, 8, FittingMode::FIT_HEIGHT, 4, 4, ActiveArea( 1, 0, 4, 4 ) ) );
289 // Test Image source size > desired size, but aspect different (w < h). Should add borders, AND scale down to desired size.
290 tests.push_back( ImageFittingTestParameters( 4, 8, 4, 4, FittingMode::FIT_HEIGHT, 4, 4, ActiveArea( 1, 0, 4, 4 ) ) );
291 // Test Image source size > desired size, but aspect different (w > h). Should crop width, so no borders. No scale as result is same size as desired size.
292 tests.push_back( ImageFittingTestParameters( 8, 4, 4, 4, FittingMode::FIT_HEIGHT, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
294 PerformFittingTests( tests );
299 // Positive test case for fitting mode: SHRINK_TO_FIT.
300 int UtcDaliFittingModesShrinkToFit(void)
302 tet_printf("Running fitting mode test for: SHRINK_TO_FIT\n");
306 // Here we can define the input and expected output of each test on a single line.
307 // Source Width, Source Height, Desired Width, Desired Height, Fitting Mode, Expected Width, Expected Height, ActiveArea: X-start, Y-start, width, height
309 // Test Image source size = desired size. Output should be the same.
310 tests.push_back( ImageFittingTestParameters( 4, 4, 4, 4, FittingMode::SHRINK_TO_FIT, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
311 // Test Image source size > desired size, but aspect same. Should scale size down.
312 tests.push_back( ImageFittingTestParameters( 4, 4, 2, 2, FittingMode::SHRINK_TO_FIT, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
313 // Test Image source size < desired size, but aspect same. Should not scale size up.
314 tests.push_back( ImageFittingTestParameters( 2, 2, 4, 4, FittingMode::SHRINK_TO_FIT, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
315 // Test Image source size < desired size, but aspect different. Should add borders, but not scale overall size up, as although image is smaller than desired size, aspect is the same.
316 tests.push_back( ImageFittingTestParameters( 2, 4, 8, 8, FittingMode::SHRINK_TO_FIT, 4, 4, ActiveArea( 1, 0, 4, 4 ) ) );
317 // Test Image source size > desired size, but aspect different (w < h). Should add borders, AND scale down to desired size.
318 tests.push_back( ImageFittingTestParameters( 4, 8, 4, 4, FittingMode::SHRINK_TO_FIT, 4, 4, ActiveArea( 1, 0, 4, 4 ) ) );
319 // Test Image source size > desired size, but aspect different (w > h). Should add borders, AND scale down to desired size.
320 tests.push_back( ImageFittingTestParameters( 8, 4, 4, 4, FittingMode::SHRINK_TO_FIT, 4, 4, ActiveArea( 0, 1, 4, 2 ) ) );
322 PerformFittingTests( tests );
327 // Positive test case for fitting mode: SCALE_TO_FILL.
328 int UtcDaliFittingModesScaleToFill(void)
330 tet_printf("Running fitting mode test for: SCALE_TO_FILL\n");
334 // Here we can define the input and expected output of each test on a single line.
335 // Source Width, Source Height, Desired Width, Desired Height, Fitting Mode, Expected Width, Expected Height, ActiveArea: X-start, Y-start, width, height
337 // Test Image source size = desired size. Output should be the same.
338 tests.push_back( ImageFittingTestParameters( 4, 4, 4, 4, FittingMode::SCALE_TO_FILL, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
339 // Test Image source size > desired size, but aspect same. Should scale size down.
340 tests.push_back( ImageFittingTestParameters( 4, 4, 2, 2, FittingMode::SCALE_TO_FILL, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
341 // Test Image source size < desired size, but aspect same. Should not scale size up.
342 tests.push_back( ImageFittingTestParameters( 2, 2, 4, 4, FittingMode::SCALE_TO_FILL, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
343 // Test Image source size < desired size, but aspect different. Should crop height, so no borders. No scale up as result has same aspect after crop.
344 tests.push_back( ImageFittingTestParameters( 2, 4, 8, 8, FittingMode::SCALE_TO_FILL, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
345 // Test Image source size > desired size, but aspect different (w < h). Should crop height, so no borders. No scale as result is same size as desired size.
346 tests.push_back( ImageFittingTestParameters( 4, 8, 4, 4, FittingMode::SCALE_TO_FILL, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
347 // Test Image source size > desired size, but aspect different (w > h). Should crop width, so no borders. No scale as result is same size as desired size.
348 tests.push_back( ImageFittingTestParameters( 8, 4, 4, 4, FittingMode::SCALE_TO_FILL, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
350 PerformFittingTests( tests );