From 2c4014d716c67ba77ccfbda01edb98ad2ab32fb3 Mon Sep 17 00:00:00 2001 From: Oleg Samarin Date: Sat, 17 Jan 2026 23:09:57 +0300 Subject: [PATCH] Fixed assertion fail on resizing --- .../gui/panels/primitives/GOBitmap.cpp | 109 +++++++++++------- .../gui/panels/primitives/GOBitmap.h | 11 +- src/grandorgue/gui/panels/primitives/GODC.cpp | 11 +- 3 files changed, 85 insertions(+), 46 deletions(-) diff --git a/src/grandorgue/gui/panels/primitives/GOBitmap.cpp b/src/grandorgue/gui/panels/primitives/GOBitmap.cpp index 520faaf09..c7fa57b2c 100644 --- a/src/grandorgue/gui/panels/primitives/GOBitmap.cpp +++ b/src/grandorgue/gui/panels/primitives/GOBitmap.cpp @@ -21,27 +21,37 @@ unsigned GOBitmap::GetSourceHeight() const { void GOBitmap::BuildBitmapFrom( const wxImage &img, double scale, const wxRect &rect, GOBitmap *background) { - if (background && img.HasAlpha()) { - wxBitmap bmp(img.GetWidth(), img.GetHeight()); - wxBitmap orig(img); - wxMemoryDC dc; - - dc.SelectObject(bmp); - dc.DrawBitmap( - background->GetResultBitmap(), -rect.GetX(), -rect.GetY(), false); - dc.DrawBitmap(orig, 0, 0, true); - bmp.SetMask(orig.GetMask()); - wxImage img_result = bmp.ConvertToImage(); - if (!img_result.HasAlpha()) - img_result.InitAlpha(); - memcpy( - img_result.GetAlpha(), img.GetAlpha(), img.GetWidth() * img.GetHeight()); - - m_ResultBitmap = (wxBitmap)img_result.Scale( - img.GetWidth() * scale, img.GetHeight() * scale, wxIMAGE_QUALITY_BICUBIC); - } else - m_ResultBitmap = (wxBitmap)img.Scale( - img.GetWidth() * scale, img.GetHeight() * scale, wxIMAGE_QUALITY_BICUBIC); + const int imgHeight = img.GetHeight(); + const int imgWidth = img.GetWidth(); + const int newHeight = imgHeight * scale; + const int newWidth = imgWidth * scale; + + m_ResultValid = newHeight > 0 && newWidth > 0; + if (m_ResultValid) { + const wxBitmap *pBackgroundBitmap + = background ? background->GetResultBitmap() : nullptr; + + if (pBackgroundBitmap && img.HasAlpha()) { + wxBitmap bmp(imgWidth, imgHeight); + wxBitmap orig(img); + wxMemoryDC dc; + + dc.SelectObject(bmp); + dc.DrawBitmap(*pBackgroundBitmap, -rect.GetX(), -rect.GetY(), false); + dc.DrawBitmap(orig, 0, 0, true); + bmp.SetMask(orig.GetMask()); + + wxImage img_result = bmp.ConvertToImage(); + + if (!img_result.HasAlpha()) + img_result.InitAlpha(); + memcpy(img_result.GetAlpha(), img.GetAlpha(), imgWidth * imgHeight); + m_ResultBitmap = (wxBitmap)img_result.Scale( + newWidth, newHeight, wxIMAGE_QUALITY_BICUBIC); + } else + m_ResultBitmap + = (wxBitmap)img.Scale(newWidth, newHeight, wxIMAGE_QUALITY_BICUBIC); + } m_Scale = scale; } @@ -56,26 +66,47 @@ void GOBitmap::BuildScaledBitmap( void GOBitmap::BuildTileBitmap( double scale, - const wxRect &rect, - unsigned xo, - unsigned yo, + const wxRect &newRect, + unsigned newXOffset, + unsigned newYOffset, GOBitmap *background) { + const int tgtHeight = newRect.GetHeight(); + const int tgtWidth = newRect.GetWidth(); + if ( p_SourceImage - && ( - scale != m_Scale - || m_ResultWidth != rect.GetWidth() - || m_ResultHeight != rect.GetHeight() || xo != m_ResultXOffset - || yo != m_ResultYOffset)) { - wxImage img(rect.GetWidth(), rect.GetHeight()); - - for (int y = -yo; y < img.GetHeight(); y += GetSourceHeight()) - for (int x = -xo; x < img.GetWidth(); x += GetSourceWidth()) - img.Paste(*p_SourceImage, x, y); - BuildBitmapFrom(img, scale, rect, background); - m_ResultWidth = rect.GetWidth(); - m_ResultHeight = rect.GetHeight(); - m_ResultXOffset = xo; - m_ResultYOffset = yo; + && (scale != m_Scale || m_ResultWidth != tgtHeight || m_ResultHeight != tgtWidth || newXOffset != m_ResultXOffset || newYOffset != m_ResultYOffset)) { + const int srcHeight = p_SourceImage->GetHeight(); + const int srcWidth = p_SourceImage->GetWidth(); + wxImage img(tgtWidth, tgtHeight); + + for (int y = -newYOffset; y < tgtHeight; y += srcHeight) + for (int x = -newXOffset; x < tgtWidth; x += srcWidth) { + // Calculate source starting position using std::max(0, -offset) + const int srcX = std::max(0, -x); + const int srcY = std::max(0, -y); + + // Ensure copy stays within target bounds using std::min + const int copyWidth = std::min(srcWidth - srcX, tgtWidth - x); + const int copyHeight = std::min(srcHeight - srcY, tgtHeight - y); + + // Paste only if valid copy region exists + if (copyWidth > 0 && copyHeight > 0) { + if (copyWidth != (int)srcWidth || copyHeight != (int)srcHeight) { + // Partial copy - use GetSubImage + wxImage tile = p_SourceImage->GetSubImage( + wxRect(srcX, srcY, copyWidth, copyHeight)); + img.Paste(tile, x, y); + } else { + // Full tile copy - use direct Paste + img.Paste(*p_SourceImage, x, y); + } + } + } + BuildBitmapFrom(img, scale, newRect, background); + m_ResultHeight = tgtHeight; + m_ResultWidth = tgtWidth; + m_ResultXOffset = newXOffset; + m_ResultYOffset = newYOffset; } } diff --git a/src/grandorgue/gui/panels/primitives/GOBitmap.h b/src/grandorgue/gui/panels/primitives/GOBitmap.h index c8bf69839..fe111dee4 100644 --- a/src/grandorgue/gui/panels/primitives/GOBitmap.h +++ b/src/grandorgue/gui/panels/primitives/GOBitmap.h @@ -27,6 +27,7 @@ class GOBitmap { int m_ResultHeight = 0; unsigned m_ResultXOffset = 0; unsigned m_ResultYOffset = 0; + bool m_ResultValid = false; void BuildBitmapFrom( const wxImage &img, double scale, const wxRect &rect, GOBitmap *background); @@ -41,12 +42,14 @@ class GOBitmap { double scale, const wxRect &rect, GOBitmap *background); void BuildTileBitmap( double scale, - const wxRect &rect, - unsigned xo, - unsigned yo, + const wxRect &newRect, + unsigned newXOffset, + unsigned newYOffset, GOBitmap *background); - const wxBitmap &GetResultBitmap() const { return m_ResultBitmap; } + const wxBitmap *GetResultBitmap() const { + return m_ResultValid ? &m_ResultBitmap : nullptr; + } }; #endif diff --git a/src/grandorgue/gui/panels/primitives/GODC.cpp b/src/grandorgue/gui/panels/primitives/GODC.cpp index c53dbb2bf..2b0ef545d 100644 --- a/src/grandorgue/gui/panels/primitives/GODC.cpp +++ b/src/grandorgue/gui/panels/primitives/GODC.cpp @@ -24,9 +24,14 @@ wxRect GODC::ScaleRect(const wxRect &rect) { } void GODC::DrawBitmap(GOBitmap &bitmap, const wxRect &target) { - unsigned xpos = target.GetX() * m_Scale + 0.5; - unsigned ypos = target.GetY() * m_Scale + 0.5; - m_DC->DrawBitmap(bitmap.GetResultBitmap(), xpos, ypos, true); + const wxBitmap *pBitmap = bitmap.GetResultBitmap(); + + if (pBitmap) { + unsigned xpos = target.GetX() * m_Scale + 0.5; + unsigned ypos = target.GetY() * m_Scale + 0.5; + + m_DC->DrawBitmap(*pBitmap, xpos, ypos, true); + } } wxString GODC::WrapText(const wxString &string, unsigned width) {