View Issue Details

IDProjectCategoryView StatusLast Update
0015560ScribusGraphics / Image Framespublic2024-01-08 03:59
Reporterale Assigned Toale  
PrioritynormalSeverityfeatureReproducibilityN/A
Status assignedResolutionopen 
Target Version1.5.5.svn 
Summary0015560: [PATCH (needs review)] fill a frame with the image
Description- the frame has a fixed size,
- the image has different proportions than the frame
- i want the frame to be 100% filled.

this is a common use case for me and i can get there with scribus but it's more painful than it should.
(see the screencast in the first note)

i propose to add a third option to the image scaling:

- free
- fit to frame size
- fill the frame

filling the frame means:
- by default scale to the minimal scale that fills the frame
- only allow movements that do not create a white padding (see 0015448)
- (optional: allow scaling in)
Tagspatch
PatchYes

Relationships

related to 0015448 assignedale [PATCH] when an image is set to fit the frame, it should just fit it 
has duplicate 0016137 new Add option to always fill image frame 
related to 0015713 closedJLuc Provide new "fixed viewport" image resize mode 
related to 0011142 new Fit image to fill frame 

Activities

ale

2019-01-28 09:02

manager  

image-fill-demo.gif (193,501 bytes)   
image-fill-demo.gif (193,501 bytes)   

ale

2019-01-28 09:11

manager   ~0045867

the current steps are:
- scale to frame size
- non proportional
- link the x and y scale to make it again proportional
- move the image inside of the frames
- set x-pos or y-pos so that there cannot be any padding bands.

ale

2019-03-06 14:42

manager   ~0045971

Last edited: 2019-03-06 16:29

i've attached a patch.

it does work but it has a big "error": since the 0 value has changed (from false to the first item in the enum) existing .sla files will be read incorrectly.

i see a few ways for fixing this, but i first want to have other people opinion on what could be a good solution.

p.s.: the same is also valid for the preferences, but that's less of an issue in my eyes...

p.p.s: this patch is based on the "fit to frame" patch

ale

2019-03-06 14:43

manager  

image-fill-mode.diff (67,043 bytes)   
diff --git a/scribus/appmodehelper.cpp b/scribus/appmodehelper.cpp
index 2f6a32801..d26be66fa 100644
--- a/scribus/appmodehelper.cpp
+++ b/scribus/appmodehelper.cpp
@@ -570,7 +570,7 @@ void AppModeHelper::enableActionsForSelection(ScribusMainWindow* scmw, ScribusDo
 			(*a_scrActions)["toolsUnlinkTextFrame"]->setEnabled(false);
 			(*a_scrActions)["toolsUnlinkTextFrameAndCutText"]->setEnabled(false);
 			(*a_scrActions)["toolsLinkTextFrame"]->setEnabled(false);
-			(*a_scrActions)["toolsEditContents"]->setEnabled(currItem->ScaleType);
+			(*a_scrActions)["toolsEditContents"]->setEnabled(true);
 			(*a_scrActions)["toolsEditWithStoryEditor"]->setEnabled(false);
 			(*a_scrActions)["toolsRotate"]->setEnabled(!inAnEditMode);
 			(*a_scrActions)["toolsCopyProperties"]->setEnabled(!inAnEditMode);
diff --git a/scribus/canvasgesture_resize.cpp b/scribus/canvasgesture_resize.cpp
index a43ef1f63..52fceaefe 100644
--- a/scribus/canvasgesture_resize.cpp
+++ b/scribus/canvasgesture_resize.cpp
@@ -313,7 +313,7 @@ void ResizeGesture::doResize(bool scaleContent)
 			double imgScX = (newBounds.width() - m_extraWidth) / divX * currItem->imageXScale();
 			double imgScY = (newBounds.height() - m_extraHeight) / divY * currItem->imageYScale();
 			// The aspect ratio has been fixed, so make the modification in the direction of the larger movement.
-			if (currItem->keepAspectRatio() && currItem->fitImageToFrame()) 
+			if (currItem->keepAspectRatio() && currItem->isImageScaleFit()) 
 			{
 				if (qAbs((newBounds.width() - m_extraWidth) - currItem->width()) > qAbs((newBounds.height() - m_extraHeight) - currItem->height()))
 					imgScY = imgScX;
@@ -322,7 +322,7 @@ void ResizeGesture::doResize(bool scaleContent)
 			}
 			currItem->setImageXYScale(imgScX, imgScY);
 		}
-		else if (currItem->itemType() == PageItem::ImageFrame && currItem->imageIsAvailable && !currItem->fitImageToFrame())
+		else if (currItem->itemType() == PageItem::ImageFrame && currItem->imageIsAvailable && !currItem->isImageScaleFit())
 		{
 			QTransform mm = currItem->getTransform();
 			QPointF itPos = mm.map(QPointF(-m_extraX, -m_extraY));
diff --git a/scribus/canvasmode.cpp b/scribus/canvasmode.cpp
index 036fbaf5d..a39463b65 100644
--- a/scribus/canvasmode.cpp
+++ b/scribus/canvasmode.cpp
@@ -1313,7 +1313,7 @@ void CanvasMode::commonkeyPressEvent_NormalNodeEdit(QKeyEvent *e)
 			double radRotation = rotationFC * M_PI / 180.0;
 
 			bool moveImage = false;
-			if ((currItem->asImageFrame() || currItem->asLatexFrame() || currItem->asOSGFrame()) && currItem->imageIsAvailable && !currItem->fitImageToFrame())
+			if ((currItem->asImageFrame() || currItem->asLatexFrame() || currItem->asOSGFrame()) && currItem->imageIsAvailable && !currItem->isImageScaleFit())
 				moveImage = true;
 
 			switch (kk)
diff --git a/scribus/canvasmode_edit.cpp b/scribus/canvasmode_edit.cpp
index cbf5eabea..863ee8ee9 100644
--- a/scribus/canvasmode_edit.cpp
+++ b/scribus/canvasmode_edit.cpp
@@ -417,8 +417,7 @@ void CanvasMode_Edit::mouseMoveEvent(QMouseEvent *m)
 			{
 				if (m->modifiers() & Qt::ShiftModifier)
 				{
-					// only rotate if free scale
-					if (currItem->ScaleType)
+					if (currItem->isImageScaleFree())
 					{
 						m_view->setCursor(IconManager::instance()->loadCursor("Rotieren2.png"));
 						QTransform p = currItem->getTransform();
diff --git a/scribus/canvasmode_normal.cpp b/scribus/canvasmode_normal.cpp
index 9688f569c..c6331a338 100644
--- a/scribus/canvasmode_normal.cpp
+++ b/scribus/canvasmode_normal.cpp
@@ -196,7 +196,7 @@ void CanvasMode_Normal::mouseDoubleClickEvent(QMouseEvent *m)
 	{
 		if (currItem->asLatexFrame()) 
 		{
-			if (currItem->locked()) // || (!currItem->ScaleType))
+			if (currItem->locked())
 			{
 				return;
 			}
@@ -209,7 +209,7 @@ void CanvasMode_Normal::mouseDoubleClickEvent(QMouseEvent *m)
 		}
 		else if ((currItem->itemType() == PageItem::Polygon) || (currItem->itemType() == PageItem::PolyLine) || (currItem->itemType() == PageItem::Group) || (currItem->itemType() == PageItem::ImageFrame) || (currItem->itemType() == PageItem::PathText))
 		{
-			if (currItem->locked()) //|| (!currItem->ScaleType))
+			if (currItem->locked())
 			{
 				//mousePressEvent(m);
 				return;
diff --git a/scribus/pageitem.cpp b/scribus/pageitem.cpp
index c6a8bce2f..594d48757 100644
--- a/scribus/pageitem.cpp
+++ b/scribus/pageitem.cpp
@@ -192,7 +192,7 @@ PageItem::PageItem(const PageItem & other)
 	OldH2(other.OldH2),
 	Sizing(other.Sizing),
 	m_layerID(other.m_layerID),
-	ScaleType(other.ScaleType),
+	m_scaleMode{other.m_scaleMode},
 	AspectRatio(other.AspectRatio),
 	DashValues(other.DashValues),
 	DashOffset(other.DashOffset),
@@ -650,7 +650,7 @@ PageItem::PageItem(ScribusDoc *pa, ItemType newType, double x, double y, double
 	groupWidth = 1.0;
 	groupHeight = 1.0;
 	m_layerID = m_Doc->activeLayer();
-	ScaleType = true;
+	m_scaleMode = ImageScaleMode::free;
 	AspectRatio = true;
 	NamedLStyle = "";
 	DashValues.clear();
@@ -4219,24 +4219,44 @@ void PageItem::flipImageV()
 	m_ImageIsFlippedV = !m_ImageIsFlippedV;
 }
 
-void PageItem::setImageScalingMode(bool freeScale, bool keepRatio)
+void PageItem::setImageScalingMode(ImageScaleMode scaleMode, bool keepRatio)
 {
-	if (ScaleType == freeScale && AspectRatio == keepRatio)
+	if (scaleMode == ImageScaleMode::free && AspectRatio == keepRatio)
+	{
+		m_scaleMode = scaleMode;
+		update();
 		return;
+	}
+
 	if (UndoManager::undoEnabled())
 	{
-		QString from = ScaleType ? Um::FreeScaling : Um::FrameSize;
+		QString from = "";
+		if (m_scaleMode == ImageScaleMode::free)
+			from += Um::FreeScaling;
+		else if (m_scaleMode == ImageScaleMode::fit)
+			from += Um::FrameSize;
+		else if (m_scaleMode == ImageScaleMode::fill)
+			from += Um::FrameFill;
 		from += ", ";
 		from += AspectRatio ? Um::KeepRatio : Um::BreakRatio;
-		QString to = freeScale ? Um::FreeScaling : Um::FrameSize;
+
+		QString to = "";
+		if (scaleMode == ImageScaleMode::free)
+			to += Um::FreeScaling;
+		else if (scaleMode == ImageScaleMode::fit)
+			to += Um::FrameSize;
+		else if (scaleMode == ImageScaleMode::fill)
+			to += Um::FrameFill;
 		to += ", ";
 		to += keepRatio ? Um::KeepRatio : Um::BreakRatio;
+
 		SimpleState *ss = new SimpleState(Um::ImageScaling, QString(Um::FromTo).arg(from, to), Um::IImageScaling);
 		ss->set("SCALE_MODE");
-		if (freeScale != ScaleType)
+		if (scaleMode != m_scaleMode)
 		{
-			ss->set("SCALE_TYPE", freeScale);
-			if (!freeScale)
+			ss->set("OLD_SCALE_TYPE", static_cast<int>(m_scaleMode));
+			ss->set("NEW_SCALE_TYPE", static_cast<int>(scaleMode));
+			if (scaleMode != ImageScaleMode::free)
 			{
 				//if switching from free scaling to frame size
 				//in undo must be offset and scale saved
@@ -4251,13 +4271,13 @@ void PageItem::setImageScalingMode(bool freeScale, bool keepRatio)
 			ss->set("ASPECT_RATIO", keepRatio);
 		undoManager->action(this, ss);
 	}
-	if (!freeScale)
+	if (scaleMode != ImageScaleMode::free)
 	{
 		m_imageXOffset = 0.0;
 		m_imageYOffset = 0.0;
 		m_imageRotation = 0;
 	}
-	ScaleType = freeScale;
+	m_scaleMode = scaleMode;
 	AspectRatio = keepRatio;
 	adjustPictScale();
 	update();
@@ -7099,16 +7119,16 @@ void PageItem::restoreTextFlowing(SimpleState *state, bool isUndo)
 
 void PageItem::restoreImageScaleMode(SimpleState *state, bool isUndo)
 {
-	bool type=ScaleType;
-	if (state->contains("SCALE_TYPE"))
+	auto scaleMode = m_scaleMode;
+	if (state->contains("SCALE_MODE"))
 	{
 		if (isUndo)
-			type = !state->getBool("SCALE_TYPE");
+			scaleMode = static_cast<ImageScaleMode>(state->getInt("OLD_SCALE_TYPE"));
 		else
-			type = state->getBool("SCALE_TYPE");
+			scaleMode = static_cast<ImageScaleMode>(state->getInt("NEW_SCALE_TYPE"));
 		//if restoring free scaling
 		//old offset and scale ratio must be restored
-		if (type)
+		if (scaleMode == ImageScaleMode::free)
 		{
 			double oscx = state->getDouble("OLD_IMAGEXSCALE");
 			double oscy = state->getDouble("OLD_IMAGEYSCALE");
@@ -7121,7 +7141,7 @@ void PageItem::restoreImageScaleMode(SimpleState *state, bool isUndo)
 			m_Doc->itemSelection_SetImageOffset(ox, oy, &tempSelection);
 			m_Doc->itemSelection_SetImageRotation(orot, &tempSelection);
 		}
-		else
+		else if (m_scaleMode == ImageScaleMode::free)
 		{
 			state->set("OLD_IMAGEXOFFSET", m_imageXOffset);
 			state->set("OLD_IMAGEYOFFSET", m_imageYOffset);
@@ -7140,7 +7160,7 @@ void PageItem::restoreImageScaleMode(SimpleState *state, bool isUndo)
 			ratio = state->getBool("ASPECT_RATIO");
 	}
 
-	setImageScalingMode(type, ratio);
+	setImageScalingMode(scaleMode, ratio);
 }
 
 void PageItem::restoreImageScaleChange(SimpleState *state, bool isUndo)
@@ -7185,7 +7205,7 @@ void PageItem::restoreClearImage(UndoState *state, bool isUndo)
 		effectsInUse = is->getItem();
 		setImageFlippedH(is->getBool("CI_FLIPPH"));
 		setImageFlippedV(is->getBool("CI_FLIPPV"));
-		setImageScalingMode(is->getBool("CI_SCALING"),is->getBool("CI_ASPECT"));
+		setImageScalingMode(static_cast<ImageScaleMode>(is->getInt("CI_SCALING")),is->getBool("CI_ASPECT"));
 		setImageXOffset(is->getDouble("CI_XOFF"));
 		setImageXScale(is->getDouble("CI_XSCALE"));
 		setImageYOffset(is->getDouble("CI_YOFF"));
@@ -7521,7 +7541,7 @@ void PageItem::restoreGetImage(UndoState *state, bool isUndo)
 		{
 			setImageFlippedH(is->getBool("FLIPPH"));
 			setImageFlippedV(is->getBool("FLIPPV"));
-			setImageScalingMode(is->getBool("SCALING"), is->getBool("ASPECT"));
+			setImageScalingMode(static_cast<ImageScaleMode>(is->getInt("SCALING")), is->getBool("ASPECT"));
 		}
 	}
 	else
@@ -7533,7 +7553,7 @@ void PageItem::restoreGetImage(UndoState *state, bool isUndo)
 			effectsInUse = is->getItem();
 			setImageFlippedH(is->getBool("FLIPPH"));
 			setImageFlippedV(is->getBool("FLIPPV"));
-			setImageScalingMode(is->getBool("SCALING"), is->getBool("ASPECT"));
+			setImageScalingMode(static_cast<ImageScaleMode>(is->getInt("SCALING")), is->getBool("ASPECT"));
 			setImageXOffset(is->getDouble("XOFF"));
 			setImageXScale(is->getDouble("XSCALE"));
 			setImageYOffset(is->getDouble("YOFF"));
@@ -9349,7 +9369,7 @@ bool PageItem::loadImage(const QString& filename, const bool reload, const int g
 		is->set("NEW_IMAGE_PATH", filename);
 		is->set("FLIPPH",imageFlippedH());
 		is->set("FLIPPV",imageFlippedV());
-		is->set("SCALING",ScaleType);
+		is->set("SCALING",static_cast<int>(m_scaleMode));
 		is->set("ASPECT",AspectRatio);
 		is->set("XOFF",imageXOffset());
 		is->set("XSCALE",imageXScale());
@@ -9733,50 +9753,29 @@ void PageItem::adjustPictScale()
 {
 	if (itemType() != PageItem::ImageFrame)
 		return;
-	if (ScaleType)
+	if (m_scaleMode == ImageScaleMode::free)
 		return;
 	if (OrigW == 0 || OrigH == 0)
 		return;
 	double xs = m_width / static_cast<double>(OrigW);
 	double ys = m_height / static_cast<double>(OrigH);
-	double imgXOffs = m_imageXOffset;
-	double imgYOffs = m_imageYOffset; 
-	double imageRot = fmod(m_imageRotation, 360);
-	if (imageRot != 0.0)
-	{
-		QRectF br = QRectF(0, 0, OrigW, OrigH);
-		QTransform m;
-		m.rotate(m_imageRotation);
-		br = m.mapRect(br);
-		xs = m_width / br.width();
-		ys = m_height / br.height();
-		QLineF wL = QLineF(0, 0, OrigW, 0);
-		wL.setAngle(-m_imageRotation);
-		QLineF hL = QLineF(0, 0, 0, OrigH);
-		hL.setAngle(-m_imageRotation-90);
-		QTransform mm;
-		mm.scale(xs, ys);
-		hL = mm.map(hL);
-		wL = mm.map(wL);
-		xs = wL.length() / static_cast<double>(OrigW);
-		ys = hL.length() / static_cast<double>(OrigH);
-		m_imageXOffset = -br.x();
-		m_imageYOffset = -br.y();
-	}
-	if (AspectRatio)
+	if (m_scaleMode == ImageScaleMode::fit)
 	{
-		m_imageXScale = qMin(xs, ys);
-		m_imageYScale = qMin(xs, ys);
-	}
-	else
-	{
-		m_imageXScale = xs;
-		m_imageYScale = ys;
+		if (AspectRatio)
+		{
+			m_imageXScale = qMin(xs, ys);
+			m_imageYScale = qMin(xs, ys);
+		}
+		else
+		{
+			m_imageXScale = xs;
+			m_imageYScale = ys;
+		}
 	}
-	if (m_Doc && m_Doc->isLoading())
+	else if (m_scaleMode == ImageScaleMode::fill)
 	{
-		m_imageXOffset = imgXOffs;
-		m_imageYOffset = imgYOffs;
+		m_imageXScale = qMax(xs, ys);
+		m_imageYScale = qMax(xs, ys);
 	}
 	if (!imageClip.empty())
 	{
@@ -10137,6 +10136,8 @@ void PageItem::updateConstants()
  * Apply the mouse movements for moving an image in the frame.
  * If the image fits the frame, constraint the movements
  * and make sure that the image does not overflow the frame.
+ * If the image fills the frame, constraint the movements
+ * and make sure that the image fills the frame.
  */
 void PageItem::moveImageInFrame(double dX, double dY)
 {
@@ -10150,18 +10151,44 @@ void PageItem::moveImageInFrame(double dX, double dY)
 	if (imageFlippedV())
 		dY = -dY;
 
-	if (!ScaleType)
+	auto overflowX = OrigW - m_width / m_imageXScale;
+	auto overflowY = OrigH - m_height / m_imageYScale;
+
+	if (m_scaleMode == PageItem::ImageScaleMode::fit)
 	{
 		if (!AspectRatio)
 			return;
 		if (isImageFittingHorizontal())
 			dX = 0;
+		else
+		{
+			dX = qMax(dX, -m_imageXOffset);
+			dX = qMin(dX, - (overflowX + m_imageXOffset));
+		}
 		if (isImageFittingVertical())
 			dY = 0;
-		dX = qMax(dX, -m_imageXOffset);
-		dY = qMax(dY, -m_imageYOffset);
-		dX = qMin(dX, m_width / m_imageXScale - OrigW - m_imageXOffset);
-		dY = qMin(dY, m_height / m_imageYScale - OrigH - m_imageYOffset);
+		else
+		{
+			dY = qMax(dY, -m_imageYOffset);
+			dY = qMin(dY, - (overflowY + m_imageYOffset));
+		}
+	}
+	else if (m_scaleMode == PageItem::ImageScaleMode::fill)
+	{
+		if (isImageFittingHorizontal())
+			dY = 0;
+		else
+		{
+			dY = qMin(dY, -m_imageYOffset);
+			dY = qMax(dY, -(overflowY + m_imageYOffset));
+		}
+		if (isImageFittingVertical())
+			dX = 0;
+		else
+		{
+			dX = qMin(dX, -m_imageXOffset);
+			dX = qMax(dX, - (overflowX + m_imageXOffset));
+		}
 	}
 
 	moveImageXYOffsetBy(dX, dY);
diff --git a/scribus/pageitem.h b/scribus/pageitem.h
index 3351bc77a..9fc353a5b 100644
--- a/scribus/pageitem.h
+++ b/scribus/pageitem.h
@@ -216,6 +216,12 @@ public:	// Start enumerator definitions
 		Round		= 2,
 		Other		= 3
 	};
+
+	enum class ImageScaleMode {
+		free,
+		fit,
+		fill
+	};
 		//End enumerator definitions
 
 	// This property may not hang around for too long, but should be useful
@@ -724,8 +730,12 @@ public: // Start public functions
 	bool keepAspectRatio() const { return AspectRatio; }
 	void setKeepAspectRatio(bool val) { AspectRatio = val; }
 	//
-	bool fitImageToFrame() const { return !ScaleType; }
-	void setFitImageToFrame(bool val) { ScaleType = !val; }
+	void setImageScaleFree() { m_scaleMode = ImageScaleMode::free; }
+	void setImageScaleFit() { m_scaleMode = ImageScaleMode::fit; }
+	void setImageScaleFill() { m_scaleMode = ImageScaleMode::fill; }
+	bool isImageScaleFree() { return m_scaleMode == ImageScaleMode::free; }
+	bool isImageScaleFit() { return m_scaleMode == ImageScaleMode::fit; }
+	bool isImageScaleFill() { return m_scaleMode == ImageScaleMode::fill; }
 	bool isImageInline() const { return isInlineImage; }
 	void setImageInline(bool val) { isInlineImage = val; }
 	void setInlineExt(const QString& val) { inlineExt = val; }
@@ -1028,10 +1038,10 @@ public: // Start public functions
 
 	/**
 	 * @brief Set the image scaling mode.
-	 * @param freeScale is the scaling free (not forced to frame size)
+	 * @param scaleMode free, fit, or fill
 	 * @param keepRatio should the image's aspect ratio be respected
 	 */
-	void setImageScalingMode(bool freeScale, bool keepRatio);
+	void setImageScalingMode(ImageScaleMode scaleMode, bool keepRatio);
 
 	/** @brief Lock or unlock this pageitem. */
 	void toggleLock();
@@ -1346,7 +1356,7 @@ public:	// Start public variables
 	double OldH2;
 	bool Sizing;
 	int  m_layerID;
-	bool ScaleType;
+	ImageScaleMode m_scaleMode{ImageScaleMode::free};
 	bool AspectRatio;
 	QVector<double> DashValues;
 	double DashOffset;
diff --git a/scribus/pageitem_imageframe.cpp b/scribus/pageitem_imageframe.cpp
index 19fe5b913..978165626 100644
--- a/scribus/pageitem_imageframe.cpp
+++ b/scribus/pageitem_imageframe.cpp
@@ -220,7 +220,7 @@ void PageItem_ImageFrame::clearContents()
 		is->set("CI_PFILE", Pfile);
 		is->set("CI_FLIPPH",imageFlippedH());
 		is->set("CI_FLIPPV",imageFlippedV());
-		is->set("CI_SCALING",ScaleType);
+		is->set("CI_SCALING",static_cast<int>(m_scaleMode));
 		is->set("CI_ASPECT",AspectRatio);
 		is->set("CI_XOFF",imageXOffset());
 		is->set("CI_XSCALE",imageXScale());
@@ -245,7 +245,7 @@ void PageItem_ImageFrame::clearContents()
 	setImageFlippedH(false);
 	setImageFlippedV(false);
 	EmProfile = "";
-	ScaleType = m_Doc->prefsData().itemToolPrefs.imageScaleType;;
+	m_scaleMode = m_Doc->prefsData().itemToolPrefs.imageScaleType;
 	AspectRatio = m_Doc->prefsData().itemToolPrefs.imageAspectRatio;
 	setFillTransparency(0.0);
 	setLineTransparency(0.0);
@@ -330,13 +330,13 @@ void PageItem_ImageFrame::handleModeEditKey(QKeyEvent *k, bool& keyRepeat)
 		UndoTransaction transaction;
 		if (UndoManager::undoEnabled())
 		{
-			if ((fitImageToFrame() || !controlDown) && (dX != 0.0 || dY != 0.0))
+			if ((isImageScaleFit() || !controlDown) && (dX != 0.0 || dY != 0.0))
 				transaction = undoManager->beginTransaction(getUName(), getUPixmap(), Um::ImageScale, "", Um::IMove);
 		}
 		if (dX != 0.0)
 		{
 			double newXScale = dX / 100.0 * m_imageXScale;
-			setImageScalingMode(true, AspectRatio);
+			setImageScalingMode(ImageScaleMode::free, AspectRatio);
 			setImageXScale(newXScale);
 			if (!controlDown)
 			{
@@ -347,7 +347,7 @@ void PageItem_ImageFrame::handleModeEditKey(QKeyEvent *k, bool& keyRepeat)
 		else if (dY != 0.0)
 		{
 			double newYScale = dY / 100.0 * m_imageYScale;
-			setImageScalingMode(true, AspectRatio);
+			setImageScalingMode(ImageScaleMode::free, AspectRatio);
 			setImageYScale(newYScale);
 			if (!controlDown)
 			{
diff --git a/scribus/pageitem_osgframe.cpp b/scribus/pageitem_osgframe.cpp
index b2f63547e..9f6dff8b6 100644
--- a/scribus/pageitem_osgframe.cpp
+++ b/scribus/pageitem_osgframe.cpp
@@ -118,7 +118,7 @@ void PageItem_OSGFrame::setImage(QImage &image)
 		delete tempFile;
 		isTempFile = true;
 	}
-	setImageScalingMode(false, true);
+	setImageScalingMode(ImageScaleMode::fit, true);
 }
 
 void PageItem_OSGFrame::clearContents()
diff --git a/scribus/plugins/fileloader/scribus12format/scribus12format.cpp b/scribus/plugins/fileloader/scribus12format/scribus12format.cpp
index 21ea7fd1b..28bb8bc6e 100644
--- a/scribus/plugins/fileloader/scribus12format/scribus12format.cpp
+++ b/scribus/plugins/fileloader/scribus12format/scribus12format.cpp
@@ -222,7 +222,10 @@ void Scribus12Format::PasteItem(struct CopyPasteBuffer *Buffer, bool drag, bool
 			m_Doc->loadPict(currItem->Pfile, currItem);
 		currItem->setImageXYScale(Buffer->LocalScX, Buffer->LocalScY);
 		currItem->setImageVisible(Buffer->PicArt);
-		currItem->ScaleType = Buffer->ScaleType;
+		if (Buffer->ScaleType)
+			currItem->setImageScaleFree();
+		else
+			currItem->setImageScaleFit();
 		currItem->AspectRatio = Buffer->AspectRatio;
 		currItem->setLineWidth(Buffer->Pwidth);
 //		undoManager->setUndoEnabled(true);
@@ -405,7 +408,10 @@ void Scribus12Format::PasteItem(struct CopyPasteBuffer *Buffer, bool drag, bool
 			m_Doc->loadPict(currItem->Pfile, currItem);
 		currItem->setImageXYScale(Buffer->LocalScX, Buffer->LocalScY);
 		currItem->setImageVisible(Buffer->PicArt);
-		currItem->ScaleType = Buffer->ScaleType;
+		if (Buffer->ScaleType)
+			currItem->setImageScaleFree();
+		else
+			currItem->setImageScaleFit();
 		currItem->AspectRatio = Buffer->AspectRatio;
 		currItem->setLineWidth(Buffer->Pwidth);
 		PageItem_LatexFrame *latexframe = currItem->asLatexFrame();
@@ -430,7 +436,10 @@ void Scribus12Format::PasteItem(struct CopyPasteBuffer *Buffer, bool drag, bool
 			m_Doc->loadPict(currItem->Pfile, currItem);
 		currItem->setImageXYScale(Buffer->LocalScX, Buffer->LocalScY);
 		currItem->setImageVisible(Buffer->PicArt);
-		currItem->ScaleType = Buffer->ScaleType;
+		if (Buffer->ScaleType)
+			currItem->setImageScaleFree();
+		else
+			currItem->setImageScaleFit();
 		currItem->AspectRatio = Buffer->AspectRatio;
 		currItem->setLineWidth(Buffer->Pwidth);
 //		undoManager->setUndoEnabled(true);
diff --git a/scribus/plugins/fileloader/scribus134format/scribus134format.cpp b/scribus/plugins/fileloader/scribus134format/scribus134format.cpp
index a8634f3d8..804892f69 100644
--- a/scribus/plugins/fileloader/scribus134format/scribus134format.cpp
+++ b/scribus/plugins/fileloader/scribus134format/scribus134format.cpp
@@ -14,6 +14,7 @@ for which a new license (GPL+exception) is in place.
 #include "langmgr.h"
 #include "ui/missing.h"
 #include "hyphenator.h"
+#include "pageitem.h"
 #include "pageitem_latexframe.h"
 #include "pageitem_table.h"
 #include "prefsmanager.h"
@@ -1026,7 +1027,7 @@ void Scribus134Format::readToolSettings(ScribusDoc* doc, ScXmlStreamAttributes&
 	doc->itemToolPrefs().lineEndArrow   = attrs.valueAsInt("EndArrow", 0);
 	doc->itemToolPrefs().imageScaleX      = attrs.valueAsDouble("PICTSCX", 1.0);
 	doc->itemToolPrefs().imageScaleY      = attrs.valueAsDouble("PICTSCY", 1.0);
-	doc->itemToolPrefs().imageScaleType   = attrs.valueAsBool("PSCALE", true);
+	doc->itemToolPrefs().imageScaleType   = static_cast<PageItem::ImageScaleMode>(attrs.valueAsInt("PSCALE", 0));
 	doc->itemToolPrefs().imageAspectRatio = attrs.valueAsBool("PASPECT", false);
 	doc->itemToolPrefs().imageLowResType  = attrs.valueAsInt("HalfRes", 1);
 	doc->itemToolPrefs().imageUseEmbeddedPath = attrs.valueAsBool("EmbeddedPath", false);
@@ -2555,7 +2556,7 @@ PageItem* Scribus134Format::pasteItem(ScribusDoc *doc, ScXmlStreamAttributes& at
 		if (pagenr > -2) 
 			currItem->OwnPage = pagenr;
 		UndoManager::instance()->setUndoEnabled(false);
-		currItem->ScaleType   = attrs.valueAsInt("SCALETYPE", 1);
+		currItem->m_scaleMode = static_cast<PageItem::ImageScaleMode>(attrs.valueAsInt("SCALETYPE", 0));
 		currItem->AspectRatio = attrs.valueAsInt("RATIO", 0);
 		currItem->setImageXYScale(scx, scy);
 		currItem->setImageXYOffset(attrs.valueAsDouble("LOCALX"), attrs.valueAsDouble("LOCALY"));
@@ -2851,7 +2852,7 @@ PageItem* Scribus134Format::pasteItem(ScribusDoc *doc, ScXmlStreamAttributes& at
 		UndoManager::instance()->setUndoEnabled(false);
 		if (currItem->isAnnotation() && currItem->annotation().UseIcons())
 		{
-			currItem->ScaleType   = attrs.valueAsInt("SCALETYPE", 1);
+			currItem->m_scaleMode = static_cast<PageItem::ImageScaleMode>(attrs.valueAsInt("SCALETYPE", 0));
 			currItem->AspectRatio = attrs.valueAsInt("RATIO", 0);
 			currItem->setImageXYScale(scx, scy);
 			currItem->setImageXYOffset(attrs.valueAsDouble("LOCALX"), attrs.valueAsDouble("LOCALY"));
diff --git a/scribus/plugins/fileloader/scribus13format/scribus13format.cpp b/scribus/plugins/fileloader/scribus13format/scribus13format.cpp
index 952b3992f..4fdd46eb2 100644
--- a/scribus/plugins/fileloader/scribus13format/scribus13format.cpp
+++ b/scribus/plugins/fileloader/scribus13format/scribus13format.cpp
@@ -11,6 +11,7 @@ for which a new license (GPL+exception) is in place.
 #include "commonstrings.h"
 #include "langmgr.h"
 #include "ui/missing.h"
+#include "pageitem.h"
 #include "pageitem_group.h"
 #include "prefsmanager.h"
 #include "qtiocompressor.h"
@@ -391,7 +392,7 @@ bool Scribus13Format::loadFile(const QString & fileName, const FileFormat & /* f
 		m_Doc->itemToolPrefs().lineEndArrow = dc.attribute("EndArrow", "0").toInt();
 		m_Doc->itemToolPrefs().imageScaleX = ScCLocale::toDoubleC(dc.attribute("PICTSCX"), 1.0);
 		m_Doc->itemToolPrefs().imageScaleY = ScCLocale::toDoubleC(dc.attribute("PICTSCY"), 1.0);
-		m_Doc->itemToolPrefs().imageScaleType = static_cast<bool>(dc.attribute("PSCALE", "1").toInt());
+		m_Doc->itemToolPrefs().imageScaleType = static_cast<PageItem::ImageScaleMode>(dc.attribute("PSCALE", "0").toInt());
 		m_Doc->itemToolPrefs().imageAspectRatio = static_cast<bool>(dc.attribute("PASPECT", "0").toInt());
 		m_Doc->itemToolPrefs().imageLowResType = dc.attribute("HalfRes", "1").toInt();
 		m_Doc->itemToolPrefs().imageUseEmbeddedPath = static_cast<bool>(dc.attribute("EmbeddedPath", "0").toInt());
@@ -1521,7 +1522,7 @@ PageItem* Scribus13Format::PasteItem(QDomElement *obj, ScribusDoc *doc, const QS
 		if (pagenr > -2) 
 			currItem->setOwnerPage(pagenr);
 		UndoManager::instance()->setUndoEnabled(false);
-		currItem->ScaleType = obj->attribute("SCALETYPE", "1").toInt();
+		currItem->m_scaleMode = static_cast<PageItem::ImageScaleMode>(obj->attribute("SCALETYPE", "0").toInt());
 		currItem->AspectRatio = obj->attribute("RATIO", "0").toInt();
 		currItem->setImageXYScale(scx, scy);
 		currItem->setImageXYOffset(offsX, offsY);
@@ -1814,7 +1815,7 @@ PageItem* Scribus13Format::PasteItem(QDomElement *obj, ScribusDoc *doc, const QS
 		UndoManager::instance()->setUndoEnabled(false);
 		if (currItem->isAnnotation() && currItem->annotation().UseIcons())
 		{
-			currItem->ScaleType = obj->attribute("SCALETYPE", "1").toInt();
+			currItem->m_scaleMode = static_cast<PageItem::ImageScaleMode>(obj->attribute("SCALETYPE", "0").toInt());
 			currItem->AspectRatio = obj->attribute("RATIO", "0").toInt();
 			currItem->setImageXYScale(scx, scy);
 			currItem->setImageXYOffset(offsX, offsY);
diff --git a/scribus/plugins/fileloader/scribus150format/scribus150format.cpp b/scribus/plugins/fileloader/scribus150format/scribus150format.cpp
index 973403680..53ba1e913 100644
--- a/scribus/plugins/fileloader/scribus150format/scribus150format.cpp
+++ b/scribus/plugins/fileloader/scribus150format/scribus150format.cpp
@@ -15,6 +15,7 @@ for which a new license (GPL+exception) is in place.
 #include "hyphenator.h"
 #include "langmgr.h"
 #include "notesstyles.h"
+#include "pageitem.h"
 #include "pageitem_latexframe.h"
 #include "pageitem_noteframe.h"
 #include "pagesize.h"
@@ -2238,7 +2239,7 @@ void Scribus150Format::readToolSettings(ScribusDoc* doc, ScXmlStreamAttributes&
 	doc->itemToolPrefs().lineEndArrow   = attrs.valueAsInt("EndArrow", 0);
 	doc->itemToolPrefs().imageScaleX      = attrs.valueAsDouble("PICTSCX", 1.0);
 	doc->itemToolPrefs().imageScaleY      = attrs.valueAsDouble("PICTSCY", 1.0);
-	doc->itemToolPrefs().imageScaleType   = attrs.valueAsBool("PSCALE", true);
+	doc->itemToolPrefs().imageScaleType   = static_cast<PageItem::ImageScaleMode>(attrs.valueAsInt("PSCALE", 0));
 	doc->itemToolPrefs().imageAspectRatio = attrs.valueAsBool("PASPECT", false);
 	doc->itemToolPrefs().imageLowResType  = attrs.valueAsInt("HalfRes", 1);
 	doc->itemToolPrefs().imageUseEmbeddedPath = attrs.valueAsBool("EmbeddedPath", false);
@@ -4835,7 +4836,7 @@ PageItem* Scribus150Format::pasteItem(ScribusDoc *doc, ScXmlStreamAttributes& at
 		if (pagenr > -2) 
 			currItem->setOwnerPage(pagenr);
 		UndoManager::instance()->setUndoEnabled(false);
-		currItem->ScaleType   = attrs.valueAsInt("SCALETYPE", 1);
+		currItem->m_scaleMode = static_cast<PageItem::ImageScaleMode>(attrs.valueAsInt("SCALETYPE", 0));
 		currItem->AspectRatio = attrs.valueAsInt("RATIO", 0);
 		currItem->setImageXYScale(scx, scy);
 		currItem->setImageXYOffset(attrs.valueAsDouble("LOCALX"), attrs.valueAsDouble("LOCALY"));
@@ -5228,7 +5229,7 @@ PageItem* Scribus150Format::pasteItem(ScribusDoc *doc, ScXmlStreamAttributes& at
 			currItem->setImageVisible( attrs.valueAsInt("PICART"));
 /*			currItem->BBoxX = ScCLocale::toDoubleC( obj->attribute("BBOXX"));
 			currItem->BBoxH = ScCLocale::toDoubleC( obj->attribute("BBOXH")); */
-			currItem->ScaleType   = attrs.valueAsInt("SCALETYPE", 1);
+			currItem->m_scaleMode = static_cast<PageItem::ImageScaleMode>(attrs.valueAsInt("SCALETYPE", 0));
 			currItem->AspectRatio = attrs.valueAsInt("RATIO", 0);
 		}
 		UndoManager::instance()->setUndoEnabled(true);
diff --git a/scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp b/scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp
index 9dc03aeab..fab543678 100644
--- a/scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp
+++ b/scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp
@@ -2608,7 +2608,7 @@ void Scribus150Format::SetItemProps(ScXmlStreamWriter& docu, PageItem* item, con
 		docu.writeAttribute("LOCALY",item->imageYOffset());
 		docu.writeAttribute("LOCALROT" ,item->imageRotation());
 		docu.writeAttribute("PICART", item->imageVisible() ? 1 : 0);
-		docu.writeAttribute("SCALETYPE", item->ScaleType ? 1 : 0);
+		docu.writeAttribute("SCALETYPE", static_cast<int>(item->m_scaleMode));
 		docu.writeAttribute("RATIO", item->AspectRatio ? 1 : 0);
 	}
 	if (item->asTextFrame() || item->asPathText())
diff --git a/scribus/plugins/import/cgm/importcgm.cpp b/scribus/plugins/import/cgm/importcgm.cpp
index 739c16cdb..71237bb98 100644
--- a/scribus/plugins/import/cgm/importcgm.cpp
+++ b/scribus/plugins/import/cgm/importcgm.cpp
@@ -1578,7 +1578,7 @@ void CgmPlug::decodeClass4(QDataStream &ts, quint16 elemID, quint16 paramLen)
 		delete tempFile;
 		ite->setImageFlippedH(flipX);
 		ite->setImageFlippedV(flipY);
-		ite->setImageScalingMode(false, false);
+		ite->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 		ite->adjustPictScale();
 		colorPrecision = t_colorPrecision;
 		colorIndexPrecision = t_colorIndexPrecision;
@@ -2409,7 +2409,7 @@ void CgmPlug::decodeClass5(QDataStream &ts, quint16 elemID, quint16 paramLen)
 				ite->isTempFile = true;
 				tmpImg.save(fileName, "PNG");
 				m_Doc->loadPict(fileName, ite);
-				ite->setImageScalingMode(false, true);
+				ite->setImageScalingMode(PageItem::ImageScaleMode::fit, true);
 				ScPattern pat = ScPattern();
 				pat.setDoc(m_Doc);
 				pat.pattern = tmpImg;
diff --git a/scribus/plugins/import/drw/importdrw.cpp b/scribus/plugins/import/drw/importdrw.cpp
index 6437db27b..b736fbdff 100644
--- a/scribus/plugins/import/drw/importdrw.cpp
+++ b/scribus/plugins/import/drw/importdrw.cpp
@@ -28,6 +28,7 @@ for which a new license (GPL+exception) is in place.
 
 #include "commonstrings.h"
 #include "loadsaveplugin.h"
+#include "pageitem.h"
 #include "pageitem_imageframe.h"
 #include "pagesize.h"
 #include "prefscontext.h"
@@ -907,7 +908,7 @@ void DrwPlug::decodeCmd(quint8 cmd, int pos)
 						tmpImage.save(fileName, "PNG");
 						m_Doc->loadPict(fileName, currentItem);
 						delete tempFile;
-						currentItem->setImageScalingMode(false, false);
+						currentItem->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 					}
 					imageValid = false;
 					tmpImage = QImage();
diff --git a/scribus/plugins/import/emf/importemf.cpp b/scribus/plugins/import/emf/importemf.cpp
index a88425cb7..c4c428042 100644
--- a/scribus/plugins/import/emf/importemf.cpp
+++ b/scribus/plugins/import/emf/importemf.cpp
@@ -31,6 +31,7 @@ for which a new license (GPL+exception) is in place.
 #include "fileloader.h"
 #include "ui/missing.h"
 #include "ui/multiprogressdialog.h"
+#include "pageitem.h"
 #include "pageitem_imageframe.h"
 #include "pagesize.h"
 #include "prefscontext.h"
@@ -2959,7 +2960,7 @@ void EmfPlug::handleImage(qint32 dstX, qint32 dstY, qint32 dstW, qint32 dstH, co
 			ite->isInlineImage = true;
 			ite->isTempFile = true;
 			ite->AspectRatio = false;
-			ite->ScaleType   = false;
+			ite->setImageScaleFit();
 			if (currentDC.clipValid)
 			{
 				FPointArray cp = currentDC.clipPath.copy();
@@ -5720,7 +5721,7 @@ void EmfPlug::handleEMFPDrawImageData(QPointF p1, QPointF p2, QPointF p3, quint8
 						m_Effects.clear();
 					}
 					m_Doc->loadPict(fileName, ite);
-					ite->setImageScalingMode(false, false);
+					ite->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 					ite->updateClip();
 					if (currentDC.clipValid)
 					{
diff --git a/scribus/plugins/import/idml/importidml.cpp b/scribus/plugins/import/idml/importidml.cpp
index a00e724a3..3630c030f 100644
--- a/scribus/plugins/import/idml/importidml.cpp
+++ b/scribus/plugins/import/idml/importidml.cpp
@@ -2602,12 +2602,12 @@ QList<PageItem*> IdmlPlug::parseItemXML(const QDomElement& itElem, const QTransf
 							item->isTempFile = true;
 							item->AspectRatio = true;
 							if (imageFit == "None")
-								item->ScaleType   = true;
+								item->setImageScaleFree();
 							else if (imageFit == "ContentToFrame")
-								item->ScaleType   = false;
+								item->setImageScaleFit();
 							else if (imageFit == "Proportionally")
 							{
-								item->ScaleType   = false;
+								item->setImageScaleFit();
 								item->AspectRatio = false;
 							}
 							m_Doc->loadPict(fileName, item);
@@ -2637,12 +2637,12 @@ QList<PageItem*> IdmlPlug::parseItemXML(const QDomElement& itElem, const QTransf
 					}
 					item->AspectRatio = true;
 					if (imageFit == "None")
-						item->ScaleType   = true;
+						item->setImageScaleFree();
 					else if (imageFit == "ContentToFrame")
-						item->ScaleType   = false;
+						item->setImageScaleFit();
 					else if (imageFit == "Proportionally")
 					{
-						item->ScaleType   = false;
+						item->setImageScaleFit();
 						item->AspectRatio = false;
 					}
 					m_Doc->loadPict(QUrl::fromPercentEncoding(fileName), item);
diff --git a/scribus/plugins/import/odg/importodg.cpp b/scribus/plugins/import/odg/importodg.cpp
index 2f63eb028..31617addb 100644
--- a/scribus/plugins/import/odg/importodg.cpp
+++ b/scribus/plugins/import/odg/importodg.cpp
@@ -1566,7 +1566,7 @@ PageItem* OdgPlug::parseFrame(QDomElement &e)
 								retObj->isInlineImage = true;
 								retObj->isTempFile = true;
 								retObj->AspectRatio = false;
-								retObj->ScaleType   = false;
+								retObj->setImageScaleFit();
 								m_Doc->loadPict(fileName, retObj);
 								retObj->adjustPictScale();
 							}
@@ -1656,7 +1656,7 @@ PageItem* OdgPlug::parseFrame(QDomElement &e)
 										retObj->isInlineImage = true;
 										retObj->isTempFile = true;
 										retObj->AspectRatio = false;
-										retObj->ScaleType   = false;
+										retObj->setImageScaleFit();
 										m_Doc->loadPict(fileName, retObj);
 										retObj->adjustPictScale();
 									}
diff --git a/scribus/plugins/import/pages/importpages.cpp b/scribus/plugins/import/pages/importpages.cpp
index 272ae3908..4368f2525 100644
--- a/scribus/plugins/import/pages/importpages.cpp
+++ b/scribus/plugins/import/pages/importpages.cpp
@@ -1887,7 +1887,7 @@ PageItem* PagesPlug::parseObjReference(QDomElement &draw)
 							retObj->isInlineImage = true;
 							retObj->isTempFile = true;
 							retObj->AspectRatio = false;
-							retObj->ScaleType   = false;
+							retObj->setImageScaleFit();
 							m_Doc->loadPict(fileName, retObj);
 							retObj->adjustPictScale();
 						}
diff --git a/scribus/plugins/import/pct/importpct.cpp b/scribus/plugins/import/pct/importpct.cpp
index 8feca4fe3..0f531a2a3 100644
--- a/scribus/plugins/import/pct/importpct.cpp
+++ b/scribus/plugins/import/pct/importpct.cpp
@@ -1016,7 +1016,7 @@ void PctPlug::parsePict(QDataStream &ts)
 						ite->moveBy(offsetX, offsetY);
 						finishItem(ite);
 						m_Doc->loadPict(fileName, ite);
-						ite->setImageScalingMode(false, false);
+						ite->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 						delete tempFile;
 					}
 //					qDebug() << "End of Pict";
@@ -1852,7 +1852,7 @@ void PctPlug::handlePixmap(QDataStream &ts, quint16 opCode)
 		ite->moveBy(offsetX, offsetY);
 		finishItem(ite);
 		m_Doc->loadPict(fileName, ite);
-		ite->setImageScalingMode(false, false);
+		ite->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 		skipOpcode = false;
 	}
 	alignStreamToWord(ts, 0);
diff --git a/scribus/plugins/import/pdf/slaoutput.cpp b/scribus/plugins/import/pdf/slaoutput.cpp
index cfc438b3c..9c11a6bdf 100644
--- a/scribus/plugins/import/pdf/slaoutput.cpp
+++ b/scribus/plugins/import/pdf/slaoutput.cpp
@@ -2429,7 +2429,7 @@ void SlaOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int
 			ite->isTempFile = true;
 			res.save(fileName, "PNG");
 			m_doc->loadPict(fileName, ite);
-			ite->setImageScalingMode(false, false);
+			ite->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 			m_Elements->append(ite);
 			if (m_groupStack.count() != 0)
 			{
@@ -2445,7 +2445,7 @@ void SlaOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int
 				FPoint wh = getMaxClipF(&ite->PoLine);
 				ite->setWidthHeight(wh.x(),wh.y());
 				ite->setTextFlowMode(PageItem::TextFlowDisabled);
-				ite->ScaleType   = true;
+				ite->setImageScaleFree();
 				m_doc->adjustItemSize(ite);
 				ite->OldB2 = ite->width();
 				ite->OldH2 = ite->height();
@@ -2568,10 +2568,9 @@ void SlaOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str
 			ite->isInlineImage = true;
 			ite->isTempFile = true;
 			ite->AspectRatio = false;
-			ite->ScaleType   = false;
+			ite->setImageScaleFit();
 			res.save(fileName, "PNG");
 			m_doc->loadPict(fileName, ite);
-		//	ite->setImageScalingMode(false, false);
 			m_Elements->append(ite);
 			if (m_groupStack.count() != 0)
 			{
@@ -2587,7 +2586,7 @@ void SlaOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str
 				FPoint wh = getMaxClipF(&ite->PoLine);
 				ite->setWidthHeight(wh.x(),wh.y());
 				ite->setTextFlowMode(PageItem::TextFlowDisabled);
-				ite->ScaleType   = true;
+				ite->setImageScaleFree();
 				m_doc->adjustItemSize(ite);
 				ite->OldB2 = ite->width();
 				ite->OldH2 = ite->height();
@@ -2717,10 +2716,9 @@ void SlaOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,  i
 			ite->isInlineImage = true;
 			ite->isTempFile = true;
 			ite->AspectRatio = false;
-			ite->ScaleType   = false;
+			ite->setImageScaleFit();
 			res.save(fileName, "PNG");
 			m_doc->loadPict(fileName, ite);
-		//	ite->setImageScalingMode(false, false);
 			m_Elements->append(ite);
 			if (m_groupStack.count() != 0)
 			{
@@ -2736,7 +2734,7 @@ void SlaOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,  i
 				FPoint wh = getMaxClipF(&ite->PoLine);
 				ite->setWidthHeight(wh.x(),wh.y());
 				ite->setTextFlowMode(PageItem::TextFlowDisabled);
-				ite->ScaleType   = true;
+				ite->setImageScaleFree();
 				m_doc->adjustItemSize(ite);
 				ite->OldB2 = ite->width();
 				ite->OldH2 = ite->height();
@@ -2889,7 +2887,7 @@ void SlaOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int widt
 				ite->isInlineImage = true;
 				ite->isTempFile = true;
 				ite->AspectRatio = false;
-				ite->ScaleType   = false;
+				ite->setImageScaleFit();
 				TIFF* tif = TIFFOpen(fileName.toLocal8Bit().data(), "w");
 				if (tif)
 				{
@@ -2932,7 +2930,7 @@ void SlaOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int widt
 				ite->isInlineImage = true;
 				ite->isTempFile = true;
 				ite->AspectRatio = false;
-				ite->ScaleType   = false;
+				ite->setImageScaleFit();
 				img.save(fileName, "PNG");
 				m_doc->loadPict(fileName, ite);
 				m_Elements->append(ite);
@@ -2956,7 +2954,7 @@ void SlaOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int widt
 		FPoint wh = getMaxClipF(&ite->PoLine);
 		ite->setWidthHeight(wh.x(),wh.y());
 		ite->setTextFlowMode(PageItem::TextFlowDisabled);
-		ite->ScaleType   = true;
+		ite->setImageScaleFree();
 		m_doc->adjustItemSize(ite);
 		ite->OldB2 = ite->width();
 		ite->OldH2 = ite->height();
diff --git a/scribus/plugins/import/ps/importps.cpp b/scribus/plugins/import/ps/importps.cpp
index b90934661..35a5a6675 100644
--- a/scribus/plugins/import/ps/importps.cpp
+++ b/scribus/plugins/import/ps/importps.cpp
@@ -866,7 +866,7 @@ bool EPSPlug::Image(QString vals)
 */
 	m_Doc->loadPict(filename, ite, -1);
 	ite->setRotation(angle);
-	ite->setImageScalingMode(false, true); // fit to frame, keep ratio
+	ite->setImageScalingMode(PageItem::ImageScaleMode::fit, true); // fit to frame, keep ratio
 //	m_Doc->view()->adjustItemSize(ite);
 	Elements.append(ite);
 	return ret == 0;
diff --git a/scribus/plugins/import/svg/svgplugin.cpp b/scribus/plugins/import/svg/svgplugin.cpp
index c720d1067..100a9d7a6 100644
--- a/scribus/plugins/import/svg/svgplugin.cpp
+++ b/scribus/plugins/import/svg/svgplugin.cpp
@@ -625,7 +625,7 @@ PageItem *SVGPlug::finishNode(const QDomNode &e, PageItem* item)
 				item->setImageXYOffset(0.0, 0.0);
 				item->setImageXYScale(item->width() / (item->pixm.width() * (item->pixm.imgInfo.xres / 72.0)),
 									  item->height() / (item->pixm.height() * (item->pixm.imgInfo.yres / 72.0)));
-				item->setImageScalingMode(false, false); // fit to frame
+				item->setImageScalingMode(PageItem::ImageScaleMode::fit, false); // fit to frame
 			}
 			break;
 		}
diff --git a/scribus/plugins/import/svm/importsvm.cpp b/scribus/plugins/import/svm/importsvm.cpp
index 6b91b4b43..ca53c0265 100644
--- a/scribus/plugins/import/svm/importsvm.cpp
+++ b/scribus/plugins/import/svm/importsvm.cpp
@@ -2055,7 +2055,7 @@ void SvmPlug::handleImage(QDataStream &ds, qint64 posi, quint32 totalSize)
 			ite->isInlineImage = true;
 			ite->isTempFile = true;
 			ite->AspectRatio = false;
-			ite->ScaleType   = false;
+			ite->setImageScaleFit();
 			m_Doc->loadPict(fileName, ite);
 			ite->adjustPictScale();
 		}
@@ -2111,7 +2111,7 @@ void SvmPlug::handleImageEX(QDataStream &ds, qint64 posi, quint32 totalSize)
 			ite->isInlineImage = true;
 			ite->isTempFile = true;
 			ite->AspectRatio = false;
-			ite->ScaleType   = false;
+			ite->setImageScaleFit();
 			m_Doc->loadPict(fileName, ite);
 			ite->adjustPictScale();
 		}
@@ -4591,7 +4591,7 @@ void SvmPlug::handleEMFPDrawImageData(QPointF p1, QPointF p2, QPointF p3, quint8
 						m_Effects.clear();
 					}
 					m_Doc->loadPict(fileName, ite);
-					ite->setImageScalingMode(false, false);
+					ite->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 					ite->updateClip();
 					if (currentDC.clipPath.count() != 0)
 					{
diff --git a/scribus/plugins/import/viva/importviva.cpp b/scribus/plugins/import/viva/importviva.cpp
index fe1621933..06f9a7a11 100644
--- a/scribus/plugins/import/viva/importviva.cpp
+++ b/scribus/plugins/import/viva/importviva.cpp
@@ -1644,7 +1644,7 @@ PageItem* VivaPlug::parseObjectDetailsXML(const QDomElement& obNode, int baseTyp
 		if (baseType == 1)
 		{
 			item->AspectRatio = true;
-			item->ScaleType   = false;
+			item->setImageScaleFit();
 			bool erf = m_Doc->loadPict(imageFile, item);
 			if (!erf)
 			{
@@ -1662,7 +1662,7 @@ PageItem* VivaPlug::parseObjectDetailsXML(const QDomElement& obNode, int baseTyp
 							item->isInlineImage = true;
 							item->isTempFile = true;
 							item->AspectRatio = true;
-							item->ScaleType   = false;
+							item->setImageScaleFit();
 							m_Doc->loadPict(fileName, item);
 						}
 					}
diff --git a/scribus/plugins/import/wpg/importwpg.cpp b/scribus/plugins/import/wpg/importwpg.cpp
index 4ea64c3b4..e7ddbf088 100644
--- a/scribus/plugins/import/wpg/importwpg.cpp
+++ b/scribus/plugins/import/wpg/importwpg.cpp
@@ -406,7 +406,7 @@ void ScrPainter::drawBitmap(const libwpg::WPGBitmap& bitmap, double hres, double
 	image.setDotsPerMeterY ((int) (vres / 0.0254));
 	image.save(fileName, "PNG");
 	m_Doc->loadPict(fileName, ite);
-	ite->setImageScalingMode(false, false);
+	ite->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 	ite->moveBy(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
 	finishItem(ite);
 //	qDebug() << "drawBitmap";
diff --git a/scribus/plugins/import/xar/importxar.cpp b/scribus/plugins/import/xar/importxar.cpp
index ef9a0684a..a0013963d 100644
--- a/scribus/plugins/import/xar/importxar.cpp
+++ b/scribus/plugins/import/xar/importxar.cpp
@@ -681,7 +681,7 @@ void XarPlug::handleTags(quint32 tag, quint32 dataLen, QDataStream &ts)
 		image.save(fileName, "PNG");
 		ite->moveBy(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
 		m_Doc->LoadPict(fileName, z);
-		ite->setImageScalingMode(false, false);
+		ite->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 		ite->ClipEdited = true;
 		ite->FrameType = 3;
 		ite->setFillShade(CurrFillShade);
@@ -2816,7 +2816,7 @@ void XarPlug::handleBitmap(QDataStream &ts)
 		ite->isInlineImage = true;
 		image.save(fileName, "PNG");
 		m_Doc->loadPict(fileName, ite);
-		ite->setImageScalingMode(false, false);
+		ite->setImageScalingMode(PageItem::ImageScaleMode::fit, false);
 	}
 }
 
diff --git a/scribus/plugins/import/xps/importxps.cpp b/scribus/plugins/import/xps/importxps.cpp
index 37cb18412..46b6133ab 100644
--- a/scribus/plugins/import/xps/importxps.cpp
+++ b/scribus/plugins/import/xps/importxps.cpp
@@ -1716,7 +1716,7 @@ PageItem* XpsPlug::createItem(QDomElement &dpg, ObjState &obState)
 						retObj->isInlineImage = true;
 						retObj->isTempFile = true;
 						retObj->AspectRatio = false;
-						retObj->ScaleType   = false;
+						retObj->setImageScaleFit();
 						m_Doc->loadPict(fileName, retObj);
 						retObj->adjustPictScale();
 					}
diff --git a/scribus/plugins/scripter/api_imageitem.cpp b/scribus/plugins/scripter/api_imageitem.cpp
index 8d5be1a65..f2d753dcf 100644
--- a/scribus/plugins/scripter/api_imageitem.cpp
+++ b/scribus/plugins/scripter/api_imageitem.cpp
@@ -196,9 +196,12 @@ void ImageAPI::scaleToFrame(bool scaleToFrame, bool proportional)
 		RAISE("Specified item not an image frame.");
 		return;
 	}
-	// Set the item to scale if appropriate. ScaleType 1 is free
-	// scale, 0 is scale to frame.
-	item->ScaleType = !scaleToFrame;
+	// TODO: modify the API to give access to ImageScaleMode::fill
+	// (probably by creating scaleFree, scaleToFrame, scaleToFill
+	if (scaleToFrame)
+		item->setImageScaleFit()
+	else
+		item->setImageScaleFree()
 	// Now, if the user has chosen to set the proportional mode,
 	// set it. 1 is proportional, 0 is free aspect.
 	item->AspectRatio = proportional;
diff --git a/scribus/plugins/scriptplugin/cmdmani.cpp b/scribus/plugins/scriptplugin/cmdmani.cpp
index 03b7b3e0f..baf890ad5 100644
--- a/scribus/plugins/scriptplugin/cmdmani.cpp
+++ b/scribus/plugins/scriptplugin/cmdmani.cpp
@@ -570,9 +570,10 @@ PyObject *scribus_setscaleimagetoframe(PyObject* /* self */, PyObject* args, PyO
 		PyErr_SetString(ScribusException, QObject::tr("Specified item not an image frame.","python error").toLocal8Bit().constData());
 		return nullptr;
 	}
-	// Set the item to scale if appropriate. ScaleType 1 is free
-	// scale, 0 is scale to frame.
-	item->ScaleType = scaleToFrame == 0;
+	// Set the item to scale if appropriate. ScaleType 0 is free
+	// scale, 1 is scale to frame, 2 is fill frame.
+	scaleToFrame == 0;
+	item->setImageScaleFree();
 	// Now, if the user has chosen to set the proportional mode,
 	// set it. 1 is proportional, 0 is free aspect.
 	if (proportional != -1)
diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_pageitem.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_pageitem.cpp
index d283d257b..ad9046d70 100644
--- a/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_pageitem.cpp
+++ b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_pageitem.cpp
@@ -99,7 +99,7 @@ void export_PageItem()
 			.def_readwrite("PoShow", &PageItem::PoShow)
 			.def_readwrite("Redrawn", &PageItem::Redrawn)
 			.def_readwrite("RightLine", &PageItem::RightLine)
-			.def_readwrite("ScaleType", &PageItem::ScaleType)
+			.def_readwrite("ScaleType", &PageItem::m_scaleMode)
 			.def_readwrite("Sizing", &PageItem::Sizing)
 			.def_readwrite("Tinput", &PageItem::Tinput)
 			.def_readwrite("toPixmap", &PageItem::toPixmap)
diff --git a/scribus/prefsmanager.cpp b/scribus/prefsmanager.cpp
index a9defa046..2ab52832e 100644
--- a/scribus/prefsmanager.cpp
+++ b/scribus/prefsmanager.cpp
@@ -307,7 +307,7 @@ void PrefsManager::initDefaults()
 	appPrefs.itemToolPrefs.imageStrokeColorShade = 100;
 	appPrefs.itemToolPrefs.imageScaleX = 1;
 	appPrefs.itemToolPrefs.imageScaleY = 1;
-	appPrefs.itemToolPrefs.imageScaleType = true;
+	appPrefs.itemToolPrefs.imageScaleType = PageItem::ImageScaleMode::free;
 	appPrefs.itemToolPrefs.imageAspectRatio = true;
 	appPrefs.itemToolPrefs.imageLowResType = 1;
 	appPrefs.itemToolPrefs.imageUseEmbeddedPath = false;
@@ -2206,7 +2206,7 @@ bool PrefsManager::ReadPref(const QString& ho)
 			appPrefs.itemToolPrefs.imageStrokeColorShade = dc.attribute("ImageStrokeColorShade", "100").toInt();
 			appPrefs.itemToolPrefs.imageScaleX = ScCLocale::toDoubleC(dc.attribute("ImageScaleX"), 1.0);
 			appPrefs.itemToolPrefs.imageScaleY = ScCLocale::toDoubleC(dc.attribute("ImageScaleY"), 1.0);
-			appPrefs.itemToolPrefs.imageScaleType = static_cast<bool>(dc.attribute("ImageScaleType", "1").toInt());
+			appPrefs.itemToolPrefs.imageScaleType = static_cast<PageItem::ImageScaleMode>(dc.attribute("ImageScaleType", "0").toInt());
 			appPrefs.itemToolPrefs.imageAspectRatio = static_cast<bool>(dc.attribute("ImageAspectRatio", "1").toInt());
 			appPrefs.itemToolPrefs.imageUseEmbeddedPath = static_cast<bool>(dc.attribute("ImageUseEmbeddedPath", "0").toInt());
 			appPrefs.itemToolPrefs.imageLowResType = dc.attribute("ImageLowResType", "1").toInt();
diff --git a/scribus/prefsstructs.h b/scribus/prefsstructs.h
index fa1c5d66f..95de9935b 100644
--- a/scribus/prefsstructs.h
+++ b/scribus/prefsstructs.h
@@ -25,6 +25,7 @@ for which a new license (GPL+exception) is in place.
 #include "scfonts.h"
 #include "scpattern.h"
 #include "vgradient.h"
+#include "pageitem.h"
 
 struct CheckerPrefs
 {
@@ -277,7 +278,7 @@ struct ItemToolPrefs
 	int imageStrokeColorShade; //! Default shade of stroke color of an image grame
 	double imageScaleX; //! X scale of an image within an image frame
 	double imageScaleY; //! Y scale of an image within an image frame
-	bool imageScaleType; //! Scale type of image
+	PageItem::ImageScaleMode imageScaleType; //! Scale type of image
 	bool imageAspectRatio; //! Use stored aspect ratio for the image
 	int imageLowResType; //! Preview type for an image frame
 	bool imageUseEmbeddedPath; //! Use embedded path, eg from an EPS etc.
diff --git a/scribus/relaxng/schema/pageitems.rnc b/scribus/relaxng/schema/pageitems.rnc
index 78b30c2f7..a5b7d9147 100644
--- a/scribus/relaxng/schema/pageitems.rnc
+++ b/scribus/relaxng/schema/pageitems.rnc
@@ -109,7 +109,7 @@ grammar {
                         [impl:name="PicArt" impl:getter="imageShown" impl:setter="setImageShown"]
                         attribute PICART { xsd:boolean },
                         [impl:name="ScaleType"]
-                        attribute SCALETYPE { xsd:boolean },
+                        attribute SCALETYPE { xsd:int },
                         [impl:name="AspectRatio"]
                         attribute RATIO { xsd:boolean },
                         #[ impl:name="LocalRot" ]
diff --git a/scribus/scribusdoc.cpp b/scribus/scribusdoc.cpp
index a27577c78..8ac162ba7 100644
--- a/scribus/scribusdoc.cpp
+++ b/scribus/scribusdoc.cpp
@@ -5602,7 +5602,7 @@ void ScribusDoc::itemAddDetails(const PageItem::ItemType itemType, const PageIte
 	{
 		case PageItem::ImageFrame:
 			newItem->setImageXYScale(m_docPrefsData.itemToolPrefs.imageScaleX, m_docPrefsData.itemToolPrefs.imageScaleY);
-			newItem->ScaleType = m_docPrefsData.itemToolPrefs.imageScaleType;
+			newItem->m_scaleMode = m_docPrefsData.itemToolPrefs.imageScaleType;
 			newItem->AspectRatio = m_docPrefsData.itemToolPrefs.imageAspectRatio;
 			newItem->IProfile = m_docPrefsData.colorPrefs.DCMSset.DefaultImageRGBProfile;
 			newItem->IRender = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentImages;
@@ -15236,7 +15236,7 @@ void ScribusDoc::removeFromGroup(PageItem* item)
 	item->setXYPos(nX, nY, true);
 	item->rotateBy(-gRot);
 	item->setLineWidth(item->lineWidth() * qMax(grScXi, grScYi));
-	if (!item->ScaleType)
+	if (!item->isImageScaleFree())
 		item->adjustPictScale();
 	else
 	{
@@ -15742,7 +15742,7 @@ void ScribusDoc::itemSelection_AdjustImagetoFrameSize( Selection *customSelectio
 		if (currItem!=nullptr)
 		{
 			if (currItem->asImageFrame() && currItem->imageIsAvailable)
-				currItem->setImageScalingMode(false, true);
+				currItem->setImageScalingMode(PageItem::ImageScaleMode::fit, true);
 		}
 	}
 	regionsChanged()->update(QRectF());
diff --git a/scribus/third_party/rtf-qt/sladocumentrtfoutput.cpp b/scribus/third_party/rtf-qt/sladocumentrtfoutput.cpp
index 01e0a5885..a316490ab 100644
--- a/scribus/third_party/rtf-qt/sladocumentrtfoutput.cpp
+++ b/scribus/third_party/rtf-qt/sladocumentrtfoutput.cpp
@@ -652,7 +652,7 @@ namespace RtfReader
 				item->isInlineImage = true;
 				item->isTempFile = true;
 				item->AspectRatio = true;
-				item->ScaleType   = false;
+				item->setImageScaleFit();
 				m_Doc->loadPict(fileName, item);
 				m_Doc->Items->takeAt(z);
 				item->isEmbedded = true;
diff --git a/scribus/ui/prefs_itemtools.cpp b/scribus/ui/prefs_itemtools.cpp
index fed3f14d0..f71fe9083 100644
--- a/scribus/ui/prefs_itemtools.cpp
+++ b/scribus/ui/prefs_itemtools.cpp
@@ -15,6 +15,7 @@ for which a new license (GPL+exception) is in place.
 #include "commonstrings.h"
 #include "prefsmanager.h"
 #include "sampleitem.h"
+#include "pageitem.h"
 
 
 Prefs_ItemTools::Prefs_ItemTools(QWidget* parent, ScribusDoc* doc)
@@ -135,8 +136,9 @@ void Prefs_ItemTools::restoreDefaults(struct ApplicationPrefs *prefsData)
 	rightTextDistanceSpinBox->setValue(prefsData->itemToolPrefs.textDistances.right() * unitRatio);
 
 	//Image Tool
-	imageFreeScalingRadioButton->setChecked( prefsData->itemToolPrefs.imageScaleType );
-	imageFrameScalingRadioButton->setChecked( !prefsData->itemToolPrefs.imageScaleType );
+	imageFreeScalingRadioButton->setChecked(prefsData->itemToolPrefs.imageScaleType == PageItem::ImageScaleMode::free);
+	imageFrameScalingRadioButton->setChecked(prefsData->itemToolPrefs.imageScaleType == PageItem::ImageScaleMode::fit);
+	imageFillScalingRadioButton->setChecked(prefsData->itemToolPrefs.imageScaleType == PageItem::ImageScaleMode::fill);
 	imageHorizontalScalingSpinBox->setValue(qRound(prefsData->itemToolPrefs.imageScaleX * 100));
 	imageVerticalScalingSpinBox->setValue(qRound(prefsData->itemToolPrefs.imageScaleY * 100));
 	imageKeepAspectRatioCheckBox->setChecked(prefsData->itemToolPrefs.imageAspectRatio);
@@ -267,7 +269,12 @@ void Prefs_ItemTools::saveGuiToPrefs(struct ApplicationPrefs *prefsData) const
 	prefsData->itemToolPrefs.imageStrokeColorShade = imageFrameFillShadingSpinBox->value();
 	prefsData->itemToolPrefs.imageScaleX = static_cast<double>(imageHorizontalScalingSpinBox->value()) / 100.0;
 	prefsData->itemToolPrefs.imageScaleY = static_cast<double>(imageVerticalScalingSpinBox->value()) / 100.0;
-	prefsData->itemToolPrefs.imageScaleType = imageFreeScalingRadioButton->isChecked();
+	if (imageFreeScalingRadioButton->isChecked())
+		prefsData->itemToolPrefs.imageScaleType = PageItem::ImageScaleMode::free;
+	else if (imageFrameScalingRadioButton->isChecked())
+		prefsData->itemToolPrefs.imageScaleType = PageItem::ImageScaleMode::fit;
+	else if (imageFillScalingRadioButton->isChecked())
+		prefsData->itemToolPrefs.imageScaleType = PageItem::ImageScaleMode::fill;
 	prefsData->itemToolPrefs.imageAspectRatio = imageKeepAspectRatioCheckBox->isChecked();
 	prefsData->itemToolPrefs.imageUseEmbeddedPath = imageUseEmbeddedClippingPathCheckBox->isChecked();
 	int haRes = 0;
@@ -342,6 +349,7 @@ void Prefs_ItemTools::enableSignals(bool on)
 		connect(imageVerticalScalingSpinBox, SIGNAL(valueChanged(int)), this, SLOT(imageVerticalScalingChange()));
 		connect(imageFreeScalingRadioButton, SIGNAL(clicked(bool)), this, SLOT(imageScalingTypeChange()));
 		connect(imageFrameScalingRadioButton, SIGNAL(clicked(bool)), this, SLOT(imageScalingTypeChange()));
+		connect(imageFillScalingRadioButton, SIGNAL(clicked(bool)), this, SLOT(imageScalingTypeChange()));
 	}
 	else
 	{
diff --git a/scribus/ui/prefs_itemtoolsbase.ui b/scribus/ui/prefs_itemtoolsbase.ui
index db4d78eff..bd167ce7e 100644
--- a/scribus/ui/prefs_itemtoolsbase.ui
+++ b/scribus/ui/prefs_itemtoolsbase.ui
@@ -781,6 +781,16 @@
             </widget>
            </item>
            <item row="9" column="0">
+            <widget class="QRadioButton" name="imageFillScalingRadioButton">
+             <property name="text">
+              <string>Scale Image to Fill Frame</string>
+             </property>
+             <attribute name="buttonGroup">
+              <string notr="true">scalingButtonGroup</string>
+             </attribute>
+            </widget>
+           </item>
+           <item row="10" column="0">
             <spacer name="verticalSpacer_5">
              <property name="orientation">
               <enum>Qt::Vertical</enum>
@@ -796,7 +806,7 @@
              </property>
             </spacer>
            </item>
-           <item row="10" column="0">
+           <item row="11" column="0">
             <widget class="QLabel" name="OnScreenPreviewLabel">
              <property name="font">
               <font>
@@ -809,14 +819,14 @@
              </property>
             </widget>
            </item>
-           <item row="11" column="0" colspan="2">
+           <item row="12" column="0" colspan="2">
             <widget class="Line" name="line_4">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
             </widget>
            </item>
-           <item row="12" column="0">
+           <item row="13" column="0">
             <widget class="QRadioButton" name="onscreenResolutionFullRadioButton">
              <property name="text">
               <string>Full Resolution</string>
@@ -826,7 +836,7 @@
              </attribute>
             </widget>
            </item>
-           <item row="13" column="0">
+           <item row="14" column="0">
             <widget class="QRadioButton" name="onscreenResolutionNormalRadioButton">
              <property name="text">
               <string>Normal Resolution</string>
@@ -836,7 +846,7 @@
              </attribute>
             </widget>
            </item>
-           <item row="14" column="0">
+           <item row="15" column="0">
             <widget class="QRadioButton" name="onscreenResolutionLowRadioButton">
              <property name="text">
               <string>Low Resolution</string>
@@ -846,7 +856,7 @@
              </attribute>
             </widget>
            </item>
-           <item row="15" column="0">
+           <item row="16" column="0">
             <spacer name="verticalSpacer_6">
              <property name="orientation">
               <enum>Qt::Vertical</enum>
@@ -1584,6 +1594,7 @@
   <tabstop>imageVerticalScalingSpinBox</tabstop>
   <tabstop>imageFrameScalingRadioButton</tabstop>
   <tabstop>imageKeepAspectRatioCheckBox</tabstop>
+  <tabstop>imageFillScalingRadioButton</tabstop>
   <tabstop>onscreenResolutionFullRadioButton</tabstop>
   <tabstop>onscreenResolutionNormalRadioButton</tabstop>
   <tabstop>onscreenResolutionLowRadioButton</tabstop>
diff --git a/scribus/ui/propertiespalette_image.cpp b/scribus/ui/propertiespalette_image.cpp
index a2b7580df..1c5333dea 100644
--- a/scribus/ui/propertiespalette_image.cpp
+++ b/scribus/ui/propertiespalette_image.cpp
@@ -87,6 +87,7 @@ PropertiesPalette_Image::PropertiesPalette_Image( QWidget* parent) : QWidget(par
 	keepImageDPIRatioButton->setAutoRaise( true );
 
 	frameScale->setText( tr("&To Frame Size"));
+	fillScale->setText( tr("F&ill Frame"));
 
 	cbProportional->setEnabled( false );
 	cbProportional->setText( "P&roportional" );
@@ -106,6 +107,7 @@ PropertiesPalette_Image::PropertiesPalette_Image( QWidget* parent) : QWidget(par
 	connect(keepImageDPIRatioButton, SIGNAL(clicked())       , this, SLOT(handleImageDPIRatio()));
 	connect(freeScale          , SIGNAL(clicked())           , this, SLOT(handleScaling()));
 	connect(frameScale         , SIGNAL(clicked())           , this, SLOT(handleScaling()));
+	connect(fillScale, &QRadioButton::clicked, this, &PropertiesPalette_Image::handleScaling);
 	connect(cbProportional     , SIGNAL(stateChanged(int))   , this, SLOT(handleScaling()));
 	connect(imgEffectsButton   , SIGNAL(clicked())           , this, SLOT(handleImageEffects()));
 	connect(imgExtProperties   , SIGNAL(clicked())           , this, SLOT(handleExtImgProperties()));
@@ -477,13 +479,19 @@ void PropertiesPalette_Image::setCurrentItem(PageItem *item)
 
 		imgEffectsButton->setVisible(m_item->imageIsAvailable && m_item->isRaster);
 		imgExtProperties->setVisible(m_item->imageIsAvailable && m_item->pixm.imgInfo.valid);
-		bool setter = m_item->ScaleType;
-		freeScale->setChecked(setter);
-		frameScale->setChecked(!setter);
+
+		if (m_item->isImageScaleFree())
+			freeScale->setChecked(true);
+		else if (m_item->isImageScaleFit())
+			frameScale->setChecked(true);
+		else if (m_item->isImageScaleFill())
+			fillScale->setChecked(true);
+
 		if ((m_item->asLatexFrame()) || (m_item->asOSGFrame()))
 		{
 			freeScale->setEnabled(false);
 			frameScale->setEnabled(false);
+			fillScale->setEnabled(false);
 			cbProportional->setEnabled(false);
 			imageXScaleSpinBox->setEnabled(false);
 			imageYScaleSpinBox->setEnabled(false);
@@ -492,28 +500,32 @@ void PropertiesPalette_Image::setCurrentItem(PageItem *item)
 		}
 		else
 		{
-			imageXScaleSpinBox->setEnabled(setter);
-			imageYScaleSpinBox->setEnabled(setter);
-			imgDpiX->setEnabled(setter);
-			imgDpiY->setEnabled(setter);
-			cbProportional->setEnabled(!setter);
+
+			bool isFree = m_item->isImageScaleFree();
+			imageXScaleSpinBox->setEnabled(isFree);
+			imageYScaleSpinBox->setEnabled(isFree);
+			imgDpiX->setEnabled(isFree);
+			imgDpiY->setEnabled(isFree);
+			cbProportional->setEnabled(m_item->isImageScaleFit());
 			cbProportional->setChecked(m_item->AspectRatio);
 			freeScale->setEnabled(true);
 			frameScale->setEnabled(true);
+			fillScale->setEnabled(true);
 			//Necessary for undo action
-			keepImageWHRatioButton->setEnabled(setter);
-			keepImageDPIRatioButton->setEnabled(setter);
+			keepImageWHRatioButton->setEnabled(isFree);
+			keepImageDPIRatioButton->setEnabled(isFree);
 			keepImageWHRatioButton->setChecked(m_item->AspectRatio);
 			keepImageDPIRatioButton->setChecked(m_item->AspectRatio);
 		}
 
 		bool xEnabled{true};
 		bool yEnabled{true};
-		bool rotationEnabled{true};
-		double rangeMin{-16777215};
+		double rangeMinX{-16777215};
+		double rangeMinY{-16777215};
 		double rangeMaxX{16777215 * m_unitRatio};
 		double rangeMaxY{16777215 * m_unitRatio};
-		if (!setter)
+
+		if (m_item->isImageScaleFit())
 		{
 			if (m_item->AspectRatio)
 			{
@@ -525,18 +537,26 @@ void PropertiesPalette_Image::setCurrentItem(PageItem *item)
 				xEnabled = false;
 				yEnabled = false;
 			}
-			rotationEnabled = false;
-			rangeMin = 0.0;
+			rangeMinX = rangeMinY = 0.0;
 			rangeMaxX = (m_item->width() - m_item->OrigW * m_item->imageXScale()) * m_unitRatio;
 			rangeMaxY = (m_item->height() - m_item->OrigH * m_item->imageYScale()) * m_unitRatio;
 		}
+		else if (m_item->isImageScaleFill())
+		{
+			xEnabled = m_item->isImageFittingHorizontal();
+			yEnabled = m_item->isImageFittingVertical();
+			rangeMinX = (m_item->width() - m_item->OrigW * m_item->imageXScale()) * m_unitRatio;
+			rangeMinY = (m_item->height() - m_item->OrigH * m_item->imageYScale()) * m_unitRatio;
+			rangeMaxX = rangeMaxY = 0.0;
+		}
 		imageXOffsetSpinBox->setEnabled(xEnabled);
 		if (xEnabled)
-			imageXOffsetSpinBox->setValues(rangeMin, rangeMaxX, unitGetPrecisionFromIndex(m_unitIndex), 0);
+			imageXOffsetSpinBox->setValues(rangeMinX, rangeMaxX, unitGetPrecisionFromIndex(m_unitIndex), 0);
 		imageYOffsetSpinBox->setEnabled(yEnabled);
 		if (yEnabled)
-			imageYOffsetSpinBox->setValues(rangeMin, rangeMaxY, unitGetPrecisionFromIndex(m_unitIndex), 0);
-		imageRotation->setEnabled(rotationEnabled);
+			imageYOffsetSpinBox->setValues(rangeMinY, rangeMaxY, unitGetPrecisionFromIndex(m_unitIndex), 0);
+
+		imageRotation->setEnabled(m_item->isImageScaleFree());
 
 		imageXScaleSpinBox->blockSignals(false);
 		imageYScaleSpinBox->blockSignals(false);
@@ -620,12 +640,19 @@ void PropertiesPalette_Image::handleScaling()
 
 	// here there was code setting which widgets are enabled
 	// when the scaling type changes. but, finally,
-	// handleSelectionChanged() and setCurItem() get called
+	// handleSelectionChanged() and setCurrentItem() get called
 	// and overwrite what has been done here.
 
 	if ((m_haveDoc) && (m_haveItem))
 	{
-		m_item->setImageScalingMode(freeScale->isChecked(), cbProportional->isChecked());
+		PageItem::ImageScaleMode scaleMode;
+		if (freeScale->isChecked())
+			scaleMode = PageItem::ImageScaleMode::free;
+		else if (frameScale->isChecked())
+			scaleMode = PageItem::ImageScaleMode::fit;
+		else if (fillScale->isChecked())
+			scaleMode = PageItem::ImageScaleMode::fill;
+		m_item->setImageScalingMode(scaleMode, cbProportional->isChecked());
 		m_doc->changed();
 		emit UpdtGui(PageItem::ImageFrame);
 	}
diff --git a/scribus/ui/propertiespalette_imagebase.ui b/scribus/ui/propertiespalette_imagebase.ui
index c284516b9..37e001678 100644
--- a/scribus/ui/propertiespalette_imagebase.ui
+++ b/scribus/ui/propertiespalette_imagebase.ui
@@ -255,6 +255,16 @@
         </property>
        </widget>
       </item>
+      <item row="8" column="0">
+       <widget class="QRadioButton" name="fillScale">
+        <property name="toolTip">
+         <string>Make the image fill the frame</string>
+        </property>
+        <property name="text">
+         <string>F&amp;ill Frame</string>
+        </property>
+       </widget>
+      </item>
      </layout>
     </widget>
    </item>
@@ -420,6 +430,7 @@
   <tabstop>keepImageWHRatioButton</tabstop>
   <tabstop>keepImageDPIRatioButton</tabstop>
   <tabstop>frameScale</tabstop>
+  <tabstop>fillScale</tabstop>
   <tabstop>cbProportional</tabstop>
   <tabstop>inputProfiles</tabstop>
   <tabstop>renderIntent</tabstop>
diff --git a/scribus/undomanager.cpp b/scribus/undomanager.cpp
index f030abb2f..1ad0ff390 100644
--- a/scribus/undomanager.cpp
+++ b/scribus/undomanager.cpp
@@ -704,6 +704,7 @@ void UndoManager::languageChange()
 	UndoManager::ChangeMeshGradient = tr("Change mesh gradient");
 	UndoManager::Mode               = tr("Change Mode");
 	UndoManager::FreeScaling        = tr("Free scaling");
+	UndoManager::FrameFill          = tr("Fill frame");
 	UndoManager::KeepRatio          = tr("Keep aspect ratio");
 	UndoManager::BreakRatio         = tr("Break aspect ratio");
 	UndoManager::EditContourLine    = tr("Edit contour line");
@@ -989,6 +990,7 @@ QString UndoManager::PageNmbr           = "";
 QString UndoManager::ImageScaling       = "";
 QString UndoManager::FrameSize          = "";
 QString UndoManager::FreeScaling        = "";
+QString UndoManager::FrameFill          = "";
 QString UndoManager::KeepRatio          = "";
 QString UndoManager::BreakRatio         = "";
 QString UndoManager::EditContourLine    = "";
diff --git a/scribus/undomanager.h b/scribus/undomanager.h
index fd30ff3db..dc5a64153 100644
--- a/scribus/undomanager.h
+++ b/scribus/undomanager.h
@@ -480,6 +480,7 @@ public:
 	static QString ImageScaling;
 	static QString FrameSize;
 	static QString FreeScaling;
+	static QString FrameFill;
 	static QString KeepRatio;
 	static QString BreakRatio;
 	static QString EditContourLine;
image-fill-mode.diff (67,043 bytes)   

ale

2024-01-07 13:07

manager   ~0050843

so, is this feature just as useless as the lack of comments let me think?

... personally, i could have used it yesterday.

i don't recall the details, but from the comments i've left a few years ago, the big question is what's the best way to keep the compatibility with old documents and introducing at the same time a better interface...

utnik

2024-01-08 03:59

updater   ~0050847

i would like to have a 'fill frame' setting. i think it would often be my standard setting when placing images (as a good starting point…)
as i am not a programmer, i don't really see, how the problems with existing files can be fixed.
one more question is: should the (overlapping) image be centered or not? in most use cases (at least for me) it wouldn't really matter, as i would edit the exact placing anyway. but i can imagine some 'quick and dirty' use cases where 'centered' might be handy.

Issue History

Date Modified Username Field Change
2019-01-28 09:02 ale New Issue
2019-01-28 09:02 ale File Added: image-fill-demo.gif
2019-01-28 09:06 ale Description Updated
2019-01-28 09:11 ale Note Added: 0045867
2019-01-28 09:11 ale Description Updated
2019-01-28 09:19 ale Assigned To => ale
2019-01-28 09:19 ale Status new => assigned
2019-01-28 09:20 ale Summary fill a frame with the imaged => fill a frame with the image
2019-03-06 14:39 ale Summary fill a frame with the image => [PATCH (needs review)] fill a frame with the image
2019-03-06 14:39 ale Patch No => Yes
2019-03-06 14:39 ale Tag Attached: patch
2019-03-06 14:42 ale Note Added: 0045971
2019-03-06 14:42 ale Note Edited: 0045971
2019-03-06 14:43 ale File Added: image-fill-mode.diff
2019-03-06 16:29 ale Note Edited: 0045971
2019-03-06 16:30 ale Relationship added related to 0015448
2019-06-14 17:56 JLuc Relationship added related to 0015713
2020-06-19 08:14 JLuc Relationship added has duplicate 0016137
2020-11-10 07:10 ale Relationship added related to 0011142
2024-01-07 13:07 ale Note Added: 0050843
2024-01-08 03:59 utnik Note Added: 0050847