From 9d071d2a2cec9a7662a02669488569a017f0ea35 Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Mon, 13 Feb 2017 21:25:04 -0700 Subject: 8.9 --- wx+/image_tools.h | 516 +++++++++++++++++++++++++++--------------------------- 1 file changed, 258 insertions(+), 258 deletions(-) mode change 100644 => 100755 wx+/image_tools.h (limited to 'wx+/image_tools.h') diff --git a/wx+/image_tools.h b/wx+/image_tools.h old mode 100644 new mode 100755 index cd0e28f0..6287b752 --- a/wx+/image_tools.h +++ b/wx+/image_tools.h @@ -1,258 +1,258 @@ -// ***************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * -// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * -// ***************************************************************************** - -#ifndef IMAGE_TOOLS_H_45782456427634254 -#define IMAGE_TOOLS_H_45782456427634254 - -#include -#include -#include -#include -#include - - -namespace zen -{ -enum class ImageStackLayout -{ - HORIZONTAL, - VERTICAL -}; - -enum class ImageStackAlignment -{ - CENTER, - LEFT, - RIGHT, - TOP = LEFT, - BOTTOM = RIGHT, -}; -wxImage stackImages(const wxImage& img1, const wxImage& img2, ImageStackLayout dir, ImageStackAlignment align, int gap = 0); - -wxImage createImageFromText(const wxString& text, const wxFont& font, const wxColor& col); - -wxBitmap layOver(const wxBitmap& background, const wxBitmap& foreground); //merge - -wxImage greyScale(const wxImage& img); //greyscale + brightness adaption -wxBitmap greyScale(const wxBitmap& bmp); // - -//void moveImage(wxImage& img, int right, int up); -void adjustBrightness(wxImage& img, int targetLevel); -double getAvgBrightness(const wxImage& img); //in [0, 255] -void brighten(wxImage& img, int level); //level: delta per channel in points - -bool isEqual(const wxBitmap& lhs, const wxBitmap& rhs); //pixel-wise equality (respecting alpha channel) - -void convertToVanillaImage(wxImage& img); //add alpha channel if missing + remove mask if existing - -//wxColor gradient(const wxColor& from, const wxColor& to, double fraction); //maps fraction within [0, 1] to an intermediate color - -//wxColor hsvColor(double h, double s, double v); //h within [0, 360), s, v within [0, 1] - - - - - - - - - - - - - - -//################################### implementation ################################### -/* -inline -void moveImage(wxImage& img, int right, int up) -{ - img = img.GetSubImage(wxRect(std::max(0, -right), std::max(0, up), img.GetWidth() - abs(right), img.GetHeight() - abs(up))); - img.Resize(wxSize(img.GetWidth() + abs(right), img.GetHeight() + abs(up)), wxPoint(std::max(0, right), std::max(0, -up))); -} -*/ - - -inline -wxImage greyScale(const wxImage& img) -{ - wxImage output = img.ConvertToGreyscale(1.0 / 3, 1.0 / 3, 1.0 / 3); //treat all channels equally! - //wxImage output = bmp.ConvertToImage().ConvertToGreyscale(); - adjustBrightness(output, 160); - return output; -} - - -inline -wxBitmap greyScale(const wxBitmap& bmp) -{ - assert(!bmp.GetMask()); //wxWidgets screws up for the gazillionth time applying a mask instead of alpha channel if the .png image has only 0 and 0xff opacity values!!! - return greyScale(bmp.ConvertToImage()); -} - - -inline -double getAvgBrightness(const wxImage& img) -{ - const int pixelCount = img.GetWidth() * img.GetHeight(); - auto pixBegin = img.GetData(); - - if (pixelCount > 0 && pixBegin) - { - auto pixEnd = pixBegin + 3 * pixelCount; //RGB - - if (img.HasAlpha()) - { - const unsigned char* alphaFirst = img.GetAlpha(); - - //calculate average weighted by alpha channel - double dividend = 0; - for (auto it = pixBegin; it != pixEnd; ++it) - dividend += *it * static_cast(alphaFirst[(it - pixBegin) / 3]); - - const double divisor = 3.0 * std::accumulate(alphaFirst, alphaFirst + pixelCount, 0.0); - - return numeric::isNull(divisor) ? 0 : dividend / divisor; - } - else - return std::accumulate(pixBegin, pixEnd, 0.0) / (3.0 * pixelCount); - } - return 0; -} - - -inline -void brighten(wxImage& img, int level) -{ - if (auto pixBegin = img.GetData()) - { - const int pixelCount = img.GetWidth() * img.GetHeight(); - auto pixEnd = pixBegin + 3 * pixelCount; //RGB - if (level > 0) - std::for_each(pixBegin, pixEnd, [&](unsigned char& c) { c = static_cast(std::min(255, c + level)); }); - else - std::for_each(pixBegin, pixEnd, [&](unsigned char& c) { c = static_cast(std::max(0, c + level)); }); - } -} - - -inline -void adjustBrightness(wxImage& img, int targetLevel) -{ - brighten(img, targetLevel - getAvgBrightness(img)); -} - - -inline -wxBitmap layOver(const wxBitmap& background, const wxBitmap& foreground) -{ - assert(foreground.HasAlpha() == background.HasAlpha()); //we don't support mixed-mode brittleness! - - wxBitmap output(background.ConvertToImage()); //attention: wxBitmap/wxImage use ref-counting without copy on write! - { - wxMemoryDC dc(output); - - const int offsetX = (background.GetWidth () - foreground.GetWidth ()) / 2; - const int offsetY = (background.GetHeight() - foreground.GetHeight()) / 2; - dc.DrawBitmap(foreground, offsetX, offsetY); - } - return output; -} - - -inline -bool isEqual(const wxBitmap& lhs, const wxBitmap& rhs) -{ - if (lhs.IsOk() != rhs.IsOk()) - return false; - if (!lhs.IsOk()) - return true; - - if (lhs.GetSize() != rhs.GetSize()) - return false; - - wxImage imLhs = lhs.ConvertToImage(); - wxImage imRhs = rhs.ConvertToImage(); - - if (imLhs.HasAlpha() != imRhs.HasAlpha()) - return false; - - const int pixelCount = lhs.GetWidth() * lhs.GetHeight(); - - if (!std::equal(imLhs.GetData(), imLhs.GetData() + pixelCount * 3, imRhs.GetData())) - return false; - - if (imLhs.HasAlpha()) - if (!std::equal(imLhs.GetAlpha(), imLhs.GetAlpha() + pixelCount, imRhs.GetAlpha())) - return false; - - return true; -} - -/* -inline -wxColor gradient(const wxColor& from, const wxColor& to, double fraction) -{ - fraction = std::max(0.0, fraction); - fraction = std::min(1.0, fraction); - return wxColor(from.Red () + (to.Red () - from.Red ()) * fraction, - from.Green() + (to.Green() - from.Green()) * fraction, - from.Blue () + (to.Blue () - from.Blue ()) * fraction, - from.Alpha() + (to.Alpha() - from.Alpha()) * fraction); -} -*/ - -/* -inline -wxColor hsvColor(double h, double s, double v) //h within [0, 360), s, v within [0, 1] -{ - //http://de.wikipedia.org/wiki/HSV-Farbraum - - //make input values fit into bounds - if (h > 360) - h -= static_cast(h / 360) * 360; - else if (h < 0) - h -= static_cast(h / 360) * 360 - 360; - numeric::confine(s, 0, 1); - numeric::confine(v, 0, 1); - //------------------------------------ - const int h_i = h / 60; - const float f = h / 60 - h_i; - - auto polish = [](double val) -> unsigned char - { - int result = numeric::round(val * 255); - numeric::confine(result, 0, 255); - return static_cast(result); - }; - - const unsigned char p = polish(v * (1 - s)); - const unsigned char q = polish(v * (1 - s * f)); - const unsigned char t = polish(v * (1 - s * (1 - f))); - const unsigned char vi = polish(v); - - switch (h_i) - { - case 0: - return wxColor(vi, t, p); - case 1: - return wxColor(q, vi, p); - case 2: - return wxColor(p, vi, t); - case 3: - return wxColor(p, q, vi); - case 4: - return wxColor(t, p, vi); - case 5: - return wxColor(vi, p, q); - } - assert(false); - return *wxBLACK; -} -*/ -} - -#endif //IMAGE_TOOLS_H_45782456427634254 +// ***************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * +// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * +// ***************************************************************************** + +#ifndef IMAGE_TOOLS_H_45782456427634254 +#define IMAGE_TOOLS_H_45782456427634254 + +#include +#include +#include +#include +#include + + +namespace zen +{ +enum class ImageStackLayout +{ + HORIZONTAL, + VERTICAL +}; + +enum class ImageStackAlignment +{ + CENTER, + LEFT, + RIGHT, + TOP = LEFT, + BOTTOM = RIGHT, +}; +wxImage stackImages(const wxImage& img1, const wxImage& img2, ImageStackLayout dir, ImageStackAlignment align, int gap = 0); + +wxImage createImageFromText(const wxString& text, const wxFont& font, const wxColor& col); + +wxBitmap layOver(const wxBitmap& background, const wxBitmap& foreground); //merge + +wxImage greyScale(const wxImage& img); //greyscale + brightness adaption +wxBitmap greyScale(const wxBitmap& bmp); // + +//void moveImage(wxImage& img, int right, int up); +void adjustBrightness(wxImage& img, int targetLevel); +double getAvgBrightness(const wxImage& img); //in [0, 255] +void brighten(wxImage& img, int level); //level: delta per channel in points + +bool isEqual(const wxBitmap& lhs, const wxBitmap& rhs); //pixel-wise equality (respecting alpha channel) + +void convertToVanillaImage(wxImage& img); //add alpha channel if missing + remove mask if existing + +//wxColor gradient(const wxColor& from, const wxColor& to, double fraction); //maps fraction within [0, 1] to an intermediate color + +//wxColor hsvColor(double h, double s, double v); //h within [0, 360), s, v within [0, 1] + + + + + + + + + + + + + + +//################################### implementation ################################### +/* +inline +void moveImage(wxImage& img, int right, int up) +{ + img = img.GetSubImage(wxRect(std::max(0, -right), std::max(0, up), img.GetWidth() - abs(right), img.GetHeight() - abs(up))); + img.Resize(wxSize(img.GetWidth() + abs(right), img.GetHeight() + abs(up)), wxPoint(std::max(0, right), std::max(0, -up))); +} +*/ + + +inline +wxImage greyScale(const wxImage& img) +{ + wxImage output = img.ConvertToGreyscale(1.0 / 3, 1.0 / 3, 1.0 / 3); //treat all channels equally! + //wxImage output = bmp.ConvertToImage().ConvertToGreyscale(); + adjustBrightness(output, 160); + return output; +} + + +inline +wxBitmap greyScale(const wxBitmap& bmp) +{ + assert(!bmp.GetMask()); //wxWidgets screws up for the gazillionth time applying a mask instead of alpha channel if the .png image has only 0 and 0xff opacity values!!! + return greyScale(bmp.ConvertToImage()); +} + + +inline +double getAvgBrightness(const wxImage& img) +{ + const int pixelCount = img.GetWidth() * img.GetHeight(); + auto pixBegin = img.GetData(); + + if (pixelCount > 0 && pixBegin) + { + auto pixEnd = pixBegin + 3 * pixelCount; //RGB + + if (img.HasAlpha()) + { + const unsigned char* alphaFirst = img.GetAlpha(); + + //calculate average weighted by alpha channel + double dividend = 0; + for (auto it = pixBegin; it != pixEnd; ++it) + dividend += *it * static_cast(alphaFirst[(it - pixBegin) / 3]); + + const double divisor = 3.0 * std::accumulate(alphaFirst, alphaFirst + pixelCount, 0.0); + + return numeric::isNull(divisor) ? 0 : dividend / divisor; + } + else + return std::accumulate(pixBegin, pixEnd, 0.0) / (3.0 * pixelCount); + } + return 0; +} + + +inline +void brighten(wxImage& img, int level) +{ + if (auto pixBegin = img.GetData()) + { + const int pixelCount = img.GetWidth() * img.GetHeight(); + auto pixEnd = pixBegin + 3 * pixelCount; //RGB + if (level > 0) + std::for_each(pixBegin, pixEnd, [&](unsigned char& c) { c = static_cast(std::min(255, c + level)); }); + else + std::for_each(pixBegin, pixEnd, [&](unsigned char& c) { c = static_cast(std::max(0, c + level)); }); + } +} + + +inline +void adjustBrightness(wxImage& img, int targetLevel) +{ + brighten(img, targetLevel - getAvgBrightness(img)); +} + + +inline +wxBitmap layOver(const wxBitmap& background, const wxBitmap& foreground) +{ + assert(foreground.HasAlpha() == background.HasAlpha()); //we don't support mixed-mode brittleness! + + wxBitmap output(background.ConvertToImage()); //attention: wxBitmap/wxImage use ref-counting without copy on write! + { + wxMemoryDC dc(output); + + const int offsetX = (background.GetWidth () - foreground.GetWidth ()) / 2; + const int offsetY = (background.GetHeight() - foreground.GetHeight()) / 2; + dc.DrawBitmap(foreground, offsetX, offsetY); + } + return output; +} + + +inline +bool isEqual(const wxBitmap& lhs, const wxBitmap& rhs) +{ + if (lhs.IsOk() != rhs.IsOk()) + return false; + if (!lhs.IsOk()) + return true; + + if (lhs.GetSize() != rhs.GetSize()) + return false; + + wxImage imLhs = lhs.ConvertToImage(); + wxImage imRhs = rhs.ConvertToImage(); + + if (imLhs.HasAlpha() != imRhs.HasAlpha()) + return false; + + const int pixelCount = lhs.GetWidth() * lhs.GetHeight(); + + if (!std::equal(imLhs.GetData(), imLhs.GetData() + pixelCount * 3, imRhs.GetData())) + return false; + + if (imLhs.HasAlpha()) + if (!std::equal(imLhs.GetAlpha(), imLhs.GetAlpha() + pixelCount, imRhs.GetAlpha())) + return false; + + return true; +} + +/* +inline +wxColor gradient(const wxColor& from, const wxColor& to, double fraction) +{ + fraction = std::max(0.0, fraction); + fraction = std::min(1.0, fraction); + return wxColor(from.Red () + (to.Red () - from.Red ()) * fraction, + from.Green() + (to.Green() - from.Green()) * fraction, + from.Blue () + (to.Blue () - from.Blue ()) * fraction, + from.Alpha() + (to.Alpha() - from.Alpha()) * fraction); +} +*/ + +/* +inline +wxColor hsvColor(double h, double s, double v) //h within [0, 360), s, v within [0, 1] +{ + //http://de.wikipedia.org/wiki/HSV-Farbraum + + //make input values fit into bounds + if (h > 360) + h -= static_cast(h / 360) * 360; + else if (h < 0) + h -= static_cast(h / 360) * 360 - 360; + numeric::confine(s, 0, 1); + numeric::confine(v, 0, 1); + //------------------------------------ + const int h_i = h / 60; + const float f = h / 60 - h_i; + + auto polish = [](double val) -> unsigned char + { + int result = numeric::round(val * 255); + numeric::confine(result, 0, 255); + return static_cast(result); + }; + + const unsigned char p = polish(v * (1 - s)); + const unsigned char q = polish(v * (1 - s * f)); + const unsigned char t = polish(v * (1 - s * (1 - f))); + const unsigned char vi = polish(v); + + switch (h_i) + { + case 0: + return wxColor(vi, t, p); + case 1: + return wxColor(q, vi, p); + case 2: + return wxColor(p, vi, t); + case 3: + return wxColor(p, q, vi); + case 4: + return wxColor(t, p, vi); + case 5: + return wxColor(vi, p, q); + } + assert(false); + return *wxBLACK; +} +*/ +} + +#endif //IMAGE_TOOLS_H_45782456427634254 -- cgit