diff --git a/src/raster/algorithm/resize_image.cpp b/src/raster/algorithm/resize_image.cpp index b536b9768..ee412ba8b 100644 --- a/src/raster/algorithm/resize_image.cpp +++ b/src/raster/algorithm/resize_image.cpp @@ -35,23 +35,22 @@ void resize_image(const Image* src, Image* dst, ResizeMethod method, const Palet switch (method) { // TODO optimize this - case RESIZE_METHOD_NEAREST_NEIGHBOR: { - uint32_t color; - double u, v, du, dv; - int x, y; + case RESIZE_METHOD_NEAREST_NEIGHBOR: + { + int o_width = src->getWidth(), o_height = src->getHeight(); + int n_width = dst->getWidth(), n_height = dst->getHeight(); + double x_ratio = o_width / (double)n_width; + double y_ratio = o_height / (double)n_height; + double px, py; + int i; - u = v = 0.0; - du = src->getWidth() * 1.0 / dst->getWidth(); - dv = src->getHeight() * 1.0 / dst->getHeight(); - for (y=0; ygetHeight(); ++y) { - for (x=0; xgetWidth(); ++x) { - color = src->getPixel(MID(0, u, src->getWidth()-1), - MID(0, v, src->getHeight()-1)); - dst->putPixel(x, y, color); - u += du; + for (int y = 0; y < n_height; y++) { + for (int x = 0; x < n_width; x++) { + px = floor(x * x_ratio); + py = floor(y * y_ratio); + i = (int)(py * o_width + px); + dst->putPixel(x, y, src->getPixel(i % o_width, i / o_width)); } - u = 0.0; - v += dv; } break; } diff --git a/src/raster/resize_image_unittest.cpp b/src/raster/resize_image_unittest.cpp new file mode 100644 index 000000000..6427aee78 --- /dev/null +++ b/src/raster/resize_image_unittest.cpp @@ -0,0 +1,111 @@ +// Aseprite Gfx Library +// Copyright (C) 2001-2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "raster/color.h" +#include "raster/image.h" +#include "raster/algorithm/resize_image.h" + +using namespace std; +using namespace raster; + +/*************************** + * Test dat + */ + +// Base image +color_t test_image_base_3x3[9] = +{ + 0x000000, 0xffffff, 0x000000, + 0xffffff, 0xffffff, 0xffffff, + 0x000000, 0xffffff, 0x000000 +}; + +// Base image scaled to 9x9 with nearest neighbor interpolation +color_t test_image_scaled_9x9_nearest[81] = +{ + 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000 +}; + +// Base image scalled to 9x9 with bilinear interpolation +color_t test_image_scaled_9x9_bilinear[81] = +{ + 0x000000, 0x000000, 0x565656, 0xa9a9a9, 0xffffff, 0xa9a9a9, 0x565656, 0x000000, 0x000000, + 0x000000, 0x000000, 0x565656, 0xa9a9a9, 0xffffff, 0xa9a9a9, 0x565656, 0x000000, 0x000000, + 0x565656, 0x565656, 0x8f8f8f, 0xc6c6c6, 0xffffff, 0xc6c6c6, 0x8f8f8f, 0x565656, 0x565656, + 0xa9a9a9, 0xa9a9a9, 0xc6c6c6, 0xe2e2e2, 0xffffff, 0xe2e2e2, 0xc6c6c6, 0xa9a9a9, 0xa9a9a9, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xa9a9a9, 0xa9a9a9, 0xc6c6c6, 0xe2e2e2, 0xffffff, 0xe2e2e2, 0xc6c6c6, 0xa9a9a9, 0xa9a9a9, + 0x565656, 0x565656, 0x8f8f8f, 0xc6c6c6, 0xffffff, 0xc6c6c6, 0x8f8f8f, 0x565656, 0x565656, + 0x000000, 0x000000, 0x565656, 0xa9a9a9, 0xffffff, 0xa9a9a9, 0x565656, 0x000000, 0x000000, + 0x000000, 0x000000, 0x565656, 0xa9a9a9, 0xffffff, 0xa9a9a9, 0x565656, 0x000000, 0x000000 +}; + +Image* create_image_from_data(PixelFormat format, color_t* data, int width, int height) +{ + Image* new_image = Image::create(format, width, height); + for (int i = 0; i < width * height; i++) { + new_image->putPixel(i % width, i / width, data[i]); + } + + return new_image; +} + +// Simple pixel to pixel image comparison +bool compare_images(Image* a, Image* b) +{ + for (int y = 0; y < a->getHeight(); y++) { + for (int x = 0; x < a->getWidth(); x++) { + if (!(a->getPixel(x, y) == b->getPixel(x, y))) + return false; + } + } + return true; +} + +TEST(ResizeImage, NearestNeighborInterp) +{ + Image* src = create_image_from_data(IMAGE_RGB, test_image_base_3x3, 3, 3); + Image* dst = Image::create(IMAGE_RGB, 9, 9); + + // Pre-rendered test image for comparison + Image* test_dst = create_image_from_data(IMAGE_RGB, test_image_scaled_9x9_nearest, 9, 9); + + algorithm::resize_image(src, dst, algorithm::ResizeMethod::RESIZE_METHOD_NEAREST_NEIGHBOR, NULL, NULL); + + ASSERT_TRUE(compare_images(dst, test_dst)) << "resize_image() result does not match test image!"; +} + +TEST(ResizeImage, BilinearInterpRGBType) +{ + Image* src = create_image_from_data(IMAGE_RGB, test_image_base_3x3, 3, 3); + Image* dst = Image::create(IMAGE_RGB, 9, 9); + + // Pre-rendered test image for comparison + Image* test_dst = create_image_from_data(IMAGE_RGB, test_image_scaled_9x9_bilinear, 9, 9); + + algorithm::resize_image(src, dst, algorithm::ResizeMethod::RESIZE_METHOD_BILINEAR, NULL, NULL); + + ASSERT_TRUE(compare_images(dst, test_dst)) << "resize_image() result does not match test image!"; +} +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}