summaryrefslogtreecommitdiff
path: root/oox/source/drawingml
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2022-06-15 18:33:38 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2022-06-17 14:25:54 +0200
commit5772cef244dbee5834efbc693bc714d89ae6301d (patch)
tree136d4491c9cffc3638f29588a1bb4b3568a63648 /oox/source/drawingml
parent4dab8afe89c57318cc7503ae051963de89a6cd25 (diff)
tdf#134210: Reimplement cropping from srcRect and fillRect
This avoids the scaling after the crop, since scaling is performed anyway when applying BitmapMode_STRETCH. This improves resulting bitmap quality. Also consider the "crop to zero" case (when the sum of cropped parts is equal to 100%). In that case, just use an empty graphic as the fill bitmap. This makes the differences between srcRect and fillRect processing explicit, simplifies the code, avoids extra rounding inaccuracies, and takes care of the edge cases that were considered in commit 2859ec288f2c1323ea3123d82cb1684b349ff598 Author Miklos Vajna <vmiklos@collabora.com> Date Wed Jun 15 15:52:18 2022 +0200 oox: fix div by zero in lclCalculateCropPercentage() The change in SdImportTest2::testTdf134210 is because we now don't scale the cropped image. The previous value was an interpolated color, while the new value is the actual color of pixel [0, 41] of the original image. Change-Id: I24fa9928cff32bcaa6a7b3e34def14700fddd7ca Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135917 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'oox/source/drawingml')
-rw-r--r--oox/source/drawingml/fillproperties.cxx92
1 files changed, 39 insertions, 53 deletions
diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx
index 93fea51194ef..9270201920b3 100644
--- a/oox/source/drawingml/fillproperties.cxx
+++ b/oox/source/drawingml/fillproperties.cxx
@@ -88,67 +88,55 @@ Reference< XGraphic > lclRotateGraphic(uno::Reference<graphic::XGraphic> const &
return aReturnGraphic.GetXGraphic();
}
-void lclCalculateCropPercentage(uno::Reference<graphic::XGraphic> const & xGraphic, geometry::IntegerRectangle2D &aFillRect)
+using Quotients = std::tuple<double, double, double, double>;
+Quotients getQuotients(geometry::IntegerRectangle2D aRelRect, double hDiv, double vDiv)
{
- ::Graphic aGraphic(xGraphic);
- assert (aGraphic.GetType() == GraphicType::Bitmap);
-
- BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
-
- sal_Int32 nScaledWidth = aBitmapEx.GetSizePixel().Width();
- sal_Int32 nScaledHeight = aBitmapEx.GetSizePixel().Height();
-
- sal_Int32 nOrigWidth = (nScaledWidth * (100000 - aFillRect.X1 - aFillRect.X2)) / 100000;
- if (nOrigWidth == 0)
- {
- nOrigWidth = 1;
- }
- sal_Int32 nOrigHeight = (nScaledHeight * (100000 - aFillRect.Y1 - aFillRect.Y2)) / 100000;
- if (nOrigHeight == 0)
- {
- nOrigHeight = 1;
- }
+ return { aRelRect.X1 / hDiv, aRelRect.Y1 / vDiv, aRelRect.X2 / hDiv, aRelRect.Y2 / vDiv };
+}
- sal_Int32 nLeftPercentage = nScaledWidth * aFillRect.X1 / nOrigWidth;
- sal_Int32 nRightPercentage = nScaledWidth * aFillRect.X2 / nOrigWidth;
- sal_Int32 nTopPercentage = nScaledHeight * aFillRect.Y1 / nOrigHeight;
- sal_Int32 nBottomPercentage = nScaledHeight * aFillRect.Y2 / nOrigHeight;
+// ECMA-376 Part 1 20.1.8.55 srcRect (Source Rectangle)
+std::optional<Quotients> CropQuotientsFromSrcRect(geometry::IntegerRectangle2D aSrcRect)
+{
+ // Currently the following precondition is guaranteed in GraphicProperties::pushToPropMap
+ assert(aSrcRect.X1 >= 0 && aSrcRect.X2 >= 0 && aSrcRect.Y1 >= 0 && aSrcRect.Y2 >= 0);
+ if (aSrcRect.X1 + aSrcRect.X2 >= 100'000 || aSrcRect.Y1 + aSrcRect.Y2 >= 100'000)
+ return {}; // Cropped everything
+ return getQuotients(aSrcRect, 100'000.0, 100'000.0);
+}
- aFillRect.X1 = -nLeftPercentage;
- aFillRect.X2 = -nRightPercentage;
- aFillRect.Y1 = -nTopPercentage;
- aFillRect.Y2 = -nBottomPercentage;
+// ECMA-376 Part 1 20.1.8.30 fillRect (Fill Rectangle)
+std::optional<Quotients> CropQuotientsFromFillRect(geometry::IntegerRectangle2D aFillRect)
+{
+ // Currently the following precondition is guaranteed in FillProperties::pushToPropMap
+ assert(aFillRect.X1 <= 0 && aFillRect.X2 <= 0 && aFillRect.Y1 <= 0 && aFillRect.Y2 <= 0);
+ // Negative divisor and negative relative offset give positive value wanted in lclCropGraphic
+ return getQuotients(aFillRect, -100'000.0 + aFillRect.X1 + aFillRect.X2,
+ -100'000.0 + aFillRect.Y1 + aFillRect.Y2);
}
-// Crops a piece of the bitmap. Takes negative aFillRect values. Negative values means "crop",
-// positive values means "grow" bitmap with empty spaces. lclCropGraphic doesn't handle growing.
-Reference< XGraphic > lclCropGraphic(uno::Reference<graphic::XGraphic> const & xGraphic, geometry::IntegerRectangle2D aFillRect)
+// Crops a piece of the bitmap. lclCropGraphic doesn't handle growing.
+Reference<XGraphic> lclCropGraphic(uno::Reference<graphic::XGraphic> const& xGraphic,
+ std::optional<Quotients> quotients)
{
::Graphic aGraphic(xGraphic);
- ::Graphic aReturnGraphic;
-
assert (aGraphic.GetType() == GraphicType::Bitmap);
- BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
-
- sal_Int32 nOrigHeight = aBitmapEx.GetSizePixel().Height();
- sal_Int32 nHeight = nOrigHeight;
- sal_Int32 nTopCorr = nOrigHeight * -1 * static_cast<double>(aFillRect.Y1) / 100000;
- nHeight += nTopCorr;
- sal_Int32 nBottomCorr = nOrigHeight * -1 * static_cast<double>(aFillRect.Y2) / 100000;
- nHeight += nBottomCorr;
+ BitmapEx aBitmapEx;
+ if (quotients)
+ {
+ aBitmapEx = aGraphic.GetBitmapEx();
- sal_Int32 nOrigWidth = aBitmapEx.GetSizePixel().Width();
- sal_Int32 nWidth = nOrigWidth;
- sal_Int32 nLeftCorr = nOrigWidth * -1 * static_cast<double>(aFillRect.X1) / 100000;
- nWidth += nLeftCorr;
- sal_Int32 nRightCorr = nOrigWidth * -1 * static_cast<double>(aFillRect.X2) / 100000;
- nWidth += nRightCorr;
+ const Size bmpSize = aBitmapEx.GetSizePixel();
+ const auto& [qx1, qy1, qx2, qy2] = *quotients;
+ const tools::Long l = std::round(bmpSize.Width() * qx1);
+ const tools::Long t = std::round(bmpSize.Height() * qy1);
+ const tools::Long r = std::round(bmpSize.Width() * qx2);
+ const tools::Long b = std::round(bmpSize.Height() * qy2);
- aBitmapEx.Scale(Size(nWidth, nHeight));
- aBitmapEx.Crop(tools::Rectangle(Point(nLeftCorr, nTopCorr), Size(nOrigWidth, nOrigHeight)));
+ aBitmapEx.Crop({ l, t, bmpSize.Width() - r - 1, bmpSize.Height() - b - 1 });
+ }
- aReturnGraphic = ::Graphic(aBitmapEx);
+ ::Graphic aReturnGraphic(aBitmapEx);
aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
return aReturnGraphic.GetXGraphic();
@@ -818,7 +806,7 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap,
if(bIsCustomShape && bHasCropValues && bNeedCrop)
{
- xGraphic = lclCropGraphic(xGraphic, aFillRect);
+ xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromFillRect(aFillRect));
rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic);
}
}
@@ -932,9 +920,7 @@ void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelpe
if(mbIsCustomShape && bHasCropValues && bNeedCrop)
{
- geometry::IntegerRectangle2D aCropRect = oClipRect;
- lclCalculateCropPercentage(xGraphic, aCropRect);
- xGraphic = lclCropGraphic(xGraphic, aCropRect);
+ xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromSrcRect(oClipRect));
}
}
}