From ca9e597e376f1546cfbf1347979542c76e3e74ae Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 17 Nov 2018 06:06:01 +0800 Subject: [PATCH] improve performance of blur algorithm --- include/nana/paint/detail/image_processor.hpp | 155 +++++++++--------- 1 file changed, 76 insertions(+), 79 deletions(-) diff --git a/include/nana/paint/detail/image_processor.hpp b/include/nana/paint/detail/image_processor.hpp index 1a412a2e..1638c25d 100644 --- a/include/nana/paint/detail/image_processor.hpp +++ b/include/nana/paint/detail/image_processor.hpp @@ -1,7 +1,7 @@ /* * Image Processor Algorithm Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -551,55 +551,65 @@ namespace detail { void process(pixel_buffer& pixbuf, const nana::rectangle& area, std::size_t u_radius) const { - int radius = static_cast(u_radius); - int w = area.width; - int h = area.height; - int wm = w - 1; - int hm = h - 1; - int wh = w * h; - int div = (radius << 1) + 1; + const int radius = static_cast(u_radius); + const int safe_radius = std::min(radius, static_cast(area.height) - 2); + const int radius_plus_one = radius + 1; - int large_edge = (w > h ? w : h); - const int div_256 = div * 256; + const int width_3times = static_cast(area.width * 3); + const int wm = area.width - 1; + const int hm = area.height - 1; + const int wh = area.width * area.height; + const int div = (radius << 1) + 1; - std::unique_ptr table_rgb(new int[(wh << 1) + wh + (large_edge << 1) + div_256]); + const int large_edge = std::max(area.width, area.height); + std::unique_ptr table_rgb(new int[wh * 3 + (large_edge << 1) + div * 256]); - int * tbl_r = table_rgb.get(); - int * tbl_g = tbl_r + wh; - int * tbl_b = tbl_g + wh; - - int * vmin = tbl_b + wh; - int * vmax = vmin + large_edge; + int * tbl_rgb = table_rgb.get(); + int * const vmin = tbl_rgb + 3 * wh; + int * const vmax = vmin + large_edge; int * dv = vmax + large_edge; - const int end_div = div - 1; - for(int i = 0, *dv_block = dv; i < 256; ++i) + + for (int i = 0; i < 256; ++i) { - for(int u = 0; u < end_div; u += 2) + dv[0] = i; + for (int u = 1; u < div; u += 2) { - dv_block[u] = i; - dv_block[u + 1] = i; + dv[u] = i; + dv[u + 1] = i; } - dv_block[div - 1] = i; - dv_block += div; + dv += div; } + dv = vmax + large_edge; + auto linepix = pixbuf.raw_ptr(area.y) + area.x; - int yi = 0; - for(int y = 0; y < h; ++y) + for(int x = 0; x < static_cast(area.width); ++x) + { + vmin[x] = std::min(x + radius_plus_one, wm); + vmax[x] = std::max(x - radius, 0); + } + + for(int y = 0; y < static_cast(area.height); ++y) { int sum_r = 0, sum_g = 0, sum_b = 0; if(radius <= wm) { - for(int i = - radius; i <= radius; ++i) + auto px = linepix; + + sum_r = int(px->element.red) * radius_plus_one; + sum_g = int(px->element.blue) * radius_plus_one; + sum_b = int(px->element.blue) * radius_plus_one; + + auto radius_px_end = px + radius_plus_one; + for (++px; px < radius_px_end; ++px) { - auto px = linepix[(i > 0 ? i : 0)]; - sum_r += px.element.red; - sum_g += px.element.green; - sum_b += px.element.blue; - } + sum_r += px->element.red; + sum_g += px->element.green; + sum_b += px->element.blue; + } } else { @@ -612,75 +622,62 @@ namespace detail } } - for(int x = 0; x < w; ++x) + for(int x = 0; x < static_cast(area.width); ++x) { - tbl_r[yi] = dv[sum_r]; - tbl_g[yi] = dv[sum_g]; - tbl_b[yi] = dv[sum_b]; + tbl_rgb[0] = dv[sum_r]; + tbl_rgb[1] = dv[sum_g]; + tbl_rgb[2] = dv[sum_b]; + tbl_rgb += 3; - if(0 == y) - { - vmin[x] = std::min(x + radius + 1, wm); - vmax[x] = std::max(x - radius, 0); - } - - auto p1 = linepix[vmin[x]]; - auto p2 = linepix[vmax[x]]; + auto& p1 = linepix[vmin[x]]; + auto& p2 = linepix[vmax[x]]; sum_r += p1.element.red - p2.element.red; sum_g += p1.element.green - p2.element.green; sum_b += p1.element.blue - p2.element.blue; - ++yi; } linepix = pixbuf.raw_ptr(area.y + y) + area.x; } - const int yp_init = -radius * w; - const std::size_t bytes_pl = pixbuf.bytes_per_line(); - for(int x = 0; x < w; ++x) - { - int sum_r = 0, sum_g = 0, sum_b = 0; - int yp = yp_init; - for(int i = -radius; i <= radius; ++i) + tbl_rgb = table_rgb.get(); + + for (int y = 0; y < static_cast(area.height); ++y) + { + vmin[y] = std::min(y + radius_plus_one, hm) * width_3times; + vmax[y] = std::max(y - radius, 0) * width_3times; + } + + for(int x = 0; x < static_cast(area.width); ++x) + { + int sum_r = int(tbl_rgb[0]) * radius_plus_one; + int sum_g = int(tbl_rgb[1]) * radius_plus_one; + int sum_b = int(tbl_rgb[2]) * radius_plus_one; + + int nextln = width_3times; + for (int i = 0; i < safe_radius; ++i) { - if(yp < 1) - { - sum_r += tbl_r[x]; - sum_g += tbl_g[x]; - sum_b += tbl_b[x]; - } - else - { - int yi = yp + x; - sum_r += tbl_r[yi]; - sum_g += tbl_g[yi]; - sum_b += tbl_b[yi]; - } - yp += w; + sum_r += tbl_rgb[nextln]; + sum_g += tbl_rgb[nextln + 1]; + sum_b += tbl_rgb[nextln + 2]; + nextln += width_3times; } linepix = pixbuf.raw_ptr(area.y) + x + area.x; - - for(int y = 0; y < h; ++y) + for(int y = 0; y < static_cast(area.height); ++y) { linepix->value = 0xFF000000 | (dv[sum_r] << 16) | (dv[sum_g] << 8) | dv[sum_b]; - if(x == 0) - { - vmin[y] = std::min(y + radius + 1, hm) * w; - vmax[y] = std::max(y - radius, 0) * w; - } - int pt1 = x + vmin[y]; - int pt2 = x + vmax[y]; - - sum_r += tbl_r[pt1] - tbl_r[pt2]; - sum_g += tbl_g[pt1] - tbl_g[pt2]; - sum_b += tbl_b[pt1] - tbl_b[pt2]; + int pt1 = vmin[y]; + int pt2 = vmax[y]; + sum_r += tbl_rgb[pt1] - tbl_rgb[pt2]; + sum_g += tbl_rgb[pt1 + 1] - tbl_rgb[pt2 + 1]; + sum_b += tbl_rgb[pt1 + 2] - tbl_rgb[pt2 + 2]; linepix = pixel_at(linepix, bytes_pl); } + tbl_rgb += 3; } } };//end class superfast_blur