[Scummvm-git-logs] scummvm master -> 057fcebbdb3d96b0f82ef77484ffa8b33b12f8c1

sev- noreply at scummvm.org
Wed Feb 25 17:10:46 UTC 2026


This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
d71243e70b COMMON: Expose printable area/paper size in print manager interface
cad7c5b8c7 WIN32: Implement printable area/paper size functions in print manager
0a9e52626d GOB: Special case in the printing opcode to get the printable area size
0ec635288a COMMON, WIN32: doPrint() can now specify a move/stretch on the page
4dc4b07ecf GUI: Add "fit to page" and "center" options in print dialog
f618e9b4ea WIN32: Fix color format issue when printing high-color surfaces
057fcebbdb WIN32: Ensure the surface pitch is a multiple of 4 before printing


Commit: d71243e70b78c1ab1208c0d9e77a10b2e023f55c
    https://github.com/scummvm/scummvm/commit/d71243e70b78c1ab1208c0d9e77a10b2e023f55c
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-02-25T18:10:36+01:00

Commit Message:
COMMON: Expose printable area/paper size in print manager interface

Changed paths:
    common/printman.cpp
    common/printman.h


diff --git a/common/printman.cpp b/common/printman.cpp
index 81b0b5b6f89..172bbf9d383 100644
--- a/common/printman.cpp
+++ b/common/printman.cpp
@@ -88,4 +88,16 @@ void PrintingManager::doPrint(const Graphics::ManagedSurface &surf) {
 	warning("PrintingManager::doPrint: No printing support in this backend");
 }
 
-} // End of namespace Common
+Common::Rect PrintingManager::getPrintableArea() const {
+	return Common::Rect();
+}
+
+Common::Point PrintingManager::getPrintableAreaOffset() const {
+	return Common::Point();
+}
+
+Common::Rect PrintingManager::getPaperDimensions() const {
+	return Common::Rect();
+}
+
+} // End of namespace Common
\ No newline at end of file
diff --git a/common/printman.h b/common/printman.h
index c04431cdea6..94e6c3459c6 100644
--- a/common/printman.h
+++ b/common/printman.h
@@ -53,6 +53,10 @@ public:
 
 	void setJobName(const Common::String &jobName) { _jobName = jobName; }
 
+	virtual Common::Rect getPrintableArea() const;
+	virtual Common::Point getPrintableAreaOffset() const;
+	virtual Common::Rect getPaperDimensions() const;
+
 protected:
 	virtual void doPrint(const Graphics::ManagedSurface &surf);
 


Commit: cad7c5b8c74cd2075a6d223c29764d0f43c35555
    https://github.com/scummvm/scummvm/commit/cad7c5b8c74cd2075a6d223c29764d0f43c35555
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-02-25T18:10:36+01:00

Commit Message:
WIN32: Implement printable area/paper size functions in print manager

Changed paths:
    backends/printing/win32/win32-printman.cpp


diff --git a/backends/printing/win32/win32-printman.cpp b/backends/printing/win32/win32-printman.cpp
index d3a48bd3271..5ebc04bd02c 100644
--- a/backends/printing/win32/win32-printman.cpp
+++ b/backends/printing/win32/win32-printman.cpp
@@ -42,9 +42,14 @@ public:
 
 	Common::String getDefaultPrinterName() const override;
 
+	Common::Rect getPrintableArea() const override;
+	Common::Point getPrintableAreaOffset() const override;
+	Common::Rect getPaperDimensions() const override;
+
 private:
-	HDC createDefaultPrinterContext();
-	HDC createPrinterContext(LPTSTR devName);
+	HDC createDefaultPrinterContext() const;
+	HDC createPrinterContext(LPTSTR devName) const;
+	HDC createPrinterContext() const;
 	HBITMAP buildBitmap(HDC hdc, const Graphics::ManagedSurface &surf);
 };
 
@@ -52,12 +57,9 @@ private:
 Win32PrintingManager::~Win32PrintingManager() {}
 
 void Win32PrintingManager::doPrint(const Graphics::ManagedSurface &surf) {
-
-	HDC hdcPrint;
-	if (!_printerName.size())
-		hdcPrint = createDefaultPrinterContext();
-	else
-		hdcPrint = createPrinterContext(Win32::stringToTchar(_printerName));
+	HDC hdcPrint = createPrinterContext();
+	if (!hdcPrint)
+		return;
 
 	DOCINFOA info;
 	info.cbSize = sizeof(info);
@@ -89,7 +91,7 @@ void Win32PrintingManager::doPrint(const Graphics::ManagedSurface &surf) {
 	DeleteDC(hdcPrint);
 }
 
-HDC Win32PrintingManager::createDefaultPrinterContext() {
+HDC Win32PrintingManager::createDefaultPrinterContext() const {
 	TCHAR szPrinter[MAX_PATH];
 	BOOL success;
 	DWORD cchPrinter(ARRAYSIZE(szPrinter));
@@ -101,7 +103,7 @@ HDC Win32PrintingManager::createDefaultPrinterContext() {
 	return createPrinterContext(szPrinter);
 }
 
-HDC Win32PrintingManager::createPrinterContext(LPTSTR devName) {
+HDC Win32PrintingManager::createPrinterContext(LPTSTR devName) const {
 	HANDLE handle;
 	BOOL success;
 
@@ -125,6 +127,13 @@ HDC Win32PrintingManager::createPrinterContext(LPTSTR devName) {
 	return printerDC;
 }
 
+HDC Win32PrintingManager::createPrinterContext() const {
+	if (_printerName.empty())
+		return createDefaultPrinterContext();
+	else
+		return createPrinterContext(Win32::stringToTchar(_printerName));
+}
+
 HBITMAP Win32PrintingManager::buildBitmap(HDC hdc, const Graphics::ManagedSurface &surf) {
 	const uint colorCount = 256;
 	BITMAPINFO *bitmapInfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * (colorCount - 1));
@@ -204,6 +213,42 @@ Common::String Win32PrintingManager::getDefaultPrinterName() const {
 	return name;
 }
 
+Common::Rect Win32PrintingManager::getPrintableArea() const {
+	HDC hdcPrint = createPrinterContext();
+	if (hdcPrint) {
+		int16 width = GetDeviceCaps(hdcPrint, HORZRES);
+		int16 height = GetDeviceCaps(hdcPrint, VERTRES);
+		DeleteDC(hdcPrint);
+		return Common::Rect(width, height);
+	}
+
+	return Common::Rect();
+}
+
+Common::Point Win32PrintingManager::getPrintableAreaOffset() const {
+	HDC hdcPrint = createPrinterContext();
+	if (hdcPrint) {
+		int16 x = GetDeviceCaps(hdcPrint, PHYSICALOFFSETX);
+		int16 y = GetDeviceCaps(hdcPrint, PHYSICALOFFSETY);
+		DeleteDC(hdcPrint);
+		return Common::Point(x, y);
+	}
+
+	return Common::Point();
+}
+
+Common::Rect Win32PrintingManager::getPaperDimensions() const {
+	HDC hdcPrint = createPrinterContext();
+	if (hdcPrint) {
+		int16 width = GetDeviceCaps(hdcPrint, PHYSICALWIDTH);
+		int16 height = GetDeviceCaps(hdcPrint, PHYSICALHEIGHT);
+		DeleteDC(hdcPrint);
+		return Common::Rect(width, height);
+	}
+
+	return Common::Rect();
+}
+
 Common::PrintingManager *createWin32PrintingManager() {
 	return new Win32PrintingManager();
 }


Commit: 0a9e52626d7d15e6754b543cb5952f173911bb02
    https://github.com/scummvm/scummvm/commit/0a9e52626d7d15e6754b543cb5952f173911bb02
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-02-25T18:10:36+01:00

Commit Message:
GOB: Special case in the printing opcode to get the printable area size

(without printing anything yet)

Changed paths:
    engines/gob/inter_playtoons.cpp


diff --git a/engines/gob/inter_playtoons.cpp b/engines/gob/inter_playtoons.cpp
index ce9b76701b4..8d6775466c2 100644
--- a/engines/gob/inter_playtoons.cpp
+++ b/engines/gob/inter_playtoons.cpp
@@ -27,6 +27,7 @@
 
 #include "common/endian.h"
 #include "common/str.h"
+#include "common/printman.h"
 #include "common/translation.h"
 
 #include "gui/gui-manager.h"
@@ -354,7 +355,20 @@ void Inter_Playtoons::oPlaytoons_writeData(OpFuncParams &params) {
 
 	if (file.compareToIgnoreCase("PRINTER") == 0) {
 		// Send a sprite to the printer.
+		WRITE_VAR(1, 0);
+
 		int32 spriteIndex = -size - 1;
+		if (spriteIndex == 1000) {
+			// Just query the printable area size, without printing anything.
+			Common::Rect printArea = g_system->getPrintingManager()->getPrintableArea();
+			if (!printArea.isEmpty()) {
+				WRITE_VAR(2, printArea.width());
+				WRITE_VAR(3, printArea.height());
+			}
+
+			return;
+		}
+
 		if (spriteIndex < 0 || spriteIndex >= Draw::kSpriteCount) {
 			warning("o7_writeData: Invalid sprite index %d for printing", spriteIndex);
 			return;


Commit: 0ec635288a37636bd671a9764f31762d3774ae59
    https://github.com/scummvm/scummvm/commit/0ec635288a37636bd671a9764f31762d3774ae59
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-02-25T18:10:36+01:00

Commit Message:
COMMON, WIN32: doPrint() can now specify a move/stretch on the page

Changed paths:
    backends/printing/win32/win32-printman.cpp
    common/printman.cpp
    common/printman.h
    gui/printing-dialog.cpp


diff --git a/backends/printing/win32/win32-printman.cpp b/backends/printing/win32/win32-printman.cpp
index 5ebc04bd02c..38630edea3a 100644
--- a/backends/printing/win32/win32-printman.cpp
+++ b/backends/printing/win32/win32-printman.cpp
@@ -36,7 +36,7 @@ class Win32PrintingManager : public Common::PrintingManager {
 public:
 	virtual ~Win32PrintingManager();
 
-	void doPrint(const Graphics::ManagedSurface &surf) override;
+	void doPrint(const Graphics::ManagedSurface &surf, const Common::Rect &destRect) override;
 
 	Common::StringArray listPrinterNames() const override;
 
@@ -50,13 +50,13 @@ private:
 	HDC createDefaultPrinterContext() const;
 	HDC createPrinterContext(LPTSTR devName) const;
 	HDC createPrinterContext() const;
-	HBITMAP buildBitmap(HDC hdc, const Graphics::ManagedSurface &surf);
+	BITMAPINFO *buildBitmapInfo(const Graphics::ManagedSurface &surf);
 };
 
 
 Win32PrintingManager::~Win32PrintingManager() {}
 
-void Win32PrintingManager::doPrint(const Graphics::ManagedSurface &surf) {
+void Win32PrintingManager::doPrint(const Graphics::ManagedSurface &surf, const Common::Rect &destRect) {
 	HDC hdcPrint = createPrinterContext();
 	if (!hdcPrint)
 		return;
@@ -68,26 +68,26 @@ void Win32PrintingManager::doPrint(const Graphics::ManagedSurface &surf) {
 	info.lpszOutput = nullptr;
 	info.lpszDocName = _jobName.c_str();
 
-	HDC hdcImg = CreateCompatibleDC(hdcPrint);
-
-	HBITMAP bitmap = buildBitmap(hdcPrint, surf);
-	if (!bitmap) {
-		DeleteDC(hdcImg);
+	BITMAPINFO *bitmapInfo = buildBitmapInfo(surf);
+	if (!bitmapInfo) {
+		DeleteDC(hdcPrint);
 		return;
 	}
 
 	StartDocA(hdcPrint, &info);
 	StartPage(hdcPrint);
 
-	SelectObject(hdcImg, bitmap);
+	StretchDIBits(hdcPrint,
+				  destRect.left, destRect.top, destRect.width(), destRect.height(),
+				  0, 0, surf.w, surf.h,
+				  surf.getPixels(),
+				  bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
 
-	BitBlt(hdcPrint, 0, 0, surf.w, surf.h, hdcImg, 0, 0, SRCCOPY);
+	free(bitmapInfo);
 
 	EndPage(hdcPrint);
 	EndDoc(hdcPrint);
 
-	DeleteObject(bitmap);
-	DeleteDC(hdcImg);
 	DeleteDC(hdcPrint);
 }
 
@@ -134,7 +134,7 @@ HDC Win32PrintingManager::createPrinterContext() const {
 		return createPrinterContext(Win32::stringToTchar(_printerName));
 }
 
-HBITMAP Win32PrintingManager::buildBitmap(HDC hdc, const Graphics::ManagedSurface &surf) {
+BITMAPINFO *Win32PrintingManager::buildBitmapInfo(const Graphics::ManagedSurface &surf) {
 	const uint colorCount = 256;
 	BITMAPINFO *bitmapInfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * (colorCount - 1));
 
@@ -166,11 +166,7 @@ HBITMAP Win32PrintingManager::buildBitmap(HDC hdc, const Graphics::ManagedSurfac
 		delete[] colors;
 	}
 
-	HBITMAP bitmap = CreateDIBitmap(hdc, &(bitmapInfo->bmiHeader), CBM_INIT, surf.getPixels(), bitmapInfo, DIB_RGB_COLORS);
-
-	free(bitmapInfo);
-
-	return bitmap;
+	return bitmapInfo;
 }
 
 Common::StringArray Win32PrintingManager::listPrinterNames() const {
diff --git a/common/printman.cpp b/common/printman.cpp
index 172bbf9d383..bbf74b46348 100644
--- a/common/printman.cpp
+++ b/common/printman.cpp
@@ -84,7 +84,7 @@ void PrintingManager::saveAsImage(const Graphics::ManagedSurface &surf, const Co
 	delete saveFile;
 }
 
-void PrintingManager::doPrint(const Graphics::ManagedSurface &surf) {
+void PrintingManager::doPrint(const Graphics::ManagedSurface &surf, const Common::Rect &destRect) {
 	warning("PrintingManager::doPrint: No printing support in this backend");
 }
 
diff --git a/common/printman.h b/common/printman.h
index 94e6c3459c6..7c990f7aa02 100644
--- a/common/printman.h
+++ b/common/printman.h
@@ -58,7 +58,7 @@ public:
 	virtual Common::Rect getPaperDimensions() const;
 
 protected:
-	virtual void doPrint(const Graphics::ManagedSurface &surf);
+	virtual void doPrint(const Graphics::ManagedSurface &surf, const Common::Rect &destRect);
 
 	virtual Common::StringArray listPrinterNames() const;
 
diff --git a/gui/printing-dialog.cpp b/gui/printing-dialog.cpp
index 1fe7f99a8d6..75d7eb20ca7 100644
--- a/gui/printing-dialog.cpp
+++ b/gui/printing-dialog.cpp
@@ -104,7 +104,7 @@ void PrintingDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 		if (_saveAsImageCheckbox->getState()) {
 			printMan->saveAsImage(_surface);
 		}
-		printMan->doPrint(_surface);
+		printMan->doPrint(_surface, _surface.getBounds());
 		close();
 		break;
 	}


Commit: 4dc4b07ecf6f7a06d5c21c409a142ac32d91fbd4
    https://github.com/scummvm/scummvm/commit/4dc4b07ecf6f7a06d5c21c409a142ac32d91fbd4
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-02-25T18:10:36+01:00

Commit Message:
GUI: Add "fit to page" and "center" options in print dialog

The preview is automatically updated when setting these options,
as well as when changing the printer or the page orientation.

Changed paths:
    gui/gui-manager.h
    gui/printing-dialog.cpp
    gui/printing-dialog.h
    gui/themes/common/highres_layout.stx
    gui/themes/common/lowres_layout.stx
    gui/themes/default.inc
    gui/themes/residualvm.zip
    gui/themes/scummclassic.zip
    gui/themes/scummclassic/classic_layout.stx
    gui/themes/scummclassic/classic_layout_lowres.stx
    gui/themes/scummmodern.zip
    gui/themes/scummremastered.zip


diff --git a/gui/gui-manager.h b/gui/gui-manager.h
index c97aed18a8b..4562d007647 100644
--- a/gui/gui-manager.h
+++ b/gui/gui-manager.h
@@ -28,6 +28,7 @@
 #include "common/str.h"
 #include "common/list.h"
 #include "common/mutex.h"
+#include "common/printman.h"
 
 #include "gui/ThemeEngine.h"
 #include "gui/widget.h"
@@ -156,6 +157,7 @@ public:
 	Graphics::MacWindowManager *getWM();
 
 	// Defined in printing-dialog.cpp
+	void printImage(const Graphics::ManagedSurface &surf, bool defaultFitToPage, bool defaultCenter, PageOrientation defaultOrientation);
 	void printImage(const Graphics::ManagedSurface &surf);
 
 protected:
diff --git a/gui/printing-dialog.cpp b/gui/printing-dialog.cpp
index 75d7eb20ca7..da1b12aa127 100644
--- a/gui/printing-dialog.cpp
+++ b/gui/printing-dialog.cpp
@@ -23,6 +23,8 @@
 #include "common/translation.h"
 #include "common/system.h"
 
+#include "graphics/palette.h"
+
 #include "gui/printing-dialog.h"
 #include "gui/widget.h"
 #include "gui/widgets/popup.h"
@@ -32,54 +34,53 @@
 
 namespace GUI {
 
+void GuiManager::printImage(const Graphics::ManagedSurface &surf, bool defaultFitToPage, bool defaultCenter, PageOrientation defaultOrientation) {
+	GUI::PrintingDialog dialog(surf, defaultFitToPage, defaultCenter, defaultOrientation);
+	dialog.runModal();
+}
+
 void GuiManager::printImage(const Graphics::ManagedSurface &surf) {
-	GUI::PrintingDialog dialog(surf);
+	PageOrientation defaultOrientation = (surf.w > surf.h) ? kPageOrientationLandscape : kPageOrientationPortrait;
+	GUI::PrintingDialog dialog(surf, true, true, defaultOrientation);
 	dialog.runModal();
 }
 
-PrintingDialog::PrintingDialog(const Graphics::ManagedSurface &surface)
+PrintingDialog::PrintingDialog(const Graphics::ManagedSurface &surface, bool defaultFitToPage, bool defaultCenter, PageOrientation defaultOrientation)
 	: Dialog("PrintingDialog"), _surface(surface) {
-	_preview = new GraphicsWidget(this, "PrintingDialog.Preview");
-
-	int16 x, y, w, h;
-	if (!g_gui.xmlEval()->getWidgetData("PrintingDialog.Preview", x, y, w, h))
-		error("Failed to get widget data for PrintingDialog.Preview");
-
-	// Scale the surface to fit the preview area, if needed
-	float scaleX = (float)w / surface.w;
-	float scaleY = (float)h / surface.h;
-	float scale = MIN(scaleX, scaleY);
 
-	// Draw page and center the image on it
-	Graphics::ManagedSurface render(w, h, g_gui.theme()->getPixelFormat());
-	render.fillRect(Common::Rect(0, 0, w, h), render.format.RGBToColor(255, 255, 255));
-	render.blitFrom(_surface, _surface.getBounds(), Common::Rect((w - _surface.w * scale) / 2, (h - _surface.h * scale) / 2,
-		(w + _surface.w * scale) / 2, (h + _surface.h * scale) / 2));
-
-	_preview->setGfx(&render, false);
+	_initDone = false;
 
+	_preview = new GraphicsWidget(this, "PrintingDialog.Preview");
 	_printButton = new ButtonWidget(this, "PrintingDialog.Print", _("Print"), Common::U32String(), kCmdPrint);
-	_saveAsImageCheckbox = new CheckboxWidget(this, "PrintingDialog.SaveAsImage", _("Save as image"));
+
+	_saveAsImageCheckbox = new CheckboxWidget(this, "PrintingDialog.SaveAsImage", _("Save as image"), Common::U32String(), kCmdSaveAsImage);
+	_saveAsImageCheckbox->setState(false);
+	_fitToPageCheckbox = new CheckboxWidget(this, "PrintingDialog.FitToPage", _("Fit to page"), Common::U32String(), kCmdFitToPage);
+	_fitToPageCheckbox->setState(defaultFitToPage);
+	_centerCheckbox = new CheckboxWidget(this, "PrintingDialog.Center", _("Center"), Common::U32String(), kCmdCenter);
+	_centerCheckbox->setState(defaultCenter);
 
 	new StaticTextWidget(this, "PrintingDialog.PrintersListDesc", _("Printer:"));
 	_printersListPopUp = new PopUpWidget(this, "PrintingDialog.PrintersList", Common::U32String(), kCmdSelectPrinterName);
+
 	Common::PrintingManager *printMan = g_system->getPrintingManager();
 	Common::StringArray printerNames = printMan->listPrinterNames();
-
 	Common::String defaultPrinterName = printMan->getDefaultPrinterName();
+
+	if (printerNames.empty()) {
+		// Only the "Save as image" option will be usable, check it in advance
+		_saveAsImageCheckbox->setState(true);
+	}
+
 	uint32 defaultPrinterId = 0;
 	uint32 tag = 0;
-
 	for (auto &name : printerNames) {
 		_printersListPopUp->appendEntry(name, tag);
 		_tagToPrinterName[tag] = name;
-
 		if (name == defaultPrinterName)
 			defaultPrinterId = tag;
-
 		tag++;
 	}
-
 	_printersListPopUp->setSelectedTag(defaultPrinterId);
 	g_system->getPrintingManager()->setPrinterName(_tagToPrinterName[defaultPrinterId]);
 
@@ -88,13 +89,124 @@ PrintingDialog::PrintingDialog(const Graphics::ManagedSurface &surface)
 	_orientationPopUp = new PopUpWidget(this, "PrintingDialog.Orientation", Common::U32String(), kCmdSelectOrientation);
 	_orientationPopUp->appendEntry("Portrait", kPageOrientationPortrait);
 	_orientationPopUp->appendEntry("Landscape", kPageOrientationLandscape);
-	// Pre-select orientation
-	if (surface.w > surface.h) {
-		_orientationPopUp->setSelectedTag(kPageOrientationLandscape);
-		printMan->_orientation = kPageOrientationLandscape;
-	}
+
+	_orientationPopUp->setSelectedTag(defaultOrientation);
+	printMan->_orientation = defaultOrientation;
 
 	new ButtonWidget(this, "PrintingDialog.Cancel", _("Cancel"), Common::U32String(), kCloseCmd);
+
+	_initDone = true;
+	updatePreview();
+}
+
+Common::Rect PrintingDialog::computePlacementInContainer(int16 srcW, int16 srcH, int16 containerW, int16 containerH, bool fitToContainer, bool center) {
+	if (!srcW || !srcH)
+		return Common::Rect();
+
+	int16 destW = srcW;
+	int16 destH = srcH;
+
+	if (fitToContainer) {
+		double scaleW = (double)containerW / srcW;
+		double scaleH = (double)containerH / srcH;
+
+		if (scaleW <= scaleH) {
+			destW = containerW;
+			destH = (int16)(srcH * scaleW);
+		} else {
+			destW = (int16)(srcW * scaleH);
+			destH = containerH;
+		}
+	}
+
+	int16 destX = 0;
+	int16 destY = 0;
+
+	if (center) {
+		destX = (containerW - destW) / 2;
+		destY = (containerH - destH) / 2;
+	}
+
+	return Common::Rect(destX, destY, destX + destW, destY + destH);
+}
+
+void PrintingDialog::updatePreview() {
+	if (!_initDone)
+		return;
+
+	if (_surface.w <= 0 || _surface.h <= 0) {
+		error("Invalid surface dimensions for printing preview");
+		return;
+	}
+
+	int16 previewX = 0, previewY = 0, previewW = 0, previewH = 0;
+	if (!g_gui.xmlEval()->getWidgetData("PrintingDialog.Preview", previewX, previewY, previewW, previewH)) {
+		error("Failed to get widget data for PrintingDialog.Preview");
+		return;
+	}
+
+	if (_saveAsImageCheckbox->getState()) {
+		// In this mode, there is no "page", just fit the image exactly in the preview area
+		Common::Rect destRect = computePlacementInContainer(_surface.w, _surface.h, previewW, previewH, true, false);
+
+		Graphics::ManagedSurface fittedImage(destRect.width(), destRect.height(), g_gui.theme()->getPixelFormat());
+		fittedImage.blitFrom(_surface, _surface.getBounds(), destRect);
+
+		int16 deltaX = (previewW - destRect.width()) / 2;
+		int16 deltaY = (previewH - destRect.height()) / 2;
+
+		_preview->resize(previewX + deltaX, destRect.top + deltaY, destRect.width(), destRect.height(), false);
+		_preview->setGfx(&fittedImage, false);
+		g_gui.scheduleTopDialogRedraw();
+		return;
+	}
+
+	Common::PrintingManager *printMan = g_system->getPrintingManager();
+	Common::Rect paperDim = printMan->getPaperDimensions();
+	Common::Rect printDim = printMan->getPrintableArea();
+	Common::Point printOffset = printMan->getPrintableAreaOffset();
+
+	if (paperDim.isEmpty()) {
+		// Defaults to A4 size at 600 DPI, just to display something in the preview.
+		paperDim = Common::Rect(4960, 7016);
+		if (printMan->_orientation == kPageOrientationLandscape)
+			SWAP(paperDim.right, paperDim.bottom);
+	}
+
+	if (printDim.isEmpty()) {
+		printDim = Common::Rect(paperDim.width() - 2 * printOffset.x, paperDim.height() - 2 *  printOffset.y);
+	}
+
+	bool fitToPage = _fitToPageCheckbox->getState();
+	bool center = _centerCheckbox->getState();
+
+	// Draw a white rectangle representing the page
+	Common::Rect pageInPreviewDims = computePlacementInContainer(paperDim.width(), paperDim.height(), previewW, previewH, true, true);
+	Graphics::ManagedSurface page(pageInPreviewDims.width(), pageInPreviewDims.height(), g_gui.theme()->getPixelFormat());
+	page.fillRect(page.getBounds(), page.format.RGBToColor(255, 255, 255));
+
+	// Blit the image to the page surface, taking into account the printable area offset and the "fit to page" and "center" options.
+	double pageToPreviewScale = (double)pageInPreviewDims.width() / paperDim.width();
+
+	Common::Rect imageOnPageDims = computePlacementInContainer(_surface.w, _surface.h, printDim.width(), printDim.height(), fitToPage, center);
+	imageOnPageDims.translate(printOffset.x, printOffset.y);
+
+	Common::Rect imageInPagePreview;
+	imageInPagePreview.left   = (int16)round(imageOnPageDims.left   * pageToPreviewScale);
+	imageInPagePreview.top    = (int16)round(imageOnPageDims.top    * pageToPreviewScale);
+	imageInPagePreview.right  = (int16)round(imageOnPageDims.right  * pageToPreviewScale);
+	imageInPagePreview.bottom = (int16)round(imageOnPageDims.bottom * pageToPreviewScale);
+
+	if (!imageInPagePreview.isEmpty())
+		page.blitFrom(_surface, _surface.getBounds(), imageInPagePreview);
+
+	// Update the preview widget
+	int16 deltaX = (previewW - pageInPreviewDims.width()) / 2;
+	int16 deltaY = (previewH - pageInPreviewDims.height()) / 2;
+
+	_preview->resize(previewX + deltaX, previewY + deltaY, pageInPreviewDims.width(), pageInPreviewDims.height(), false);
+	_preview->setGfx(&page, false);
+	g_gui.scheduleTopDialogRedraw();
 }
 
 void PrintingDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
@@ -104,15 +216,32 @@ void PrintingDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 		if (_saveAsImageCheckbox->getState()) {
 			printMan->saveAsImage(_surface);
 		}
-		printMan->doPrint(_surface, _surface.getBounds());
+
+		bool fitToPage = _fitToPageCheckbox->getState();
+		bool center = _centerCheckbox->getState();
+
+		Common::Rect printArea = printMan->getPrintableArea();
+		Common::Rect destRect = computePlacementInContainer(_surface.w, _surface.h,
+		                                                    printArea.width(), printArea.height(),
+		                                                    fitToPage, center);
+
+		printMan->doPrint(_surface, destRect);
 		close();
 		break;
 	}
 	case kCmdSelectPrinterName:
 		g_system->getPrintingManager()->setPrinterName(_tagToPrinterName[data]);
+		updatePreview();
 		break;
 	case kCmdSelectOrientation:
 		g_system->getPrintingManager()->_orientation = (PageOrientation)data;
+		updatePreview();
+		break;
+
+	case kCmdSaveAsImage:
+	case kCmdFitToPage:
+	case kCmdCenter:
+		updatePreview();
 		break;
 	default:
 		Dialog::handleCommand(sender, cmd, data);
diff --git a/gui/printing-dialog.h b/gui/printing-dialog.h
index 31c956a6c84..189de916296 100644
--- a/gui/printing-dialog.h
+++ b/gui/printing-dialog.h
@@ -36,18 +36,27 @@ public:
 		kCmdPrint = 'PRNT',
 		kCmdSelectPrinterName = 'SLPN',
 		kCmdSelectOrientation = 'SLOR',
+		kCmdSaveAsImage = 'SVIM',
+		kCmdFitToPage = 'FITP',
+		kCmdCenter = 'CNTR',
 	};
 
-	PrintingDialog(const Graphics::ManagedSurface &surface);
+	PrintingDialog(const Graphics::ManagedSurface &surface, bool defaultFitToPage, bool defaultCenter, PageOrientation defaultOrientation);
 
 	void handleCommand(CommandSender *sender, uint32 cmd, uint32 data) override;
 
 private:
+	void updatePreview();
+	static Common::Rect computePlacementInContainer(int16 srcW, int16 srcH, int16 containerW, int16 containerH, bool fitToContainer, bool center);
+
 	const Graphics::ManagedSurface &_surface;
 
+	bool _initDone;
 	GraphicsWidget *_preview;
 	ButtonWidget *_printButton;
 	CheckboxWidget *_saveAsImageCheckbox;
+	CheckboxWidget *_fitToPageCheckbox;
+	CheckboxWidget *_centerCheckbox;
 	PopUpWidget *_printersListPopUp;
 
 	PopUpWidget *_orientationPopUp;
diff --git a/gui/themes/common/highres_layout.stx b/gui/themes/common/highres_layout.stx
index dc13d253991..791f74344b7 100644
--- a/gui/themes/common/highres_layout.stx
+++ b/gui/themes/common/highres_layout.stx
@@ -2935,6 +2935,14 @@
 						type = 'Checkbox'
 						width = '140'
 				/>
+				<widget name = 'FitToPage'
+						type = 'Checkbox'
+						width = '140'
+				/>
+				<widget name = 'Center'
+						type = 'Checkbox'
+						width = '140'
+				/>
 				<space/>
 				<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'>
 					<widget name = 'Cancel'
diff --git a/gui/themes/common/lowres_layout.stx b/gui/themes/common/lowres_layout.stx
index 2d2cde664b1..6472c4da695 100644
--- a/gui/themes/common/lowres_layout.stx
+++ b/gui/themes/common/lowres_layout.stx
@@ -2740,6 +2740,14 @@
 						type = 'Checkbox'
 						width = '140'
 				/>
+				<widget name = 'FitToPage'
+						type = 'Checkbox'
+						width = '140'
+				/>
+				<widget name = 'Center'
+						type = 'Checkbox'
+						width = '140'
+				/>
 				<space/>
 				<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'>
 					<widget name = 'Cancel'
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index c450485e944..3f632b8dd75 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -3868,6 +3868,14 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "type='Checkbox' "
 "width='140' "
 "/>"
+"<widget name='FitToPage' "
+"type='Checkbox' "
+"width='140' "
+"/>"
+"<widget name='Center' "
+"type='Checkbox' "
+"width='140' "
+"/>"
 "<space/>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='10'>"
 "<widget name='Cancel' "
@@ -6290,6 +6298,14 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "type='Checkbox' "
 "width='140' "
 "/>"
+"<widget name='FitToPage' "
+"type='Checkbox' "
+"width='140' "
+"/>"
+"<widget name='Center' "
+"type='Checkbox' "
+"width='140' "
+"/>"
 "<space/>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='10'>"
 "<widget name='Cancel' "
diff --git a/gui/themes/residualvm.zip b/gui/themes/residualvm.zip
index cb3fdc96bf5..82a12009fd4 100644
Binary files a/gui/themes/residualvm.zip and b/gui/themes/residualvm.zip differ
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index d0328f411ae..c1b0876fff0 100644
Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 3be4ef3a431..ae29a1ba3f4 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -2568,6 +2568,14 @@
 						type = 'Checkbox'
 						width = '140'
 				/>
+				<widget name = 'FitToPage'
+						type = 'Checkbox'
+						width = '140'
+				/>
+				<widget name = 'Center'
+						type = 'Checkbox'
+						width = '140'
+				/>
 				<space/>
 				<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'>
 					<widget name = 'Cancel'
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index f476d5637a9..af871444fbb 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -2547,6 +2547,14 @@
 						type = 'Checkbox'
 						width = '140'
 				/>
+				<widget name = 'FitToPage'
+						type = 'Checkbox'
+						width = '140'
+				/>
+				<widget name = 'Center'
+						type = 'Checkbox'
+						width = '140'
+				/>
 				<space/>
 				<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'>
 					<widget name = 'Cancel'
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index b3bffe4ff90..8c029cae7c1 100644
Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ
diff --git a/gui/themes/scummremastered.zip b/gui/themes/scummremastered.zip
index 75bfd46a1ee..d1b9cb2a9b1 100644
Binary files a/gui/themes/scummremastered.zip and b/gui/themes/scummremastered.zip differ


Commit: f618e9b4ead057280ead0633b7f65d32e2e22fdf
    https://github.com/scummvm/scummvm/commit/f618e9b4ead057280ead0633b7f65d32e2e22fdf
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-02-25T18:10:36+01:00

Commit Message:
WIN32: Fix color format issue when printing high-color surfaces

Changed paths:
    backends/printing/win32/win32-printman.cpp


diff --git a/backends/printing/win32/win32-printman.cpp b/backends/printing/win32/win32-printman.cpp
index 38630edea3a..1ab2994e886 100644
--- a/backends/printing/win32/win32-printman.cpp
+++ b/backends/printing/win32/win32-printman.cpp
@@ -146,7 +146,7 @@ BITMAPINFO *Win32PrintingManager::buildBitmapInfo(const Graphics::ManagedSurface
 	bitmapInfo->bmiHeader.biHeight = -((LONG)surf.h);
 	bitmapInfo->bmiHeader.biPlanes = 1;
 	bitmapInfo->bmiHeader.biBitCount = (surf.format.isCLUT8() ? 8 : surf.format.bpp());
-	bitmapInfo->bmiHeader.biCompression = BI_RGB;
+	bitmapInfo->bmiHeader.biCompression = (surf.format.isCLUT8() ? BI_RGB : BI_BITFIELDS);
 	bitmapInfo->bmiHeader.biSizeImage = 0;
 	bitmapInfo->bmiHeader.biClrUsed = (surf.format.isCLUT8() ? colorCount : 0);
 	bitmapInfo->bmiHeader.biClrImportant = (surf.format.isCLUT8() ? colorCount : 0);
@@ -164,6 +164,11 @@ BITMAPINFO *Win32PrintingManager::buildBitmapInfo(const Graphics::ManagedSurface
 		}
 
 		delete[] colors;
+	} else {
+		DWORD *masks = (DWORD *)bitmapInfo->bmiColors;
+		masks[0] = (DWORD)surf.format.rMax() << surf.format.rShift;
+		masks[1] = (DWORD)surf.format.gMax() << surf.format.gShift;
+		masks[2] = (DWORD)surf.format.bMax() << surf.format.bShift;
 	}
 
 	return bitmapInfo;


Commit: 057fcebbdb3d96b0f82ef77484ffa8b33b12f8c1
    https://github.com/scummvm/scummvm/commit/057fcebbdb3d96b0f82ef77484ffa8b33b12f8c1
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-02-25T18:10:36+01:00

Commit Message:
WIN32: Ensure the surface pitch is a multiple of 4 before printing

Changed paths:
    backends/printing/win32/win32-printman.cpp


diff --git a/backends/printing/win32/win32-printman.cpp b/backends/printing/win32/win32-printman.cpp
index 1ab2994e886..ae0c3fc7b7c 100644
--- a/backends/printing/win32/win32-printman.cpp
+++ b/backends/printing/win32/win32-printman.cpp
@@ -74,15 +74,30 @@ void Win32PrintingManager::doPrint(const Graphics::ManagedSurface &surf, const C
 		return;
 	}
 
+	// Ensure the pitch is a multiple of 4, as required by StretchDIBits
+	int32 pitchCeiledUp = (surf.pitch + 3) / 4 * 4;
+	byte *dibPixels = nullptr;
+	if (pitchCeiledUp != surf.pitch) {
+		dibPixels = new byte[pitchCeiledUp * surf.h]();
+		const byte *src = (const byte *)surf.getPixels();
+		byte *dst = dibPixels;
+		for (int y = 0; y < surf.h; y++) {
+			memcpy(dst, src, surf.pitch);
+			src += surf.pitch;
+			dst += pitchCeiledUp;
+		}
+	}
+
 	StartDocA(hdcPrint, &info);
 	StartPage(hdcPrint);
 
 	StretchDIBits(hdcPrint,
 				  destRect.left, destRect.top, destRect.width(), destRect.height(),
 				  0, 0, surf.w, surf.h,
-				  surf.getPixels(),
+				  dibPixels ? dibPixels : surf.getPixels(),
 				  bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
 
+	delete[] dibPixels;
 	free(bitmapInfo);
 
 	EndPage(hdcPrint);




More information about the Scummvm-git-logs mailing list