diff options
Diffstat (limited to 'wx+/image_tools.cpp')
-rwxr-xr-x[-rw-r--r--] | wx+/image_tools.cpp | 466 |
1 files changed, 233 insertions, 233 deletions
diff --git a/wx+/image_tools.cpp b/wx+/image_tools.cpp index 90945a44..4b0f324f 100644..100755 --- a/wx+/image_tools.cpp +++ b/wx+/image_tools.cpp @@ -1,233 +1,233 @@ -// ***************************************************************************** -// * 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 * -// ***************************************************************************** - -#include "image_tools.h" -#include <zen/string_tools.h> -#include <wx/app.h> - - -using namespace zen; - -namespace -{ -void writeToImage(const wxImage& source, wxImage& target, const wxPoint& pos) -{ - const int srcWidth = source.GetWidth (); - const int srcHeight = source.GetHeight(); - const int trgWidth = target.GetWidth (); - - if (srcWidth > 0 && srcHeight > 0) - { - assert(0 <= pos.x && pos.x + srcWidth <= trgWidth ); //draw area must be a - assert(0 <= pos.y && pos.y + srcHeight <= target.GetHeight()); //subset of target image! - assert(target.HasAlpha()); - - { - const unsigned char* sourcePtr = source.GetData(); - unsigned char* targetPtr = target.GetData() + 3 * (pos.x + pos.y * trgWidth); - - for (int row = 0; row < srcHeight; ++row) - ::memcpy(targetPtr + 3 * row * trgWidth, sourcePtr + 3 * row * srcWidth, 3 * srcWidth); - } - - //handle alpha channel - { - unsigned char* targetPtr = target.GetAlpha() + pos.x + pos.y * trgWidth; - if (source.HasAlpha()) - { - const unsigned char* sourcePtr = source.GetAlpha(); - for (int row = 0; row < srcHeight; ++row) - ::memcpy(targetPtr + row * trgWidth, sourcePtr + row * srcWidth, srcWidth); - } - else - for (int row = 0; row < srcHeight; ++row) - ::memset(targetPtr + row * trgWidth, wxIMAGE_ALPHA_OPAQUE, srcWidth); - } - } -} -} - - -wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLayout dir, ImageStackAlignment align, int gap) -{ - assert(gap >= 0); - gap = std::max(0, gap); - - const int img1Width = img1.GetWidth (); - const int img1Height = img1.GetHeight(); - const int img2Width = img2.GetWidth (); - const int img2Height = img2.GetHeight(); - - int width = std::max(img1Width, img2Width); - int height = std::max(img1Height, img2Height); - switch (dir) - { - case ImageStackLayout::HORIZONTAL: - width = img1Width + gap + img2Width; - break; - - case ImageStackLayout::VERTICAL: - height = img1Height + gap + img2Height; - break; - } - wxImage output(width, height); - output.SetAlpha(); - ::memset(output.GetAlpha(), wxIMAGE_ALPHA_TRANSPARENT, width * height); - - auto calcPos = [&](int imageExtent, int totalExtent) - { - switch (align) - { - case ImageStackAlignment::CENTER: - return (totalExtent - imageExtent) / 2; - case ImageStackAlignment::LEFT: - return 0; - case ImageStackAlignment::RIGHT: - return totalExtent - imageExtent; - } - assert(false); - return 0; - }; - - switch (dir) - { - case ImageStackLayout::HORIZONTAL: - writeToImage(img1, output, wxPoint(0, calcPos(img1Height, height))); - writeToImage(img2, output, wxPoint(img1Width + gap, calcPos(img2Height, height))); - break; - - case ImageStackLayout::VERTICAL: - writeToImage(img1, output, wxPoint(calcPos(img1Width, width), 0)); - writeToImage(img2, output, wxPoint(calcPos(img2Width, width), img1Height + gap)); - break; - } - return output; -} - - -namespace -{ -void calcAlphaForBlackWhiteImage(wxImage& image) //assume black text on white background -{ - assert(image.HasAlpha()); - if (unsigned char* alphaPtr = image.GetAlpha()) - { - const int pixelCount = image.GetWidth() * image.GetHeight(); - const unsigned char* dataPtr = image.GetData(); - for (int i = 0; i < pixelCount; ++ i) - { - const unsigned char r = *dataPtr++; - const unsigned char g = *dataPtr++; - const unsigned char b = *dataPtr++; - - //black(0,0,0) becomes fully opaque(255), while white(255,255,255) becomes transparent(0) - alphaPtr[i] = static_cast<unsigned char>((255 - r + 255 - g + 255 - b) / 3); //mixed mode arithmetics! - } - } -} - - -wxSize getTextExtent(const wxString& text, const wxFont& font) -{ - wxMemoryDC dc; //the context used for bitmaps - dc.SetFont(font); //the font parameter of GetMultiLineTextExtent() is not evalated on OS X, wxWidgets 2.9.5, so apply it to the DC directly! - return dc.GetMultiLineTextExtent(replaceCpy(text, L"&", L"", false)); //remove accelerator -} -} - -wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const wxColor& col) -{ - //wxDC::DrawLabel() doesn't respect alpha channel => calculate alpha values manually: - - if (text.empty()) - return wxImage(); - - wxBitmap newBitmap(getTextExtent(text, font)); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes - { - wxMemoryDC dc(newBitmap); - dc.SetBackground(*wxWHITE_BRUSH); - dc.Clear(); - - dc.SetTextForeground(*wxBLACK); //for use in calcAlphaForBlackWhiteImage - dc.SetTextBackground(*wxWHITE); // - dc.SetFont(font); - - //assert(!contains(text, L"&")); //accelerator keys not supported here; see also getTextExtent() - wxString textFmt = replaceCpy(text, L"&", L"", false); - - //for some reason wxDC::DrawText messes up "weak" bidi characters even when wxLayout_RightToLeft is set! (--> arrows in hebrew/arabic) - //=> use mark characters instead: - const wchar_t rtlMark = L'\u200F'; //UTF-8: E2 80 8F - if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft) - textFmt = rtlMark + textFmt + rtlMark; - - dc.DrawText(textFmt, wxPoint()); - } - - wxImage output(newBitmap.ConvertToImage()); - output.SetAlpha(); - - //calculate alpha channel - calcAlphaForBlackWhiteImage(output); - - //apply actual text color - unsigned char* dataPtr = output.GetData(); - const int pixelCount = output.GetWidth() * output.GetHeight(); - for (int i = 0; i < pixelCount; ++ i) - { - *dataPtr++ = col.Red(); - *dataPtr++ = col.Green(); - *dataPtr++ = col.Blue(); - } - return output; -} - - -void zen::convertToVanillaImage(wxImage& img) -{ - if (!img.HasAlpha()) - { - const int width = img.GetWidth (); - const int height = img.GetHeight(); - if (width <= 0 || height <= 0) return; - - unsigned char mask_r = 0; - unsigned char mask_g = 0; - unsigned char mask_b = 0; - const bool haveMask = img.HasMask() && img.GetOrFindMaskColour(&mask_r, &mask_g, &mask_b); - //check for mask before calling wxImage::GetOrFindMaskColour() to skip needlessly searching for new mask color - - img.SetAlpha(); - ::memset(img.GetAlpha(), wxIMAGE_ALPHA_OPAQUE, width * height); - - //wxWidgets, as always, tries to be more clever than it really is and fucks up wxStaticBitmap if wxBitmap is fully opaque: - img.GetAlpha()[width * height - 1] = 254; - - if (haveMask) - { - img.SetMask(false); - unsigned char* alphaPtr = img.GetAlpha(); - const unsigned char* dataPtr = img.GetData(); - - const int pixelCount = width * height; - for (int i = 0; i < pixelCount; ++ i) - { - const unsigned char r = *dataPtr++; - const unsigned char g = *dataPtr++; - const unsigned char b = *dataPtr++; - - if (r == mask_r && - g == mask_g && - b == mask_b) - alphaPtr[i] = wxIMAGE_ALPHA_TRANSPARENT; - } - } - } - else - { - assert(!img.HasMask()); - } -} +// *****************************************************************************
+// * 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 *
+// *****************************************************************************
+
+#include "image_tools.h"
+#include <zen/string_tools.h>
+#include <wx/app.h>
+
+
+using namespace zen;
+
+namespace
+{
+void writeToImage(const wxImage& source, wxImage& target, const wxPoint& pos)
+{
+ const int srcWidth = source.GetWidth ();
+ const int srcHeight = source.GetHeight();
+ const int trgWidth = target.GetWidth ();
+
+ if (srcWidth > 0 && srcHeight > 0)
+ {
+ assert(0 <= pos.x && pos.x + srcWidth <= trgWidth ); //draw area must be a
+ assert(0 <= pos.y && pos.y + srcHeight <= target.GetHeight()); //subset of target image!
+ assert(target.HasAlpha());
+
+ {
+ const unsigned char* sourcePtr = source.GetData();
+ unsigned char* targetPtr = target.GetData() + 3 * (pos.x + pos.y * trgWidth);
+
+ for (int row = 0; row < srcHeight; ++row)
+ ::memcpy(targetPtr + 3 * row * trgWidth, sourcePtr + 3 * row * srcWidth, 3 * srcWidth);
+ }
+
+ //handle alpha channel
+ {
+ unsigned char* targetPtr = target.GetAlpha() + pos.x + pos.y * trgWidth;
+ if (source.HasAlpha())
+ {
+ const unsigned char* sourcePtr = source.GetAlpha();
+ for (int row = 0; row < srcHeight; ++row)
+ ::memcpy(targetPtr + row * trgWidth, sourcePtr + row * srcWidth, srcWidth);
+ }
+ else
+ for (int row = 0; row < srcHeight; ++row)
+ ::memset(targetPtr + row * trgWidth, wxIMAGE_ALPHA_OPAQUE, srcWidth);
+ }
+ }
+}
+}
+
+
+wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLayout dir, ImageStackAlignment align, int gap)
+{
+ assert(gap >= 0);
+ gap = std::max(0, gap);
+
+ const int img1Width = img1.GetWidth ();
+ const int img1Height = img1.GetHeight();
+ const int img2Width = img2.GetWidth ();
+ const int img2Height = img2.GetHeight();
+
+ int width = std::max(img1Width, img2Width);
+ int height = std::max(img1Height, img2Height);
+ switch (dir)
+ {
+ case ImageStackLayout::HORIZONTAL:
+ width = img1Width + gap + img2Width;
+ break;
+
+ case ImageStackLayout::VERTICAL:
+ height = img1Height + gap + img2Height;
+ break;
+ }
+ wxImage output(width, height);
+ output.SetAlpha();
+ ::memset(output.GetAlpha(), wxIMAGE_ALPHA_TRANSPARENT, width * height);
+
+ auto calcPos = [&](int imageExtent, int totalExtent)
+ {
+ switch (align)
+ {
+ case ImageStackAlignment::CENTER:
+ return (totalExtent - imageExtent) / 2;
+ case ImageStackAlignment::LEFT:
+ return 0;
+ case ImageStackAlignment::RIGHT:
+ return totalExtent - imageExtent;
+ }
+ assert(false);
+ return 0;
+ };
+
+ switch (dir)
+ {
+ case ImageStackLayout::HORIZONTAL:
+ writeToImage(img1, output, wxPoint(0, calcPos(img1Height, height)));
+ writeToImage(img2, output, wxPoint(img1Width + gap, calcPos(img2Height, height)));
+ break;
+
+ case ImageStackLayout::VERTICAL:
+ writeToImage(img1, output, wxPoint(calcPos(img1Width, width), 0));
+ writeToImage(img2, output, wxPoint(calcPos(img2Width, width), img1Height + gap));
+ break;
+ }
+ return output;
+}
+
+
+namespace
+{
+void calcAlphaForBlackWhiteImage(wxImage& image) //assume black text on white background
+{
+ assert(image.HasAlpha());
+ if (unsigned char* alphaPtr = image.GetAlpha())
+ {
+ const int pixelCount = image.GetWidth() * image.GetHeight();
+ const unsigned char* dataPtr = image.GetData();
+ for (int i = 0; i < pixelCount; ++ i)
+ {
+ const unsigned char r = *dataPtr++;
+ const unsigned char g = *dataPtr++;
+ const unsigned char b = *dataPtr++;
+
+ //black(0,0,0) becomes fully opaque(255), while white(255,255,255) becomes transparent(0)
+ alphaPtr[i] = static_cast<unsigned char>((255 - r + 255 - g + 255 - b) / 3); //mixed mode arithmetics!
+ }
+ }
+}
+
+
+wxSize getTextExtent(const wxString& text, const wxFont& font)
+{
+ wxMemoryDC dc; //the context used for bitmaps
+ dc.SetFont(font); //the font parameter of GetMultiLineTextExtent() is not evalated on OS X, wxWidgets 2.9.5, so apply it to the DC directly!
+ return dc.GetMultiLineTextExtent(replaceCpy(text, L"&", L"", false)); //remove accelerator
+}
+}
+
+wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const wxColor& col)
+{
+ //wxDC::DrawLabel() doesn't respect alpha channel => calculate alpha values manually:
+
+ if (text.empty())
+ return wxImage();
+
+ wxBitmap newBitmap(getTextExtent(text, font)); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes
+ {
+ wxMemoryDC dc(newBitmap);
+ dc.SetBackground(*wxWHITE_BRUSH);
+ dc.Clear();
+
+ dc.SetTextForeground(*wxBLACK); //for use in calcAlphaForBlackWhiteImage
+ dc.SetTextBackground(*wxWHITE); //
+ dc.SetFont(font);
+
+ //assert(!contains(text, L"&")); //accelerator keys not supported here; see also getTextExtent()
+ wxString textFmt = replaceCpy(text, L"&", L"", false);
+
+ //for some reason wxDC::DrawText messes up "weak" bidi characters even when wxLayout_RightToLeft is set! (--> arrows in hebrew/arabic)
+ //=> use mark characters instead:
+ const wchar_t rtlMark = L'\u200F'; //UTF-8: E2 80 8F
+ if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft)
+ textFmt = rtlMark + textFmt + rtlMark;
+
+ dc.DrawText(textFmt, wxPoint());
+ }
+
+ wxImage output(newBitmap.ConvertToImage());
+ output.SetAlpha();
+
+ //calculate alpha channel
+ calcAlphaForBlackWhiteImage(output);
+
+ //apply actual text color
+ unsigned char* dataPtr = output.GetData();
+ const int pixelCount = output.GetWidth() * output.GetHeight();
+ for (int i = 0; i < pixelCount; ++ i)
+ {
+ *dataPtr++ = col.Red();
+ *dataPtr++ = col.Green();
+ *dataPtr++ = col.Blue();
+ }
+ return output;
+}
+
+
+void zen::convertToVanillaImage(wxImage& img)
+{
+ if (!img.HasAlpha())
+ {
+ const int width = img.GetWidth ();
+ const int height = img.GetHeight();
+ if (width <= 0 || height <= 0) return;
+
+ unsigned char mask_r = 0;
+ unsigned char mask_g = 0;
+ unsigned char mask_b = 0;
+ const bool haveMask = img.HasMask() && img.GetOrFindMaskColour(&mask_r, &mask_g, &mask_b);
+ //check for mask before calling wxImage::GetOrFindMaskColour() to skip needlessly searching for new mask color
+
+ img.SetAlpha();
+ ::memset(img.GetAlpha(), wxIMAGE_ALPHA_OPAQUE, width * height);
+
+ //wxWidgets, as always, tries to be more clever than it really is and fucks up wxStaticBitmap if wxBitmap is fully opaque:
+ img.GetAlpha()[width * height - 1] = 254;
+
+ if (haveMask)
+ {
+ img.SetMask(false);
+ unsigned char* alphaPtr = img.GetAlpha();
+ const unsigned char* dataPtr = img.GetData();
+
+ const int pixelCount = width * height;
+ for (int i = 0; i < pixelCount; ++ i)
+ {
+ const unsigned char r = *dataPtr++;
+ const unsigned char g = *dataPtr++;
+ const unsigned char b = *dataPtr++;
+
+ if (r == mask_r &&
+ g == mask_g &&
+ b == mask_b)
+ alphaPtr[i] = wxIMAGE_ALPHA_TRANSPARENT;
+ }
+ }
+ }
+ else
+ {
+ assert(!img.HasMask());
+ }
+}
|