View Issue Details

IDProjectCategoryView StatusLast Update
0015560ScribusGraphics / Image Framespublic2019-06-14 17:56
Reporterale Assigned Toale  
PrioritynormalSeverityfeatureReproducibilityN/A
Status assignedResolutionopen 
Product Version 
Target Version1.5.5.svnFixed in Version 
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 
related to 0015713 closedJLuc Provide new "fixed viewport" image resize mode 

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

View 3 revisions

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)

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 View Revisions
2019-01-28 09:11 ale Note Added: 0045867
2019-01-28 09:11 ale Description Updated View Revisions
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 View Revisions
2019-03-06 14:43 ale File Added: image-fill-mode.diff
2019-03-06 16:29 ale Note Edited: 0045971 View Revisions
2019-03-06 16:30 ale Relationship added related to 0015448
2019-06-14 17:56 JLuc Relationship added related to 0015713