[Scummvm-git-logs] scummvm master -> 1b58e6dd9079680020ad76a66aad20c549262a09

bluegr noreply at scummvm.org
Sat Apr 12 12:47:22 UTC 2025


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

Summary:
77ee5a9007 IMAGE: Get palette class by reference on image decoders
1b58e6dd90 GRAPHICS: Add method to check empty for Palette


Commit: 77ee5a90072ada3e769a9efcde52125bd9a87554
    https://github.com/scummvm/scummvm/commit/77ee5a90072ada3e769a9efcde52125bd9a87554
Author: Matthew Jimenez (matthew.jimenez at outlook.com)
Date: 2025-04-12T15:47:17+03:00

Commit Message:
IMAGE: Get palette class by reference on image decoders

Changed paths:
    backends/graphics/opengl/pipelines/libretro.cpp
    engines/ags/shared/gfx/image.cpp
    engines/bagel/boflib/gfx/bitmap.cpp
    engines/bagel/boflib/gfx/palette.cpp
    engines/buried/graphics.cpp
    engines/cine/cine.cpp
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/image/hlz.cpp
    engines/cryomni3d/image/hlz.h
    engines/cryomni3d/versailles/documentation.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/menus.cpp
    engines/director/castmember/bitmap.cpp
    engines/director/images.cpp
    engines/director/images.h
    engines/director/lingo/lingo-builtins.cpp
    engines/director/picture.cpp
    engines/director/tests.cpp
    engines/dreamweb/vgagrafx.cpp
    engines/engine.cpp
    engines/freescape/doodle.cpp
    engines/freescape/doodle.h
    engines/freescape/freescape.cpp
    engines/glk/debugger.cpp
    engines/glk/picture.cpp
    engines/glk/raw_decoder.cpp
    engines/glk/raw_decoder.h
    engines/gob/inter_v7.cpp
    engines/grim/material.cpp
    engines/hopkins/graphics.cpp
    engines/kingdom/kingdom.cpp
    engines/mm/mm1/gfx/screen_decoder.h
    engines/mohawk/bitmap.cpp
    engines/mtropolis/plugin/standard.cpp
    engines/nancy/graphics.cpp
    engines/nancy/resource.cpp
    engines/parallaction/disk_br.cpp
    engines/parallaction/disk_ns.cpp
    engines/pegasus/cursor.cpp
    engines/pegasus/surface.cpp
    engines/petka/q_manager.cpp
    engines/plumbers/plumbers.cpp
    engines/plumbers/windows.cpp
    engines/prince/cursor.cpp
    engines/prince/graphics.cpp
    engines/prince/mhwanh.cpp
    engines/prince/mhwanh.h
    engines/prince/prince.cpp
    engines/prince/script.cpp
    engines/private/private.cpp
    engines/qdengine/qdcore/util/splash_screen.cpp
    engines/queen/display.cpp
    engines/saga/scene.cpp
    engines/sci/graphics/maciconbar.cpp
    engines/scumm/macgui/macgui_impl.cpp
    engines/sludge/hsi.cpp
    engines/sludge/hsi.h
    engines/sludge/imgloader.cpp
    engines/stark/ui/dialogbox.cpp
    engines/stark/visual/image.cpp
    engines/supernova/graphics.cpp
    engines/supernova/graphics.h
    engines/supernova/screen.cpp
    engines/sword25/gfx/image/imgloader.cpp
    engines/testbed/image.cpp
    engines/testbed/misc.cpp
    engines/titanic/support/image.cpp
    engines/tucker/resource.cpp
    engines/twine/movies.cpp
    engines/twine/renderer/screens.cpp
    engines/twine/slideshow.cpp
    engines/ultima/nuvie/misc/sdl_compat.cpp
    engines/ultima/ultima4/gfx/imageloader.cpp
    engines/ultima/ultima4/gfx/imageloader.h
    engines/ultima/ultima4/gfx/imageloader_fmtowns.cpp
    engines/ultima/ultima4/gfx/imageloader_u4.cpp
    engines/ultima/ultima4/gfx/imagemgr.cpp
    engines/ultima/ultima8/gumps/cru_credits_gump.cpp
    engines/ultima/ultima8/gumps/cru_demo_gump.cpp
    engines/vcruise/runtime.cpp
    engines/wintermute/base/gfx/base_image.cpp
    graphics/macgui/macwindowborder.cpp
    graphics/macgui/macwindowmanager.cpp
    image/bmp.h
    image/cel_3do.h
    image/cicn.h
    image/gif.h
    image/iff.h
    image/image_decoder.h
    image/jpeg.cpp
    image/jpeg.h
    image/neo.cpp
    image/neo.h
    image/pcx.h
    image/pict.h
    image/png.h
    image/scr.cpp
    image/scr.h
    image/tga.h
    image/xbm.cpp
    image/xbm.h


diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index 75860d1f876..fbb0bb9ab9d 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -77,14 +77,15 @@ static Graphics::Surface *loadViaImageDecoder(const Common::Path &fileName, Comm
 		return nullptr;
 	}
 
+	// Use a cast to resolve ambiguities in JPEGDecoder
+	const Graphics::Palette & palette = static_cast<Image::ImageDecoder &>(decoder).getPalette();
 	return decoder.getSurface()->convertTo(
 #ifdef SCUMM_LITTLE_ENDIAN
 										   Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24),
 #else
 										   Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0),
 #endif
-										   // Use a cast to resolve ambiguities in JPEGDecoder
-										   static_cast<Image::ImageDecoder &>(decoder).getPalette());
+										   palette.data(), palette.size());
 }
 
 struct ImageLoader {
diff --git a/engines/ags/shared/gfx/image.cpp b/engines/ags/shared/gfx/image.cpp
index 51d3e2c7882..4cd8d8a99c6 100644
--- a/engines/ags/shared/gfx/image.cpp
+++ b/engines/ags/shared/gfx/image.cpp
@@ -52,12 +52,10 @@ BITMAP *decodeImageStream(Common::SeekableReadStream &stream, color *pal) {
 		dest->blitFrom(*src);
 
 		// Copy the palette
-		const byte *palP = decoder.getPalette();
-		if (palP && pal) {
-			for (int idx = 0; idx < 256; ++idx, palP += 3) {
-				pal[idx].r = palP[0];
-				pal[idx].g = palP[1];
-				pal[idx].b = palP[2];
+		const Graphics::Palette &palP = decoder.getPalette();
+		if (pal) {
+			for (uint idx = 0; idx < palP.size(); ++idx) {
+				palP.get(idx, pal[idx].r, pal[idx].g, pal[idx].b);
 				pal[idx].filler = 0xff;
 			}
 		}
diff --git a/engines/bagel/boflib/gfx/bitmap.cpp b/engines/bagel/boflib/gfx/bitmap.cpp
index 782e17ec81f..83f8f83d3d7 100644
--- a/engines/bagel/boflib/gfx/bitmap.cpp
+++ b/engines/bagel/boflib/gfx/bitmap.cpp
@@ -180,7 +180,7 @@ ErrorCode CBofBitmap::loadBitmap(const char *pszFileName, CBofPalette *pPalette)
 		_bitmap.copyFrom(*decoder.getSurface());
 
 		// Load the bitmap palette
-		_bitmap.setPalette(decoder.getPalette(), 0, Graphics::PALETTE_COUNT);
+		_bitmap.setPalette(decoder.getPalette().data(), 0, decoder.getPalette().size());
 
 		_nDX = _bitmap.w;
 		_nDY = _bitmap.h;
diff --git a/engines/bagel/boflib/gfx/palette.cpp b/engines/bagel/boflib/gfx/palette.cpp
index d759eae72e0..c4b4e267a66 100644
--- a/engines/bagel/boflib/gfx/palette.cpp
+++ b/engines/bagel/boflib/gfx/palette.cpp
@@ -91,9 +91,9 @@ ErrorCode CBofPalette::loadPalette(const char *pszFileName, uint16 nFlags) {
 
 	if (f.open(pszFileName) && decoder.loadStream(f)) {
 		// Copy the palette
-		_palette._numColors = decoder.getPaletteColorCount();
-		const byte *src = decoder.getPalette();
-		Common::copy(src, src + _palette._numColors * 3, _palette._data);
+		const Graphics::Palette &pal = decoder.getPalette();
+		_palette._numColors = pal.size();
+		pal.grab(_palette._data, 0, pal.size());
 
 		_errCode = ERR_NONE;
 
diff --git a/engines/buried/graphics.cpp b/engines/buried/graphics.cpp
index 3fc2e60aae8..9513ed0fc1d 100644
--- a/engines/buried/graphics.cpp
+++ b/engines/buried/graphics.cpp
@@ -214,12 +214,12 @@ Graphics::Surface *GraphicsManager::getBitmap(Common::SeekableReadStream *stream
 	// Convert to the screen format, if required
 	if (decoder.getSurface()->format != g_system->getScreenFormat()) {
 		assert(_vm->isTrueColor());
-		return decoder.getSurface()->convertTo(g_system->getScreenFormat(), decoder.getPalette());
+		return decoder.getSurface()->convertTo(g_system->getScreenFormat(), decoder.getPalette().data(), decoder.getPalette().size());
 	}
 
 	// Remap the palette, if required
-	if (!_vm->isTrueColor() && memcmp(decoder.getPalette() + 3, getDefaultPalette() + 3, 256 - 6) != 0)
-		return remapPalettedFrame(decoder.getSurface(), decoder.getPalette());
+	if (!_vm->isTrueColor() && memcmp(decoder.getPalette().data() + 3, getDefaultPalette() + 3, 256 - 6) != 0)
+		return remapPalettedFrame(decoder.getSurface(), decoder.getPalette().data());
 
 	// Just copy the frame
 	Graphics::Surface *surface = new Graphics::Surface();
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp
index ab481e7e953..9b315d48ae4 100644
--- a/engines/cine/cine.cpp
+++ b/engines/cine/cine.cpp
@@ -299,9 +299,8 @@ void CineEngine::showSplashScreen() {
 	if (surface->w == 640 && surface->h == 480) {
 		initGraphics(640, 480);
 
-		const byte *palette = decoder.getPalette();
-		int paletteColorCount = decoder.getPaletteColorCount();
-		g_system->getPaletteManager()->setPalette(palette, 0, paletteColorCount);
+		const Graphics::Palette &palette = decoder.getPalette();
+		g_system->getPaletteManager()->setPalette(palette.data(), 0, palette.size());
 
 		g_system->copyRectToScreen(surface->getPixels(), 640, 0, 0, 640, 480);
 		g_system->updateScreen();
diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index 3f933fa728a..65ee66d98db 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -191,7 +191,7 @@ bool CryOmni3DEngine::displayHLZ(const Common::Path &filepath, uint32 timeout) {
 	}
 
 	if (imageDecoder->hasPalette()) {
-		setPalette(imageDecoder->getPalette(), 0, imageDecoder->getPaletteColorCount());
+		setPalette(imageDecoder->getPalette().data(), 0, imageDecoder->getPalette().size());
 	}
 
 	const Graphics::Surface *frame = imageDecoder->getSurface();
diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index 9d669593570..a65e2beb333 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -23,6 +23,7 @@
 
 #include "common/file.h"
 #include "common/system.h"
+#include "graphics/palette.h"
 #include "graphics/surface.h"
 #include "image/image_decoder.h"
 
@@ -107,8 +108,8 @@ void ZonFixedImage::load(const Common::Path &image, const char *zone) {
 }
 
 void ZonFixedImage::display() const {
-	_engine.setupPalette(_imageDecoder->getPalette(), 0,
-	                     _imageDecoder->getPaletteColorCount());
+	_engine.setupPalette(_imageDecoder->getPalette().data(), 0,
+	                     _imageDecoder->getPalette().size());
 
 	g_system->copyRectToScreen(_imageSurface->getPixels(), _imageSurface->pitch, 0, 0,
 	                           _imageSurface->w, _imageSurface->h);
diff --git a/engines/cryomni3d/image/hlz.cpp b/engines/cryomni3d/image/hlz.cpp
index 90877f70dd6..f9f1a4b2b88 100644
--- a/engines/cryomni3d/image/hlz.cpp
+++ b/engines/cryomni3d/image/hlz.cpp
@@ -32,9 +32,7 @@
 
 namespace Image {
 
-HLZFileDecoder::HLZFileDecoder() {
-	_surface = nullptr;
-	_codec = nullptr;
+HLZFileDecoder::HLZFileDecoder() : _codec(nullptr), _surface(nullptr), _palette(256) {
 }
 
 HLZFileDecoder::~HLZFileDecoder() {
@@ -50,7 +48,13 @@ void HLZFileDecoder::destroy() {
 bool HLZFileDecoder::loadStream(Common::SeekableReadStream &stream) {
 	destroy();
 
-	stream.read(_palette, sizeof(_palette));
+	for (uint16 i = 0; i < 256; i++) {
+		byte r = stream.readByte();
+		byte g = stream.readByte();
+		byte b = stream.readByte();
+		_palette.set(i, r, g, b);
+	}
+
 	uint16 width = stream.readUint16LE();
 	uint16 height = stream.readUint16LE();
 
diff --git a/engines/cryomni3d/image/hlz.h b/engines/cryomni3d/image/hlz.h
index dc6cac2424e..1e63c4f2adb 100644
--- a/engines/cryomni3d/image/hlz.h
+++ b/engines/cryomni3d/image/hlz.h
@@ -24,6 +24,7 @@
 
 #include "common/scummsys.h"
 #include "common/str.h"
+#include "graphics/palette.h"
 #include "image/image_decoder.h"
 
 namespace Common {
@@ -46,13 +47,12 @@ public:
 	void destroy() override;
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	const Graphics::Surface *getSurface() const override { return _surface; }
-	const byte *getPalette() const override { return _palette; }
-	uint16 getPaletteColorCount() const override { return 256; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 private:
 	HLZDecoder *_codec;
 	const Graphics::Surface *_surface;
-	byte _palette[256 * 3];
+	Graphics::Palette _palette;
 };
 
 } // End of namespace Image
diff --git a/engines/cryomni3d/versailles/documentation.cpp b/engines/cryomni3d/versailles/documentation.cpp
index 6197294402e..d6bca630c86 100644
--- a/engines/cryomni3d/versailles/documentation.cpp
+++ b/engines/cryomni3d/versailles/documentation.cpp
@@ -326,8 +326,8 @@ Common::String Versailles_Documentation::docAreaHandleSummary() {
 	// No box for 6
 	boxes.setupBox(7, 0, 480 - _sprites->getCursor(225).getHeight(), 640, 480);
 
-	_engine->setupPalette(imageDecoder->getPalette(), 0,
-	                      imageDecoder->getPaletteColorCount());
+	_engine->setupPalette(imageDecoder->getPalette().data(), 0,
+	                      imageDecoder->getPalette().size());
 
 	_engine->setCursor(181);
 	_engine->showMouse(true);
@@ -445,8 +445,8 @@ Common::String Versailles_Documentation::docAreaHandleTimeline() {
 	_fontManager->setCharSpacing(1);
 	_fontManager->setSurface(&docSurface);
 
-	_engine->setupPalette(imageDecoder->getPalette(), 0,
-	                      imageDecoder->getPaletteColorCount());
+	_engine->setupPalette(imageDecoder->getPalette().data(), 0,
+	                      imageDecoder->getPalette().size());
 
 	_fontManager->displayStr(78, 10, (*_messages)[73]);
 	docSurface.hLine(0, 39, 171, 241); // minus 1 because hLine draws inclusive
@@ -956,8 +956,8 @@ Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
 
 	_fontManager->setSurface(&mapSurface);
 
-	_engine->setupPalette(imageDecoder->getPalette(), 0,
-	                      imageDecoder->getPaletteColorCount());
+	_engine->setupPalette(imageDecoder->getPalette().data(), 0,
+	                      imageDecoder->getPalette().size());
 
 	_engine->setCursor(181);
 	_engine->showMouse(true);
@@ -1178,8 +1178,8 @@ Common::String Versailles_Documentation::docAreaHandleCastleMap() {
 
 	_fontManager->setSurface(&mapSurface);
 
-	_engine->setupPalette(imageDecoder->getPalette(), 0,
-	                      imageDecoder->getPaletteColorCount());
+	_engine->setupPalette(imageDecoder->getPalette().data(), 0,
+	                      imageDecoder->getPalette().size());
 
 	_engine->setCursor(181);
 	_engine->showMouse(true);
@@ -1472,8 +1472,8 @@ void Versailles_Documentation::drawRecordData(Graphics::ManagedSurface &surface,
 	Image::ImageDecoder *imageDecoder = _engine->loadHLZ(backgroundPath);
 	const Graphics::Surface *bgFrame = imageDecoder->getSurface();
 
-	_engine->setupPalette(imageDecoder->getPalette(), 0,
-	                      imageDecoder->getPaletteColorCount());
+	_engine->setupPalette(imageDecoder->getPalette().data(), 0,
+	                      imageDecoder->getPalette().size());
 
 	surface.create(bgFrame->w, bgFrame->h, bgFrame->format);
 	surface.blitFrom(*bgFrame);
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index fd7c1ffeab2..bb333298664 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -643,9 +643,9 @@ void CryOmni3DEngine_Versailles::loadCursorsPalette() {
 		error("Failed to load BMP file");
 	}
 
-	_cursorPalette = new byte[3 * bmpDecoder.getPaletteColorCount()]();
-	memcpy(_cursorPalette, bmpDecoder.getPalette(),
-	       3 * bmpDecoder.getPaletteColorCount());
+	const Graphics::Palette &palette = bmpDecoder.getPalette();
+	_cursorPalette = new byte[3 * palette.size()]();
+	palette.grab(_cursorPalette, 0, palette.size());
 }
 
 void CryOmni3DEngine_Versailles::setupPalette(const byte *palette, uint start, uint num,
@@ -1208,8 +1208,8 @@ void CryOmni3DEngine_Versailles::doPlaceChange() {
 				_currentPlace->setupWarpConstraints(_omni3dMan);
 				_omni3dMan.setSourceSurface(_currentWarpImage->getSurface());
 
-				setupPalette(_currentWarpImage->getPalette(), 0,
-				             _currentWarpImage->getPaletteColorCount(), !_fadedPalette);
+				setupPalette(_currentWarpImage->getPalette().data(), 0,
+				             _currentWarpImage->getPalette().size(), !_fadedPalette);
 
 				setMousePos(Common::Point(320, 240)); // Center of screen
 
@@ -1647,8 +1647,8 @@ void CryOmni3DEngine_Versailles::animateWarpTransition(const Transition *transit
 }
 
 void CryOmni3DEngine_Versailles::redrawWarp() {
-	setupPalette(_currentWarpImage->getPalette(), 0,
-	             _currentWarpImage->getPaletteColorCount(), true);
+	setupPalette(_currentWarpImage->getPalette().data(), 0,
+	             _currentWarpImage->getPalette().size(), true);
 	if (_forceRedrawWarp) {
 		const Graphics::Surface *result = _omni3dMan.getSurface();
 		g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h);
@@ -1720,8 +1720,8 @@ void CryOmni3DEngine_Versailles::displayObject(const Common::String &imgName,
 
 	if (imageDecoder->hasPalette()) {
 		// We don't need to calculate transparency but it's simpler to call this function
-		setupPalette(imageDecoder->getPalette(), 0,
-		             imageDecoder->getPaletteColorCount());
+		setupPalette(imageDecoder->getPalette().data(), 0,
+		             imageDecoder->getPalette().size());
 	}
 
 	const Graphics::Surface *image = imageDecoder->getSurface();
diff --git a/engines/cryomni3d/versailles/menus.cpp b/engines/cryomni3d/versailles/menus.cpp
index b754b111d7d..3b412712b07 100644
--- a/engines/cryomni3d/versailles/menus.cpp
+++ b/engines/cryomni3d/versailles/menus.cpp
@@ -143,8 +143,8 @@ uint CryOmni3DEngine_Versailles::displayOptions() {
 
 	while (!shouldAbort() && !end) {
 		if (resetScreen) {
-			setPalette(imageDecoder->getPalette(), 0,
-			           imageDecoder->getPaletteColorCount());
+			setPalette(imageDecoder->getPalette().data(), 0,
+			           imageDecoder->getPalette().size());
 			// _cursorPalette has only 248 colors as 8 last colors are for translucency
 			setPalette(_cursorPalette + 240 * 3, 240, 8);
 
@@ -1011,8 +1011,7 @@ void CryOmni3DEngine_Versailles::displayCredits() {
 	byte palette[256 * 3];
 	memset(palette, 0, 256 * 3);
 	// getPalette returns the first color not index 0
-	memcpy(palette, imageDecoder->getPalette(),
-	       3 * imageDecoder->getPaletteColorCount());
+	imageDecoder->getPalette().grab(palette, 0, imageDecoder->getPalette().size());
 	copySubPalette(palette, _cursorPalette, 240, 8);
 
 	creditsSurface.create(bgFrame->w, bgFrame->h, bgFrame->format);
diff --git a/engines/director/castmember/bitmap.cpp b/engines/director/castmember/bitmap.cpp
index a222e6437c7..70e9ba98b50 100644
--- a/engines/director/castmember/bitmap.cpp
+++ b/engines/director/castmember/bitmap.cpp
@@ -619,7 +619,7 @@ void BitmapCastMember::load() {
 						Common::DumpFile bitmapFile;
 
 						bitmapFile.open(Common::Path(filename), true);
-						Image::writePNG(bitmapFile, *decoder->getSurface(), decoder->getPalette());
+						Image::writePNG(bitmapFile, *decoder->getSurface(), decoder->getPalette().data());
 
 						bitmapFile.close();
 					}
@@ -691,7 +691,7 @@ void BitmapCastMember::load() {
 		Common::DumpFile bitmapFile;
 
 		bitmapFile.open(Common::Path(filename), true);
-		Image::writePNG(bitmapFile, *img->getSurface(), img->getPalette());
+		Image::writePNG(bitmapFile, *img->getSurface(), img->getPalette().data());
 
 		bitmapFile.close();
 	}
diff --git a/engines/director/images.cpp b/engines/director/images.cpp
index 774c49b0928..c3b0b5a3964 100644
--- a/engines/director/images.cpp
+++ b/engines/director/images.cpp
@@ -29,10 +29,8 @@
 
 namespace Director {
 
-DIBDecoder::DIBDecoder() {
+DIBDecoder::DIBDecoder() : _palette(0) {
 	_surface = nullptr;
-	_palette = nullptr;
-	_paletteColorCount = 0;
 	_bitsPerPixel = 0;
 	_codec = nullptr;
 }
@@ -44,9 +42,7 @@ DIBDecoder::~DIBDecoder() {
 void DIBDecoder::destroy() {
 	_surface = nullptr;	// It is deleted by BitmapRawDecoder
 
-	delete[] _palette;
-	_palette = nullptr;
-	_paletteColorCount = 0;
+	_palette.clear();
 
 	delete _codec;
 	_codec = nullptr;
@@ -54,20 +50,18 @@ void DIBDecoder::destroy() {
 
 void DIBDecoder::loadPalette(Common::SeekableReadStream &stream) {
 	uint16 steps = stream.size() / 6;
-	uint16 index = 0;
-	_paletteColorCount = steps;
-	_palette = new byte[steps * 3];
+	_palette.resize(steps, false);
 
 	for (uint8 i = 0; i < steps; i++) {
-		_palette[index] = stream.readByte();
+		byte r = stream.readByte();
 		stream.readByte();
 
-		_palette[index + 1] = stream.readByte();
+		byte g = stream.readByte();
 		stream.readByte();
 
-		_palette[index + 2] = stream.readByte();
+		byte b = stream.readByte();
 		stream.readByte();
-		index += 3;
+		_palette.set(i, r, g, b);
 	}
 }
 
@@ -88,10 +82,11 @@ bool DIBDecoder::loadStream(Common::SeekableReadStream &stream) {
 	/* uint32 imageSize = */ stream.readUint32LE();
 	/* int32 pixelsPerMeterX = */ stream.readSint32LE();
 	/* int32 pixelsPerMeterY = */ stream.readSint32LE();
-	_paletteColorCount = stream.readUint32LE();
+	uint32 paletteColorCount = stream.readUint32LE();
 	/* uint32 colorsImportant = */ stream.readUint32LE();
 
-	_paletteColorCount = (_paletteColorCount == 0) ? 255: _paletteColorCount;
+	paletteColorCount = (paletteColorCount == 0) ? 255: paletteColorCount;
+	_palette.resize(paletteColorCount, false);
 
 	Common::SeekableSubReadStream subStream(&stream, 40, stream.size());
 
@@ -130,7 +125,7 @@ bool DIBDecoder::loadStream(Common::SeekableReadStream &stream) {
 * BITD
 ****************************/
 
-BITDDecoder::BITDDecoder(int w, int h, uint16 bitsPerPixel, uint16 pitch, const byte *palette, uint16 version) {
+BITDDecoder::BITDDecoder(int w, int h, uint16 bitsPerPixel, uint16 pitch, const byte *palette, uint16 version) : _palette(0) {
 	_surface = new Graphics::Surface();
 	_pitch = pitch;
 	_version = version;
@@ -164,10 +159,9 @@ BITDDecoder::BITDDecoder(int w, int h, uint16 bitsPerPixel, uint16 pitch, const
 
 	_surface->create(w, h, format);
 
-	_palette = palette;
-
 	// TODO: Bring this in from the main surface?
-	_paletteColorCount = 255;
+	_palette.resize(255, false);
+	_palette.set(palette, 0, 255);
 
 	_bitsPerPixel = bitsPerPixel;
 }
@@ -180,8 +174,6 @@ void BITDDecoder::destroy() {
 	_surface->free();
 	delete _surface;
 	_surface = nullptr;
-
-	_paletteColorCount = 0;
 }
 
 void BITDDecoder::loadPalette(Common::SeekableReadStream &stream) {
diff --git a/engines/director/images.h b/engines/director/images.h
index 2445745aa45..6d7a3b0bae8 100644
--- a/engines/director/images.h
+++ b/engines/director/images.h
@@ -22,6 +22,7 @@
 #ifndef DIRECTOR_IMAGES_H
 #define DIRECTOR_IMAGES_H
 
+#include "graphics/palette.h"
 #include "image/image_decoder.h"
 
 namespace Common {
@@ -48,15 +49,13 @@ public:
 	void destroy() override;
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	const Graphics::Surface *getSurface() const override { return _surface; }
-	const byte *getPalette() const override { return _palette; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	void loadPalette(Common::SeekableReadStream &stream);
-	uint16 getPaletteColorCount() const override { return _paletteColorCount; }
 
 private:
 	Image::Codec *_codec;
 	const Graphics::Surface *_surface;
-	byte *_palette;
-	uint32 _paletteColorCount;
+	Graphics::Palette _palette;
 	uint16 _bitsPerPixel;
 };
 
@@ -69,14 +68,12 @@ public:
 	void destroy() override;
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	const Graphics::Surface *getSurface() const override { return _surface; }
-	const byte *getPalette() const override { return _palette; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	void loadPalette(Common::SeekableReadStream &stream);
-	uint16 getPaletteColorCount() const override { return _paletteColorCount; }
 
 private:
 	Graphics::Surface *_surface;
-	const byte *_palette;
-	uint8 _paletteColorCount;
+	Graphics::Palette _palette;
 	uint16 _bitsPerPixel;
 	uint16 _version;
 	uint16 _pitch;
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 37659ee01ae..da8acc678af 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -2414,7 +2414,7 @@ void LB::b_importFileInto(int nargs) {
 	movie->createOrReplaceCastMember(memberID, bitmapCast);
 	bitmapCast->setModified(true);
 	const Graphics::Surface *surf = img->getSurface();
-	bitmapCast->_size = surf->pitch * surf->h + img->getPaletteColorCount() * 3;
+	bitmapCast->_size = surf->pitch * surf->h + img->getPalette().size() * 3;
 	score->refreshPointersForCastMemberID(dst.asMemberID());
 }
 
diff --git a/engines/director/picture.cpp b/engines/director/picture.cpp
index d8afe4d06bf..d39ee694a57 100644
--- a/engines/director/picture.cpp
+++ b/engines/director/picture.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "common/textconsole.h"
+#include "graphics/palette.h"
 #include "image/image_decoder.h"
 #include "director/picture.h"
 
@@ -27,7 +28,7 @@ namespace Director {
 
 Picture::Picture(Image::ImageDecoder &img) {
 	_surface.copyFrom(*img.getSurface());
-	copyPalette(img.getPalette(), img.getPaletteColorCount());
+	copyPalette(img.getPalette().data(), img.getPalette().size());
 }
 
 Picture::Picture(Picture &picture) {
diff --git a/engines/director/tests.cpp b/engines/director/tests.cpp
index d8f675ccbc3..ae36ecec978 100644
--- a/engines/director/tests.cpp
+++ b/engines/director/tests.cpp
@@ -119,7 +119,7 @@ void Window::testFontScaling() {
 		Image::PICTDecoder k;
 		k.loadStream(in);
 
-		Graphics::Surface *res = k.getSurface()->convertTo(_wm->_pixelformat, k.getPalette(), k.getPaletteSize(), _wm->getPalette(), _wm->getPaletteSize(), Graphics::kDitherNaive);
+		Graphics::Surface *res = k.getSurface()->convertTo(_wm->_pixelformat, k.getPalette().data(), k.getPalette().size(), _wm->getPalette(), _wm->getPaletteSize(), Graphics::kDitherNaive);
 		surface.blitFrom(*res, Common::Point(400, 280));
 		delete res;
 
diff --git a/engines/dreamweb/vgagrafx.cpp b/engines/dreamweb/vgagrafx.cpp
index 32b78fdb1f3..709c0f7ea03 100644
--- a/engines/dreamweb/vgagrafx.cpp
+++ b/engines/dreamweb/vgagrafx.cpp
@@ -171,7 +171,7 @@ void DreamWebEngine::showPCX(const Common::String &suffix) {
 	// Read the 16-color palette into the 'maingamepal' buffer. Note that
 	// the color components have to be adjusted from 8 to 6 bits.
 	memset(_mainPal, 0xff, 256 * 3);
-	memcpy(_mainPal, pcx.getPalette(), 48);
+	memcpy(_mainPal, pcx.getPalette().data(), 48);
 	for (int i = 0; i < 48; i++) {
 		_mainPal[i] >>= 2;
 	}
diff --git a/engines/engine.cpp b/engines/engine.cpp
index 9ebe737d13c..49103f7849a 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -321,7 +321,7 @@ void splashScreen() {
 	screen.free();
 
 	// Draw logo
-	Graphics::Surface *logo = bitmap.getSurface()->convertTo(g_system->getOverlayFormat(), bitmap.getPalette());
+	Graphics::Surface *logo = bitmap.getSurface()->convertTo(g_system->getOverlayFormat(), bitmap.getPalette().data(), bitmap.getPalette().size());
 	if (scaleFactor != 1.0f) {
 		Graphics::Surface *tmp = logo->scale(int16(logo->w * scaleFactor), int16(logo->h * scaleFactor), true);
 		logo->free();
diff --git a/engines/freescape/doodle.cpp b/engines/freescape/doodle.cpp
index 63849e406a2..96b22249fc6 100644
--- a/engines/freescape/doodle.cpp
+++ b/engines/freescape/doodle.cpp
@@ -7,9 +7,7 @@
 
 namespace Image {
 
-DoodleDecoder::DoodleDecoder(const byte *palette) : _surface(nullptr), _palette(nullptr) {
-	// Copy the pointer to the provided palette
-	_palette = palette;
+DoodleDecoder::DoodleDecoder(const byte *palette) : _surface(nullptr), _palette(palette, 16) {
 }
 
 DoodleDecoder::~DoodleDecoder() {
diff --git a/engines/freescape/doodle.h b/engines/freescape/doodle.h
index 54366f49f87..94a26d6a2d6 100644
--- a/engines/freescape/doodle.h
+++ b/engines/freescape/doodle.h
@@ -3,6 +3,7 @@
 
 #include "image/image_decoder.h"
 #include "common/stream.h"
+#include "graphics/palette.h"
 #include "graphics/surface.h"
 
 namespace Image {
@@ -20,8 +21,7 @@ public:
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	void destroy() override;
 	const Graphics::Surface *getSurface() const override { return _surface; }
-	const byte *getPalette() const override { return _palette; }
-	uint16 getPaletteColorCount() const override { return 16; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 	/**
 	 * Load a C64 doodle image from its component streams
@@ -41,7 +41,7 @@ private:
 	static const int kColorDataSize = 1000;  // 40x25 color cells
 
 	Graphics::Surface *_surface;
-	const byte *_palette;
+	Graphics::Palette _palette;
 
 	/**
 	 * Process an 8x8 cell of the image
diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp
index 5c7a5211f33..0ce18d7c570 100644
--- a/engines/freescape/freescape.cpp
+++ b/engines/freescape/freescape.cpp
@@ -1114,7 +1114,7 @@ byte *FreescapeEngine::getPaletteFromNeoImage(Common::SeekableReadStream *stream
 	Image::NeoDecoder decoder;
 	decoder.loadStream(*stream);
 	byte *palette = (byte *)malloc(16 * 3 * sizeof(byte));
-	memcpy(palette, decoder.getPalette(), 16 * 3 * sizeof(byte));
+	decoder.getPalette().grab(palette, 0, 16);
 	return palette;
 }
 
@@ -1124,7 +1124,7 @@ Graphics::ManagedSurface *FreescapeEngine::loadAndConvertNeoImage(Common::Seekab
 	decoder.loadStream(*stream);
 	Graphics::ManagedSurface *surface = new Graphics::ManagedSurface();
 	surface->copyFrom(*decoder.getSurface());
-	surface->convertToInPlace(_gfx->_currentPixelFormat, decoder.getPalette(), decoder.getPaletteColorCount());
+	surface->convertToInPlace(_gfx->_currentPixelFormat, decoder.getPalette().data(), decoder.getPalette().size());
 	return surface;
 }
 
@@ -1133,7 +1133,7 @@ Graphics::ManagedSurface *FreescapeEngine::loadAndConvertDoodleImage(Common::See
 	decoder.loadStreams(*bitmap, *color1, *color2);
 	Graphics::ManagedSurface *surface = new Graphics::ManagedSurface();
 	surface->copyFrom(*decoder.getSurface());
-	surface->convertToInPlace(_gfx->_currentPixelFormat, decoder.getPalette(), decoder.getPaletteColorCount());
+	surface->convertToInPlace(_gfx->_currentPixelFormat, decoder.getPalette().data(), decoder.getPalette().size());
 	return surface;
 }
 
diff --git a/engines/glk/debugger.cpp b/engines/glk/debugger.cpp
index 8ca1a3da10b..996e47e9fd5 100644
--- a/engines/glk/debugger.cpp
+++ b/engines/glk/debugger.cpp
@@ -102,14 +102,13 @@ bool Debugger::cmdDumpPic(int argc, const char **argv) {
 void Debugger::saveRawPicture(const RawDecoder &rd, Common::WriteStream &ws) {
 #ifdef USE_PNG
 	const Graphics::Surface *surface = rd.getSurface();
-	const byte *palette = rd.getPalette();
-	int paletteCount = rd.getPaletteColorCount();
+	const Graphics::Palette &palette = rd.getPalette();
 	int palStart = 0;
 	bool hasTransColor = rd.hasTransparentColor();
 	uint32 transColor = rd.getTransparentColor();
 
 	// If the image doesn't have a palette, we can directly write out the image
-	if (!palette) {
+	if (palette.size() == 0) {
 		Image::writePNG(ws, *surface);
 		return;
 	}
@@ -126,9 +125,10 @@ void Debugger::saveRawPicture(const RawDecoder &rd, Common::WriteStream &ws) {
 			if ((hasTransColor && (uint32)*srcP == transColor) || (int)*srcP < palStart) {
 				*destP = format.ARGBToColor(0, 0, 0, 0);
 			} else {
-				assert(*srcP < paletteCount);
-				const byte *palP = &palette[*srcP * 3];
-				*destP = format.ARGBToColor(255, palP[0], palP[1], palP[2]);
+				assert(*srcP < palette.size());
+				byte r, g, b;
+				palette.get(*srcP, r, g, b);
+				*destP = format.ARGBToColor(255, r, g, b);
 			}
 		}
 	}
diff --git a/engines/glk/picture.cpp b/engines/glk/picture.cpp
index dbc54b7c915..4ab55222866 100644
--- a/engines/glk/picture.cpp
+++ b/engines/glk/picture.cpp
@@ -135,8 +135,8 @@ Picture *Pictures::load(const Common::String &name) {
 		png.setKeepTransparencyPaletted(true);
 		png.loadStream(f);
 		img = png.getSurface();
-		palette = png.getPalette();
-		palCount = png.getPaletteColorCount();
+		palette = png.getPalette().data();
+		palCount = png.getPalette().size();
 		hasTransColor = png.hasTransparentColor();
 		transColor = png.getTransparentColor();
 	} else if (
@@ -152,8 +152,8 @@ Picture *Pictures::load(const Common::String &name) {
 			f.open(Common::Path(Common::String::format("pic%s.raw", name.c_str())))) {
 		raw.loadStream(f);
 		img = raw.getSurface();
-		palette = raw.getPalette();
-		palCount = raw.getPaletteColorCount();
+		palette = raw.getPalette().data();
+		palCount = raw.getPalette().size();
 		hasTransColor = raw.hasTransparentColor();
 		transColor = raw.getTransparentColor();
 	} else if (f.open(Common::Path(Common::String::format("pic%s.rect", name.c_str())))) {
diff --git a/engines/glk/raw_decoder.cpp b/engines/glk/raw_decoder.cpp
index 28f9a5722e6..a31027bd8c3 100644
--- a/engines/glk/raw_decoder.cpp
+++ b/engines/glk/raw_decoder.cpp
@@ -25,7 +25,7 @@
 
 namespace Glk {
 
-RawDecoder::RawDecoder() : Image::ImageDecoder(), _palette(nullptr), _paletteColorCount(0),
+RawDecoder::RawDecoder() : Image::ImageDecoder(), _palette(0),
 	_transColor(0) {
 }
 
@@ -35,8 +35,7 @@ RawDecoder::~RawDecoder() {
 
 void RawDecoder::destroy() {
 	_surface.free();
-	delete[] _palette;
-	_palette = nullptr;
+	_palette.clear();
 }
 
 bool RawDecoder::loadStream(Common::SeekableReadStream &stream) {
@@ -45,24 +44,29 @@ bool RawDecoder::loadStream(Common::SeekableReadStream &stream) {
 
 	uint width = stream.readUint16LE();
 	uint height = stream.readUint16LE();
-	_paletteColorCount = stream.readUint16LE();
-	assert(_paletteColorCount == 0 || _paletteColorCount <= 0x100);
+	uint paletteColorCount = stream.readUint16LE();
+	assert(paletteColorCount == 0 || paletteColorCount <= 0x100);
 
-	if (_paletteColorCount != 0) {
+	if (paletteColorCount != 0) {
 		// Read in the palette
-		_palette = new byte[_paletteColorCount * 3];
-		stream.read(_palette, _paletteColorCount * 3);
+		_palette.resize(paletteColorCount, false);
+		for (uint16 i = 0; i < paletteColorCount; i++) {
+			byte r = stream.readByte();
+			byte g = stream.readByte();
+			byte b = stream.readByte();
+			_palette.set(i, r, g, b);
+		}
 
 		// Get the transparent color
 		byte transColor = stream.readByte();
-		if (transColor < _paletteColorCount)
+		if (transColor < paletteColorCount)
 			_transColor = transColor;
 	} else {
 		_transColor = 0;
 	}
 
 	// Set up the surface
-	_surface.create(width, height, (_paletteColorCount == 0) ?
+	_surface.create(width, height, (paletteColorCount == 0) ?
 	    Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0) :
 		Graphics::PixelFormat::createFormatCLUT8());
 
@@ -71,11 +75,11 @@ bool RawDecoder::loadStream(Common::SeekableReadStream &stream) {
 	byte *pixels = (byte *)_surface.getPixels();
 	stream.read(pixels, width * height * _surface.format.bytesPerPixel);
 
-	if (_palette) {
+	if (paletteColorCount > 0) {
 		for (uint idx = 0; idx < width * height; ++idx, ++pixels) {
 			assert(*pixels != 0xff);
-			if (*pixels >= _paletteColorCount)
-				*pixels = _paletteColorCount - 1;
+			if (*pixels >= paletteColorCount)
+				*pixels = paletteColorCount - 1;
 		}
 	}
 
diff --git a/engines/glk/raw_decoder.h b/engines/glk/raw_decoder.h
index 292efe4e052..9919957ccba 100644
--- a/engines/glk/raw_decoder.h
+++ b/engines/glk/raw_decoder.h
@@ -22,6 +22,7 @@
 #ifndef GLK_RAW_DECODER_H
 #define GLK_RAW_DECODER_H
 
+#include "graphics/palette.h"
 #include "graphics/surface.h"
 #include "image/image_decoder.h"
 
@@ -42,8 +43,7 @@ namespace Glk {
 class RawDecoder : public Image::ImageDecoder {
 private:
 	Graphics::Surface _surface;
-	byte *_palette;
-	uint16 _paletteColorCount;
+	Graphics::Palette _palette;
 	uint32 _transColor;
 public:
 	RawDecoder();
@@ -52,8 +52,7 @@ public:
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	void destroy() override;
 	const Graphics::Surface *getSurface() const override { return &_surface; }
-	const byte *getPalette() const override { return _palette; }
-	uint16 getPaletteColorCount() const override { return _paletteColorCount; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	bool hasTransparentColor() const override { return true; }
 	uint32 getTransparentColor() const override { return _transColor; }
 };
diff --git a/engines/gob/inter_v7.cpp b/engines/gob/inter_v7.cpp
index c960704ad7d..9eda38cb06f 100644
--- a/engines/gob/inter_v7.cpp
+++ b/engines/gob/inter_v7.cpp
@@ -931,12 +931,12 @@ void Inter_v7::o7_loadIFFPalette() {
 
 	Image::IFFDecoder decoder;
 	decoder.loadStream(*iffFile);
-	if (!decoder.getPalette() || decoder.getPaletteColorCount() != 256) {
+	if (decoder.getPalette().size() != 256) {
 		warning("o7_loadIFFPalette(): Failed reading palette from IFF \"%s\"", file.c_str());
 		return;
 	}
 
-	const byte *palette = decoder.getPalette();
+	const byte *palette = decoder.getPalette().data();
 
 	startIndex *= 3;
 	stopIndex  *= 3;
diff --git a/engines/grim/material.cpp b/engines/grim/material.cpp
index e48928b5a27..005b697355d 100644
--- a/engines/grim/material.cpp
+++ b/engines/grim/material.cpp
@@ -81,8 +81,8 @@ static void loadImage(Image::ImageDecoder *decoder, Texture *t) {
 	if (decoder->hasPalette()) {
 		uint32 map[256];
 		Graphics::convertPaletteToMap(map,
-		                              decoder->getPalette(),
-		                              decoder->getPaletteColorCount(),
+		                              decoder->getPalette().data(),
+		                              decoder->getPalette().size(),
 		                              format_3bpp);
 		Graphics::crossBlitMap(t->_data, (const byte *)surface->getPixels(),
 		                       t->_width * t->_bpp, surface->pitch,
diff --git a/engines/hopkins/graphics.cpp b/engines/hopkins/graphics.cpp
index 7563f3a3287..703bb3c3d3e 100644
--- a/engines/hopkins/graphics.cpp
+++ b/engines/hopkins/graphics.cpp
@@ -327,7 +327,7 @@ void GraphicsManager::loadPCX640(byte *surface, const Common::Path &file, byte *
 	Common::copy((const byte *)s->getPixels(), (const byte *)s->getBasePtr(0, s->h), surface);
 
 	// Copy out the palette
-	const byte *palSrc = pcxDecoder.getPalette();
+	const byte *palSrc = pcxDecoder.getPalette().data();
 	Common::copy((const byte *)palSrc, (const byte *)palSrc + PALETTE_BLOCK_SIZE, palette);
 
 	f.close();
diff --git a/engines/kingdom/kingdom.cpp b/engines/kingdom/kingdom.cpp
index d58a0c01240..879efe5d20e 100644
--- a/engines/kingdom/kingdom.cpp
+++ b/engines/kingdom/kingdom.cpp
@@ -418,8 +418,8 @@ void KingdomGame::showPic(int reznum) {
 
 	delete stream;
 
-	const byte *palette = decoder.getPalette();
-	int paletteColorCount = decoder.getPaletteColorCount();
+	const byte *palette = decoder.getPalette().data();
+	int paletteColorCount = decoder.getPalette().size();
 	g_system->getPaletteManager()->setPalette(palette, 0, paletteColorCount);
 
 	const Graphics::Surface *surface = decoder.getSurface();
diff --git a/engines/mm/mm1/gfx/screen_decoder.h b/engines/mm/mm1/gfx/screen_decoder.h
index 723b8edfc21..1684c28e394 100644
--- a/engines/mm/mm1/gfx/screen_decoder.h
+++ b/engines/mm/mm1/gfx/screen_decoder.h
@@ -24,6 +24,7 @@
 
 #include "image/image_decoder.h"
 #include "graphics/managed_surface.h"
+#include "graphics/palette.h"
 
 namespace MM {
 namespace MM1 {
@@ -32,10 +33,11 @@ namespace Gfx {
 class ScreenDecoder : public Image::ImageDecoder {
 private:
 	Graphics::Surface _surface;
+	Graphics::Palette _palette;
 public:
 	byte _indexes[4] = { 0 };		// EGA palete indexes used
 public:
-	ScreenDecoder() {}
+	ScreenDecoder() : _palette(0) {}
 	~ScreenDecoder() override;
 
 	void destroy() override;
@@ -49,8 +51,7 @@ public:
 	const Graphics::Surface *getSurface() const override {
 		return &_surface;
 	}
-	const byte *getPalette() const override { return nullptr; }
-	uint16 getPaletteColorCount() const override { return 0; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	void clear() { _surface.free(); }
 };
 
diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp
index cf94f74eb3c..10def367725 100644
--- a/engines/mohawk/bitmap.cpp
+++ b/engines/mohawk/bitmap.cpp
@@ -669,7 +669,7 @@ MohawkSurface *MystBitmap::decodeImage(Common::SeekableReadStream *stream) {
 	byte *newPal = nullptr;
 
 	if (bitmapDecoder.hasPalette()) {
-		const byte *palette = bitmapDecoder.getPalette();
+		const byte *palette = bitmapDecoder.getPalette().data();
 		newPal = (byte *)malloc(256 * 3);
 		memcpy(newPal, palette, 256 * 3);
 	}
diff --git a/engines/mtropolis/plugin/standard.cpp b/engines/mtropolis/plugin/standard.cpp
index 303fb45c623..5fcdd8c4a21 100644
--- a/engines/mtropolis/plugin/standard.cpp
+++ b/engines/mtropolis/plugin/standard.cpp
@@ -1575,7 +1575,7 @@ bool PrintModifierImageSupplier::loadImageSlot(uint slot, const Graphics::Surfac
 	outHasPalette = _decoder->hasPalette();
 
 	if (_decoder->hasPalette())
-		outPalette.set(_decoder->getPalette(), 0, _decoder->getPaletteColorCount());
+		outPalette.set(_decoder->getPalette(), 0, _decoder->getPalette().size());
 
 	outMetadata = GUI::ImageAlbumImageMetadata();
 	outMetadata._orientation = GUI::kImageAlbumImageOrientationLandscape;
diff --git a/engines/nancy/graphics.cpp b/engines/nancy/graphics.cpp
index 12fe481df25..f1c0e6573d3 100644
--- a/engines/nancy/graphics.cpp
+++ b/engines/nancy/graphics.cpp
@@ -219,7 +219,7 @@ void GraphicsManager::loadSurfacePalette(Graphics::ManagedSurface &inSurf, const
 	if (f.open(paletteFilename.append(".bmp"))) {
 		Image::BitmapDecoder dec;
 		if (dec.loadStream(f)) {
-			inSurf.setPalette(dec.getPalette(), paletteStart, paletteSize);
+			inSurf.setPalette(dec.getPalette().data(), paletteStart, paletteSize);
 		}
 	}
 }
diff --git a/engines/nancy/resource.cpp b/engines/nancy/resource.cpp
index 7bbf3e45a9d..d83c992da78 100644
--- a/engines/nancy/resource.cpp
+++ b/engines/nancy/resource.cpp
@@ -77,7 +77,7 @@ bool ResourceManager::loadImage(const Common::Path &name, Graphics::ManagedSurfa
 			Image::BitmapDecoder bmpDec;
 			bmpDec.loadStream(*stream);
 			surf.copyFrom(*bmpDec.getSurface());
-			surf.setPalette(bmpDec.getPalette(), 0, MIN<uint>(256, bmpDec.getPaletteColorCount())); // LOGO.BMP reports 257 colors
+			surf.setPalette(bmpDec.getPalette().data(), 0, MIN<uint>(256, bmpDec.getPalette().size())); // LOGO.BMP reports 257 colors
 		}
 	}
 
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 72d8f3b27a3..664c7897a98 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -490,7 +490,7 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
 	info.height = info.bg.h;
 
 	// Overwrite the first color (transparent key) in the palette
-	p = decoder.getPalette();
+	p = decoder.getPalette().data();
 	info.palette.setEntry(0, p[0] >> 2, p[1] >> 2, p[2] >> 0);
 
 	for (i = 16; i < 32; i++) {
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index 5a6ff419a72..2c40b23305f 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -763,15 +763,11 @@ void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) {
 	info.width = info.bg.w;
 	info.height = info.bg.h;
 
-	const byte *p = decoder.getPalette();
+	const Graphics::Palette &p = decoder.getPalette();
 	for (uint i = 0; i < 32; i++) {
-		byte r = *p >> 2;
-		p++;
-		byte g = *p >> 2;
-		p++;
-		byte b = *p >> 2;
-		p++;
-		info.palette.setEntry(i, r, g, b);
+		byte r, g, b;
+		p.get(i, r, g, b);
+		info.palette.setEntry(i, r >> 2, g >> 2, b >> 2);
 	}
 
 	const Common::Array<Image::IFFDecoder::PaletteRange> &paletteRanges = decoder.getPaletteRanges();
@@ -803,12 +799,10 @@ void AmigaDisk_ns::loadMask_internal(BackgroundInfo& info, const char *name) {
 	decoder.setPixelPacking(true); // pack 4 2bit pixels into 1 byte
 	decoder.loadStream(*s);
 
-	const byte *p = decoder.getPalette();
-	byte r, g, b;
+	const Graphics::Palette &p = decoder.getPalette();
 	for (uint i = 0; i < 4; i++) {
-		r = p[i*3];
-		g = p[i*3+1];
-		b = p[i*3+2];
+		byte r, g, b;
+		p.get(i, r, g, b);
 		info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF;
 	}
 
diff --git a/engines/pegasus/cursor.cpp b/engines/pegasus/cursor.cpp
index c23b4645afc..39939a1bf10 100644
--- a/engines/pegasus/cursor.cpp
+++ b/engines/pegasus/cursor.cpp
@@ -160,7 +160,7 @@ void Cursor::loadCursorImage(CursorInfo &cursorInfo) {
 		if (!cicn.loadStream(*cicnStream))
 			error("Failed to decode cursor cicn %d", cursorInfo.tag);
 
-		cursorInfo.surface = cicn.getSurface()->convertTo(g_system->getScreenFormat(), cicn.getPalette(), cicn.getPaletteColorCount());
+		cursorInfo.surface = cicn.getSurface()->convertTo(g_system->getScreenFormat(), cicn.getPalette().data(), cicn.getPalette().size());
 		delete cicnStream;
 		return;
 	}
diff --git a/engines/pegasus/surface.cpp b/engines/pegasus/surface.cpp
index 1dd85e991e6..c648fd09391 100644
--- a/engines/pegasus/surface.cpp
+++ b/engines/pegasus/surface.cpp
@@ -105,7 +105,7 @@ bool Surface::getImageFromPICTStream(Common::SeekableReadStream *stream) {
 	if (!pict.loadStream(*stream))
 		return false;
 
-	_surface = pict.getSurface()->convertTo(g_system->getScreenFormat(), pict.getPalette());
+	_surface = pict.getSurface()->convertTo(g_system->getScreenFormat(), pict.getPalette().data(), pict.getPalette().size());
 	_ownsSurface = true;
 	_bounds = Common::Rect(0, 0, _surface->w, _surface->h);
 	return true;
diff --git a/engines/petka/q_manager.cpp b/engines/petka/q_manager.cpp
index 78d869be41e..0071e5ecd3b 100644
--- a/engines/petka/q_manager.cpp
+++ b/engines/petka/q_manager.cpp
@@ -186,7 +186,7 @@ Graphics::Surface *QManager::loadBitmapSurface(Common::SeekableReadStream &strea
 		Image::BitmapDecoder decoder;
 		if (!decoder.loadStream(stream))
 			return nullptr;
-		return decoder.getSurface()->convertTo(g_system->getScreenFormat(), decoder.getPalette());
+		return decoder.getSurface()->convertTo(g_system->getScreenFormat(), decoder.getPalette().data(), decoder.getPalette().size());
 	}
 	else if (bitsPerPixel == 1) {
 		Graphics::Surface *s = new Graphics::Surface;
@@ -218,7 +218,7 @@ Graphics::Surface *QManager::loadBitmapSurface(Common::SeekableReadStream &strea
 	if (!decoder.loadStream(convBmpStream))
 		return nullptr;
 
-	return decoder.getSurface()->convertTo(g_system->getScreenFormat(), decoder.getPalette());
+	return decoder.getSurface()->convertTo(g_system->getScreenFormat(), decoder.getPalette().data(), decoder.getPalette().size());
 }
 
 QManager::QResource::~QResource() {
diff --git a/engines/plumbers/plumbers.cpp b/engines/plumbers/plumbers.cpp
index c6105e9f65a..a71877ca657 100644
--- a/engines/plumbers/plumbers.cpp
+++ b/engines/plumbers/plumbers.cpp
@@ -267,8 +267,8 @@ void PlumbersGame::drawScreen() {
 			_showScoreFl = false;
 		}
 
-		if (_image->getPalette() != nullptr)
-			g_system->getPaletteManager()->setPalette(_image->getPalette(), 0, 256);
+		if (_image->hasPalette())
+			g_system->getPaletteManager()->setPalette(_image->getPalette().data(), 0, _image->getPalette().size());
 		g_system->updateScreen();
 	}
 }
diff --git a/engines/plumbers/windows.cpp b/engines/plumbers/windows.cpp
index d685558d4f7..b01c7096b4b 100644
--- a/engines/plumbers/windows.cpp
+++ b/engines/plumbers/windows.cpp
@@ -55,7 +55,7 @@ void PlumbersGameWindows::loadImage(const Common::String &name) {
 		_compositeSurface = new Graphics::Surface();
 		const Graphics::Surface *inSurf = _image->getSurface();
 		_compositeSurface->create(_screenW, _screenH, inSurf->format);
-		Graphics::downscaleSurfaceByHalf(_compositeSurface, inSurf, _image->getPalette());
+		Graphics::downscaleSurfaceByHalf(_compositeSurface, inSurf, _image->getPalette().data());
 	}
 }
 
diff --git a/engines/prince/cursor.cpp b/engines/prince/cursor.cpp
index 596b468abb5..4d08beee207 100644
--- a/engines/prince/cursor.cpp
+++ b/engines/prince/cursor.cpp
@@ -85,7 +85,7 @@ void PrinceEngine::changeCursor(uint16 curId) {
 		break;
 	}
 
-	CursorMan.replaceCursorPalette(_roomBmp->getPalette(), 0, 255);
+	CursorMan.replaceCursorPalette(_roomBmp->getPalette().data(), 0, 255);
 	CursorMan.replaceCursor(
 		curSurface->getBasePtr(0, 0),
 		curSurface->w, curSurface->h,
diff --git a/engines/prince/graphics.cpp b/engines/prince/graphics.cpp
index c2a76b46e0b..cfd6d40eb05 100644
--- a/engines/prince/graphics.cpp
+++ b/engines/prince/graphics.cpp
@@ -373,7 +373,7 @@ byte GraphicsMan::getBlendTableColor(byte pixelColor, byte backgroundPixelColor,
 	if (blendTable[pixelColor] != 255) {
 		currColor = blendTable[pixelColor];
 	} else {
-		const byte *originalPalette = _vm->_roomBmp->getPalette();
+		const byte *originalPalette = _vm->_roomBmp->getPalette().data();
 
 		int redFirstOrg = originalPalette[pixelColor * 3] * _vm->_mst_shadow / 256;
 		redFirstOrg = CLIP(redFirstOrg, 0, 255);
@@ -434,7 +434,7 @@ byte GraphicsMan::getBlendTableColor(byte pixelColor, byte backgroundPixelColor,
 
 void GraphicsMan::makeShadowTable(int brightness, byte *shadowPalette) {
 	int shadow =  brightness * 256 / 100;
-	const byte *originalPalette = _vm->_roomBmp->getPalette();
+	const byte *originalPalette = _vm->_roomBmp->getPalette().data();
 
 	for (int i = 0; i < 256; i++) {
 		int redFirstOrg = originalPalette[3 * i] * shadow / 256;
diff --git a/engines/prince/mhwanh.cpp b/engines/prince/mhwanh.cpp
index e1e6f6bc650..e2d0b4aaa6a 100644
--- a/engines/prince/mhwanh.cpp
+++ b/engines/prince/mhwanh.cpp
@@ -27,7 +27,7 @@
 
 namespace Prince {
 
-MhwanhDecoder::MhwanhDecoder() : _surface(nullptr), _palette(nullptr) {
+MhwanhDecoder::MhwanhDecoder() : _surface(nullptr), _palette(0) {
 }
 
 MhwanhDecoder::~MhwanhDecoder() {
@@ -40,10 +40,7 @@ void MhwanhDecoder::destroy() {
 		delete _surface;
 		_surface = nullptr;
 	}
-	if (_palette != nullptr) {
-		free(_palette);
-		_palette = nullptr;
-	}
+	_palette.clear();
 }
 
 bool MhwanhDecoder::loadStream(Common::SeekableReadStream &stream) {
@@ -51,11 +48,12 @@ bool MhwanhDecoder::loadStream(Common::SeekableReadStream &stream) {
 	stream.seek(0);
 	stream.skip(0x20);
 	// Read the palette
-	_palette = (byte *)malloc(kPaletteColorCount * 3);
+	_palette.resize(kPaletteColorCount, false);
 	for (uint16 i = 0; i < kPaletteColorCount; i++) {
-		_palette[i * 3] = stream.readByte();
-		_palette[i * 3 + 1] = stream.readByte();
-		_palette[i * 3 + 2] = stream.readByte();
+		byte r = stream.readByte();
+		byte g = stream.readByte();
+		byte b = stream.readByte();
+		_palette.set(i, r, g, b);
 	}
 
 	_surface = new Graphics::Surface();
diff --git a/engines/prince/mhwanh.h b/engines/prince/mhwanh.h
index 0bbbdd44636..f5216798324 100644
--- a/engines/prince/mhwanh.h
+++ b/engines/prince/mhwanh.h
@@ -40,13 +40,13 @@ public:
 	void destroy() override;
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	Graphics::Surface *getSurface() const override { return _surface; }
-	const byte *getPalette() const override { return _palette; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	uint16 getPaletteCount() const { return kPaletteColorCount; }
 	static const uint16 kPaletteColorCount = 256;
 
 private:
 	Graphics::Surface *_surface;
-	byte *_palette;
+	Graphics::Palette _palette;
 };
 
 } // End of namespace Prince
diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp
index f838faf0bd2..1db1ce92e94 100644
--- a/engines/prince/prince.cpp
+++ b/engines/prince/prince.cpp
@@ -403,7 +403,7 @@ void PrinceEngine::showLogo() {
 		_graph->draw(_graph->_frontScreen, logo.getSurface());
 		_graph->change();
 		_graph->update(_graph->_frontScreen);
-		setPalette(logo.getPalette());
+		setPalette(logo.getPalette().data());
 
 		uint32 logoStart = _system->getMillis();
 		while (_system->getMillis() < logoStart + 5000) {
diff --git a/engines/prince/script.cpp b/engines/prince/script.cpp
index 935f3b58f97..ffef1724ce2 100644
--- a/engines/prince/script.cpp
+++ b/engines/prince/script.cpp
@@ -602,7 +602,7 @@ void Interpreter::O_BLACKPALETTE() {
 
 void Interpreter::O_SETUPPALETTE() {
 	debugInterpreter("O_SETUPPALETTE");
-	_vm->setPalette(_vm->_roomBmp->getPalette());
+	_vm->setPalette(_vm->_roomBmp->getPalette().data());
 }
 
 void Interpreter::O_INITROOM() {
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index fdacbbf4093..4afb7885e2a 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -1497,10 +1497,10 @@ Graphics::Surface *PrivateEngine::decodeImage(const Common::String &name, byte *
 	const Graphics::Surface *oldImage = _image->getSurface();
 	Graphics::Surface *newImage;
 
-	const byte *oldPalette = _image->getPalette();
+	const byte *oldPalette = _image->getPalette().data();
 	byte *currentPalette;
 
-	uint16 ncolors = _image->getPaletteColorCount();
+	uint16 ncolors = _image->getPalette().size();
 	if (ncolors < 256 || path.toString('/').hasPrefix("intro")) { // For some reason, requires color remapping
 		currentPalette = (byte *) malloc(3*256);
 		drawScreen();
diff --git a/engines/qdengine/qdcore/util/splash_screen.cpp b/engines/qdengine/qdcore/util/splash_screen.cpp
index 8400e12287e..3ffa09b7316 100644
--- a/engines/qdengine/qdcore/util/splash_screen.cpp
+++ b/engines/qdengine/qdcore/util/splash_screen.cpp
@@ -47,10 +47,10 @@ bool SplashScreen::create(int bitmapResID) {
 		if (stream && decoder.loadStream(*stream)) {
 			_splash = new Graphics::Surface();
 			_splash->copyFrom(*decoder.getSurface());
-			_paletteCount = decoder.getPaletteColorCount();
+			_paletteCount = decoder.getPalette().size();
 			_palette = new byte[_paletteCount * 3];
 
-			memcpy(_palette, decoder.getPalette(), _paletteCount * 3);
+			memcpy(_palette, decoder.getPalette().data(), _paletteCount * 3);
 		}
 	} else {
 		warning("SplashScreen::create(): Cannot load splash screen from file %s", g_engine->getExeName());
diff --git a/engines/queen/display.cpp b/engines/queen/display.cpp
index 97da0fc7d36..6138f9ba986 100644
--- a/engines/queen/display.cpp
+++ b/engines/queen/display.cpp
@@ -827,7 +827,7 @@ void Display::decodePCX(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dst
 	*h = pcxSurface->h;
 
 	assert(palStart <= palEnd && palEnd <= 256);
-	memcpy(pal, pcx.getPalette() + palStart * 3, (palEnd - palStart) * 3);
+	memcpy(pal, pcx.getPalette().data() + palStart * 3, (palEnd - palStart) * 3);
 	for (uint16 y = 0; y < pcxSurface->h; y++)
 		memcpy(dst + y * dstPitch, pcxSurface->getBasePtr(0, y), pcxSurface->w);
 }
@@ -844,7 +844,7 @@ void Display::decodeIFF(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dst
 	*h	= iffSurface->h;
 
 	assert(palStart <= palEnd && palEnd <= 256);
-	memcpy(pal, iff.getPalette() + palStart * 3, (palEnd - palStart) * 3);
+	memcpy(pal, iff.getPalette().data() + palStart * 3, (palEnd - palStart) * 3);
 	for (uint16 y = 0; y < iffSurface->h; y++)
 		for(uint16 x = 0; x < iffSurface->w; x++)
 			dst[(y * dstPitch) + x] = *(const byte *)iffSurface->getBasePtr(x, y) + colorBase;
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index 308839af3ad..cdb54396cb6 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -434,7 +434,6 @@ void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionTy
 	if (_vm->_hasITESceneSubstitutes) {
 		for (int i = 0; i < ARRAYSIZE(sceneSubstitutes); i++) {
 			if (sceneSubstitutes[i].sceneId == sceneNumber) {
-				const byte *pal;
 				Common::File file;
 				Rect rect;
 				PalEntry cPal[PAL_ENTRIES];
@@ -444,14 +443,12 @@ void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionTy
 				if (file.open(sceneSubstitutes[i].image)) {
 					Image::IFFDecoder decoder;
 					decoder.loadStream(file);
-					pal = decoder.getPalette();
+					const Graphics::Palette &pal = decoder.getPalette();
 					rect.setWidth(decoder.getSurface()->w);
 					rect.setHeight(decoder.getSurface()->h);
 					_vm->_gfx->drawRegion(rect, (const byte *)decoder.getSurface()->getPixels());
 					for (int j = 0; j < PAL_ENTRIES; j++) {
-						cPal[j].red = *pal++;
-						cPal[j].green = *pal++;
-						cPal[j].blue = *pal++;
+						pal.get(j, cPal[j].red, cPal[j].green, cPal[j].blue);
 					}
 					_vm->_gfx->setPalette(cPal);
 
diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp
index 232ad8f4c33..75144c5d754 100644
--- a/engines/sci/graphics/maciconbar.cpp
+++ b/engines/sci/graphics/maciconbar.cpp
@@ -263,7 +263,7 @@ Graphics::Surface *GfxMacIconBar::loadPict(ResourceId id) {
 
 	Graphics::Surface *surface = new Graphics::Surface();
 	surface->copyFrom(*pictDecoder.getSurface());
-	remapColors(surface, pictDecoder.getPalette());
+	remapColors(surface, pictDecoder.getPalette().data());
 
 	return surface;
 }
diff --git a/engines/scumm/macgui/macgui_impl.cpp b/engines/scumm/macgui/macgui_impl.cpp
index 85b814bb753..764757f813e 100644
--- a/engines/scumm/macgui/macgui_impl.cpp
+++ b/engines/scumm/macgui/macgui_impl.cpp
@@ -628,9 +628,9 @@ bool MacGuiImpl::loadIcon(int id, Graphics::Surface **icon, Graphics::Surface **
 		result = true;
 		const Graphics::Surface *s1 = iconDecoder.getSurface();
 		const Graphics::Surface *s2 = iconDecoder.getMask();
-		const byte *palette = iconDecoder.getPalette();
+		const Graphics::Palette &palette = iconDecoder.getPalette();
 
-		*icon = createRemappedSurface(s1, palette, iconDecoder.getPaletteColorCount());
+		*icon = createRemappedSurface(s1, palette.data(), palette.size());
 		*mask = new Graphics::Surface();
 		(*mask)->copyFrom(*s2);
 	}
@@ -657,9 +657,9 @@ Graphics::Surface *MacGuiImpl::loadPict(int id) {
 
 	if (res && pictDecoder.loadStream(*res)) {
 		const Graphics::Surface *surface = pictDecoder.getSurface();
-		const byte *palette = pictDecoder.getPalette();
+		const Graphics::Palette &palette = pictDecoder.getPalette();
 
-		s = createRemappedSurface(surface, palette, pictDecoder.getPaletteColorCount());
+		s = createRemappedSurface(surface, palette.data(), palette.size());
 	}
 
 	delete res;
@@ -815,9 +815,6 @@ MacGuiImpl::MacDialogWindow *MacGuiImpl::createDialog(int dialogId, Common::Rect
 			Image::PICTDecoder pictDecoder;
 			Image::CicnDecoder iconDecoder;
 
-			const byte *palette = nullptr;
-			int paletteColorCount = 0;
-
 			Common::SeekableReadStream *imageRes = nullptr;
 			Image::ImageDecoder *decoder = nullptr;
 
@@ -838,10 +835,11 @@ MacGuiImpl::MacDialogWindow *MacGuiImpl::createDialog(int dialogId, Common::Rect
 			}
 
 			if (imageRes && decoder->loadStream(*imageRes)) {
-				palette = decoder->getPalette();
-				paletteColorCount = decoder->getPaletteColorCount();
-				for (int j = 0; j < paletteColorCount; j++) {
-					uint32 color = (palette[3 * j] << 16) | (palette[3 * j + 1] << 8) | palette[3 * j + 2];
+				const Graphics::Palette &palette = decoder->getPalette();
+				for (uint j = 0; j < palette.size(); j++) {
+					byte r, g, b;
+					palette.get(j, r, g, b);
+					uint32 color = (r << 16) | (g << 8) | b;
 					if (!paletteMap.contains(color))
 						paletteMap[color] = numWindowColors++;
 				}
diff --git a/engines/sludge/hsi.cpp b/engines/sludge/hsi.cpp
index 3090579b489..43c4081d4c3 100644
--- a/engines/sludge/hsi.cpp
+++ b/engines/sludge/hsi.cpp
@@ -29,7 +29,7 @@
 
 namespace Sludge {
 
-HSIDecoder::HSIDecoder() : _surface(nullptr), _reserve(-1) {
+HSIDecoder::HSIDecoder() : _surface(nullptr), _palette(0), _reserve(-1) {
 }
 
 HSIDecoder::~HSIDecoder() {
diff --git a/engines/sludge/hsi.h b/engines/sludge/hsi.h
index e23e91aaa59..ac750c72e8f 100644
--- a/engines/sludge/hsi.h
+++ b/engines/sludge/hsi.h
@@ -21,6 +21,7 @@
 #ifndef SLUDGE_HSI_H
 #define SLUDGE_HSI_H
 
+#include "graphics/palette.h"
 #include "image/image_decoder.h"
 
 namespace Sludge {
@@ -34,10 +35,12 @@ public:
 	void destroy() override;
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	Graphics::Surface *getSurface() const override { return _surface; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	void setReserve(bool reserve) { _reserve = reserve; }
 
 private:
 	Graphics::Surface *_surface;
+	Graphics::Palette _palette;
 	int _reserve;
 };
 
diff --git a/engines/sludge/imgloader.cpp b/engines/sludge/imgloader.cpp
index 51525d1a755..aee8d85bd25 100644
--- a/engines/sludge/imgloader.cpp
+++ b/engines/sludge/imgloader.cpp
@@ -91,7 +91,7 @@ bool ImgLoader::loadPNGImage(Common::SeekableReadStream *stream, Graphics::Surfa
 	}
 
 	const Graphics::Surface *sourceSurface = png.getSurface();
-	Graphics::Surface *pngSurface = sourceSurface->convertTo(*g_sludge->getScreenPixelFormat(), png.getPalette());
+	Graphics::Surface *pngSurface = sourceSurface->convertTo(*g_sludge->getScreenPixelFormat(), png.getPalette().data(), png.getPalette().size());
 	dest->copyFrom(*pngSurface);
 	pngSurface->free();
 	delete pngSurface;
diff --git a/engines/stark/ui/dialogbox.cpp b/engines/stark/ui/dialogbox.cpp
index 4feab1b8dac..5ccd38ba4f4 100644
--- a/engines/stark/ui/dialogbox.cpp
+++ b/engines/stark/ui/dialogbox.cpp
@@ -254,7 +254,7 @@ Gfx::Bitmap *DialogBox::loadBackground(Gfx::Driver *gfx) {
 
 	delete[] bitmapWithHeader;
 
-	return gfx->createBitmap(decoder.getSurface(), decoder.getPalette());
+	return gfx->createBitmap(decoder.getSurface(), decoder.getPalette().data());
 }
 
 void DialogBox::onRender() {
diff --git a/engines/stark/visual/image.cpp b/engines/stark/visual/image.cpp
index c42cebf21a1..f8c377eae64 100644
--- a/engines/stark/visual/image.cpp
+++ b/engines/stark/visual/image.cpp
@@ -81,7 +81,7 @@ bool VisualImageXMG::loadPNG(Common::SeekableReadStream *stream) {
 		return false;
 	}
 
-	if (pngDecoder.getPalette()) {
+	if (pngDecoder.hasPalette()) {
 		warning("Indexed colors PNG images are not supported");
 		return false;
 	}
diff --git a/engines/supernova/graphics.cpp b/engines/supernova/graphics.cpp
index 6605d2321ac..823b98dd7a0 100644
--- a/engines/supernova/graphics.cpp
+++ b/engines/supernova/graphics.cpp
@@ -36,8 +36,7 @@
 namespace Supernova {
 
 MSNImage::MSNImage(SupernovaEngine *vm)
-	: _vm(vm) {
-	_palette = nullptr;
+	: _palette(0), _vm(vm) {
 	_encodedImage = nullptr;
 	_filenumber = -1;
 	_pitch = 0;
@@ -144,21 +143,22 @@ bool MSNImage::loadStream(Common::SeekableReadStream &stream) {
 	size *= 16;      // a paragraph is 16 bytes
 	_encodedImage = new byte[size];
 
-	_palette = new byte[717];
-	g_system->getPaletteManager()->grabPalette(_palette, 16, 239);
+	byte palette[717];
+	g_system->getPaletteManager()->grabPalette(palette, 16, 239);
+	_palette.resize(239, false);
+	_palette.set(palette, 0, 239);
 
 	byte pal_diff;
 	byte flag = stream.readByte();
 	if (flag == 0) {
 		pal_diff = 0;
-		_palette[141] = 0xE0;
-		_palette[142] = 0xE0;
-		_palette[143] = 0xE0;
+		_palette.set(47, 0xE0, 0xE0, 0xE0);
 	} else {
 		pal_diff = 1;
-		for (int i = flag * 3; i != 0; --i) {
-			_palette[717 - i] = stream.readByte() << 2;
-		}
+		byte r = stream.readByte() << 2;
+		byte g = stream.readByte() << 2;
+		byte b = stream.readByte() << 2;
+		_palette.set(239 - flag, r, g, b);
 	}
 
 	_numSections = stream.readByte();
@@ -273,10 +273,8 @@ bool MSNImage::loadSections() {
 }
 
 void MSNImage::destroy() {
-	if (_palette) {
-		delete[] _palette;
-		_palette = nullptr;
-	}
+	_palette.clear();
+
 	if (_encodedImage) {
 		delete[] _encodedImage;
 		_encodedImage = nullptr;
diff --git a/engines/supernova/graphics.h b/engines/supernova/graphics.h
index 61d6321357b..658f0941acd 100644
--- a/engines/supernova/graphics.h
+++ b/engines/supernova/graphics.h
@@ -23,6 +23,7 @@
 #define SUPERNOVA_GRAPHICS_H
 
 #include "common/scummsys.h"
+#include "graphics/palette.h"
 #include "image/image_decoder.h"
 #include "supernova/supernova.h"
 
@@ -45,7 +46,7 @@ public:
 	void destroy() override;
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	const Graphics::Surface *getSurface() const override { return _sectionSurfaces[0]; }
-	const byte *getPalette() const override { return _palette; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 	bool init(int filenumber);
 
@@ -58,7 +59,7 @@ public:
 	int _numSections;
 	int _numClickFields;
 	Common::Array<Graphics::Surface *> _sectionSurfaces;
-	byte *_palette;
+	Graphics::Palette _palette;
 	byte *_encodedImage;
 
 	struct Section {
diff --git a/engines/supernova/screen.cpp b/engines/supernova/screen.cpp
index de009f6ba28..2f20dedce75 100644
--- a/engines/supernova/screen.cpp
+++ b/engines/supernova/screen.cpp
@@ -450,7 +450,7 @@ void Screen::renderImage(int section) {
 
 bool Screen::setCurrentImage(int filenumber) {
 	_currentImage = _resMan->getImage(filenumber);
-	_vm->_system->getPaletteManager()->setPalette(_currentImage->getPalette(), 16, 239);
+	_vm->_system->getPaletteManager()->setPalette(_currentImage->getPalette().data(), 16, 239);
 	paletteBrightness();
 
 	return true;
@@ -638,8 +638,8 @@ void Screen::paletteBrightness() {
 	}
 	for (uint i = 0; i < 717; ++i) {
 		const byte *imagePalette;
-		if (_currentImage && _currentImage->getPalette()) {
-			imagePalette = _currentImage->getPalette();
+		if (_currentImage && _currentImage->hasPalette()) {
+			imagePalette = _currentImage->getPalette().data();
 		} else {
 			imagePalette = palette + 48;
 		}
diff --git a/engines/sword25/gfx/image/imgloader.cpp b/engines/sword25/gfx/image/imgloader.cpp
index 76d3eeca918..95ef37a3543 100644
--- a/engines/sword25/gfx/image/imgloader.cpp
+++ b/engines/sword25/gfx/image/imgloader.cpp
@@ -46,7 +46,7 @@ bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, Graphics:
 		error("Error while reading PNG image");
 
 	const Graphics::Surface *sourceSurface = png.getSurface();
-	Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), png.getPalette(), png.getPaletteColorCount());
+	Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), png.getPalette().data(), png.getPalette().size());
 
 	dest->copyFrom(*pngSurface);
 
diff --git a/engines/testbed/image.cpp b/engines/testbed/image.cpp
index 1326214e60d..7a56e0afdfd 100644
--- a/engines/testbed/image.cpp
+++ b/engines/testbed/image.cpp
@@ -319,9 +319,8 @@ bool ImageTests::testImageDecoder(Common::Path &filepath, Image::ImageDecoder &d
 	g_system->endGFXTransaction();
 
 	Graphics::Screen screen;
-	if (decoder.getPaletteColorCount() > 0) {
-		Graphics::Palette palette(decoder.getPalette(), decoder.getPaletteColorCount());
-		screen.simpleBlitFrom(*pSurface, &palette);
+	if (decoder.hasPalette()) {
+		screen.simpleBlitFrom(*pSurface, &decoder.getPalette());
 	} else {
 		screen.simpleBlitFrom(*pSurface);
 	}
diff --git a/engines/testbed/misc.cpp b/engines/testbed/misc.cpp
index 1c2f86e9458..6d7ef0c7cde 100644
--- a/engines/testbed/misc.cpp
+++ b/engines/testbed/misc.cpp
@@ -246,7 +246,7 @@ bool ImageAlbumImageSupplier::loadImageSlot(uint slot, const Graphics::Surface *
 	outSurface = fi._decoder->getSurface();
 	outHasPalette = fi._decoder->hasPalette();
 	if (fi._decoder->hasPalette())
-		outPalette.set(fi._decoder->getPalette(), 0, fi._decoder->getPaletteColorCount());
+		outPalette.set(fi._decoder->getPalette(), 0, fi._decoder->getPalette().size());
 	outMetadata = GUI::ImageAlbumImageMetadata();
 
 	return true;
diff --git a/engines/titanic/support/image.cpp b/engines/titanic/support/image.cpp
index 0bf7b369382..b5a58c8d3e3 100644
--- a/engines/titanic/support/image.cpp
+++ b/engines/titanic/support/image.cpp
@@ -43,8 +43,8 @@ void Image::loadBitmap(Common::SeekableReadStream &s) {
 		blitFrom(*src);
 	} else {
 		// Convert the loaded surface to the screen surface format
-		const byte *palette = decoder.getPalette();
-		Graphics::Surface *surface = src->convertTo(scrFormat, palette);
+		const Graphics::Palette &palette = decoder.getPalette();
+		Graphics::Surface *surface = src->convertTo(scrFormat, palette.data(), palette.size());
 		create(surface->w, surface->h, scrFormat);
 		blitFrom(*surface);
 
diff --git a/engines/tucker/resource.cpp b/engines/tucker/resource.cpp
index 77b0489559c..973f880ab56 100644
--- a/engines/tucker/resource.cpp
+++ b/engines/tucker/resource.cpp
@@ -323,7 +323,7 @@ void TuckerEngine::loadImage(const char *fname, uint8 *dst, int type) {
 		memcpy(dst + y * 320, pcxSurface->getBasePtr(0, y), pcxSurface->w);
 
 	if (type != 0) {
-		memcpy(_currentPalette, pcx.getPalette(), 3 * 256);
+		pcx.getPalette().grab(_currentPalette, 0, pcx.getPalette().size());
 		setBlackPalette();
 	}
 }
diff --git a/engines/twine/movies.cpp b/engines/twine/movies.cpp
index 3302f8d3d52..958216e537f 100644
--- a/engines/twine/movies.cpp
+++ b/engines/twine/movies.cpp
@@ -311,7 +311,7 @@ void Movies::prepareGIF(int index) {
 		return;
 	}
 	const Graphics::Surface *surface = decoder.getSurface();
-	_engine->setPalette(0, decoder.getPaletteColorCount(), decoder.getPalette());
+	_engine->setPalette(0, decoder.getPalette().size(), decoder.getPalette().data());
 	Graphics::ManagedSurface& target = _engine->_frontVideoBuffer;
 	const Common::Rect surfaceBounds(0, 0, surface->w, surface->h);
 	target.blitFrom(*surface, surfaceBounds, target.getBounds());
diff --git a/engines/twine/renderer/screens.cpp b/engines/twine/renderer/screens.cpp
index 7258b3cc6cd..1d801a80c93 100644
--- a/engines/twine/renderer/screens.cpp
+++ b/engines/twine/renderer/screens.cpp
@@ -124,7 +124,7 @@ static bool loadImageDelayViaDecoder(TwinEEngine *engine, const Common::Path &fi
 	}
 	Graphics::ManagedSurface &target = engine->_frontVideoBuffer;
 	Common::Rect rect(src->w, src->h);
-	if (decoder.getPaletteColorCount() == 0) {
+	if (!decoder.hasPalette()) {
 		uint8 pal[Graphics::PALETTE_SIZE];
 		engine->_frontVideoBuffer.getPalette(pal, 0, 256);
 		Graphics::Surface *source = decoder.getSurface()->convertTo(target.format, nullptr, 0, pal, 256);
@@ -132,7 +132,7 @@ static bool loadImageDelayViaDecoder(TwinEEngine *engine, const Common::Path &fi
 		source->free();
 		delete source;
 	} else {
-		engine->setPalette(0, decoder.getPaletteColorCount(), decoder.getPalette());
+		engine->setPalette(0, decoder.getPalette().size(), decoder.getPalette().data());
 		target.blitFrom(*src, rect, target.getBounds());
 	}
 	if (engine->delaySkip(1000 * seconds)) {
diff --git a/engines/twine/slideshow.cpp b/engines/twine/slideshow.cpp
index 59b8751ced0..25657732449 100644
--- a/engines/twine/slideshow.cpp
+++ b/engines/twine/slideshow.cpp
@@ -63,7 +63,7 @@ private:
 		target.blitFrom(*src);
 
 		if (decoder.hasPalette()) {
-			setPalette(decoder.getPalette(), decoder.getPaletteColorCount());
+			setPalette(decoder.getPalette().data(), decoder.getPalette().size());
 		}
 		return true;
 	}
diff --git a/engines/ultima/nuvie/misc/sdl_compat.cpp b/engines/ultima/nuvie/misc/sdl_compat.cpp
index 6fafe8406c3..517a4df00bc 100644
--- a/engines/ultima/nuvie/misc/sdl_compat.cpp
+++ b/engines/ultima/nuvie/misc/sdl_compat.cpp
@@ -72,8 +72,7 @@ Graphics::ManagedSurface *SDL_LoadBMP(const Common::Path &filename) {
 	Graphics::ManagedSurface *const screenSurface = screen->get_sdl_surface();
 	assert(screenSurface);
 	Graphics::ManagedSurface *dest = new Graphics::ManagedSurface(src->w, src->h, screenSurface->format);
-	Graphics::Palette p(decoder.getPalette(), 256);
-	dest->blitFrom(*src, &p);
+	dest->blitFrom(*src, &decoder.getPalette());
 
 	return dest;
 }
diff --git a/engines/ultima/ultima4/gfx/imageloader.cpp b/engines/ultima/ultima4/gfx/imageloader.cpp
index c5d477e4a2c..2f1c909ac86 100644
--- a/engines/ultima/ultima4/gfx/imageloader.cpp
+++ b/engines/ultima/ultima4/gfx/imageloader.cpp
@@ -28,13 +28,11 @@ namespace Ultima {
 namespace Ultima4 {
 
 /*-------------------------------------------------------------------*/
-U4ImageDecoder::U4ImageDecoder(int width, int height, int bpp) {
+U4ImageDecoder::U4ImageDecoder(int width, int height, int bpp) : _palette(0) {
 	_width = width;
 	_height = height;
 	_bpp = bpp;
 	_surface = nullptr;
-	_palette = nullptr;
-	_paletteColorCount = 0;
 }
 
 U4ImageDecoder::~U4ImageDecoder() {
@@ -48,9 +46,7 @@ void U4ImageDecoder::destroy() {
 		_surface = nullptr;
 	}
 
-	// _palette is owned by U4PaletteLoader
-	_palette = nullptr;
-	_paletteColorCount = 0;
+	_palette.clear();
 }
 
 void U4ImageDecoder::setFromRawData(const byte *rawData) {
diff --git a/engines/ultima/ultima4/gfx/imageloader.h b/engines/ultima/ultima4/gfx/imageloader.h
index 26cf12c95a4..07b9bb366fb 100644
--- a/engines/ultima/ultima4/gfx/imageloader.h
+++ b/engines/ultima/ultima4/gfx/imageloader.h
@@ -22,6 +22,7 @@
 #ifndef ULTIMA4_GFX_IMAGELOADER_H
 #define ULTIMA4_GFX_IMAGELOADER_H
 
+#include "graphics/palette.h"
 #include "graphics/pixelformat.h"
 #include "image/image_decoder.h"
 
@@ -43,13 +44,11 @@ public:
 	// ImageDecoder API
 	void destroy() override;
 	const Graphics::Surface *getSurface() const override { return _surface; }
-	const byte *getPalette() const override { return _palette; }
-	uint16 getPaletteColorCount() const override { return _paletteColorCount; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 protected:
 	Graphics::Surface *_surface;
-	const byte *_palette;
-	uint16 _paletteColorCount;
+	Graphics::Palette _palette;
 	int _width, _height, _bpp;
 
 	/**
diff --git a/engines/ultima/ultima4/gfx/imageloader_fmtowns.cpp b/engines/ultima/ultima4/gfx/imageloader_fmtowns.cpp
index 2dfb549239b..cbb277ace72 100644
--- a/engines/ultima/ultima4/gfx/imageloader_fmtowns.cpp
+++ b/engines/ultima/ultima4/gfx/imageloader_fmtowns.cpp
@@ -57,8 +57,8 @@ bool FMTOWNSImageDecoder::loadStream(Common::SeekableReadStream &stream) {
 		setFromRawData(raw);
 
 		U4PaletteLoader pal;
-		_palette = pal.loadEgaPalette();
-		_paletteColorCount = 16;
+		_palette.resize(16, false);
+		_palette.set(pal.loadEgaPalette(), 0, 16);
 	}
 
 
diff --git a/engines/ultima/ultima4/gfx/imageloader_u4.cpp b/engines/ultima/ultima4/gfx/imageloader_u4.cpp
index 932ecb8f219..457d8ddcd64 100644
--- a/engines/ultima/ultima4/gfx/imageloader_u4.cpp
+++ b/engines/ultima/ultima4/gfx/imageloader_u4.cpp
@@ -62,14 +62,14 @@ bool U4RawImageDecoder::loadStream(Common::SeekableReadStream &stream) {
 
 	U4PaletteLoader paletteLoader;
 	if (_bpp == 8) {
-		_palette = paletteLoader.loadVgaPalette();
-		_paletteColorCount = 256;
+		_palette.resize(256, false);
+		_palette.set(paletteLoader.loadVgaPalette(), 0, 256);
 	} else if (_bpp == 4) {
-		_palette = paletteLoader.loadEgaPalette();
-		_paletteColorCount = 16;
+		_palette.resize(16, false);
+		_palette.set(paletteLoader.loadEgaPalette(), 0, 16);
 	} else if (_bpp == 1) {
-		_palette = paletteLoader.loadBWPalette();
-		_paletteColorCount = 2;
+		_palette.resize(2, false);
+		_palette.set(paletteLoader.loadBWPalette(), 0, 2);
 	}
 
 	setFromRawData(raw);
@@ -109,14 +109,14 @@ bool U4RleImageDecoder::loadStream(Common::SeekableReadStream &stream) {
 
 	U4PaletteLoader paletteLoader;
 	if (_bpp == 8) {
-		_palette = paletteLoader.loadVgaPalette();
-		_paletteColorCount = 256;
+		_palette.resize(256, false);
+		_palette.set(paletteLoader.loadVgaPalette(), 0, 256);
 	} else if (_bpp == 4) {
-		_palette = paletteLoader.loadEgaPalette();
-		_paletteColorCount = 16;
+		_palette.resize(16, false);
+		_palette.set(paletteLoader.loadEgaPalette(), 0, 16);
 	} else if (_bpp == 1) {
-		_palette = paletteLoader.loadBWPalette();
-		_paletteColorCount = 2;
+		_palette.resize(2, false);
+		_palette.set(paletteLoader.loadBWPalette(), 0, 2);
 	}
 
 	setFromRawData(raw);
@@ -156,14 +156,14 @@ bool U4LzwImageDecoder::loadStream(Common::SeekableReadStream &stream) {
 
 	U4PaletteLoader paletteLoader;
 	if (_bpp == 8) {
-		_palette = paletteLoader.loadVgaPalette();
-		_paletteColorCount = 256;
+		_palette.resize(256, false);
+		_palette.set(paletteLoader.loadVgaPalette(), 0, 256);
 	} else if (_bpp == 4) {
-		_palette = paletteLoader.loadEgaPalette();
-		_paletteColorCount = 16;
+		_palette.resize(16, false);
+		_palette.set(paletteLoader.loadEgaPalette(), 0, 16);
 	} else if (_bpp == 1) {
-		_palette = paletteLoader.loadBWPalette();
-		_paletteColorCount = 2;
+		_palette.resize(2, false);
+		_palette.set(paletteLoader.loadBWPalette(), 0, 2);
 	}
 
 	setFromRawData(raw);
diff --git a/engines/ultima/ultima4/gfx/imagemgr.cpp b/engines/ultima/ultima4/gfx/imagemgr.cpp
index 2561fe89959..c052a8ee43d 100644
--- a/engines/ultima/ultima4/gfx/imagemgr.cpp
+++ b/engines/ultima/ultima4/gfx/imagemgr.cpp
@@ -565,10 +565,9 @@ ImageInfo *ImageMgr::get(const Common::String &name, bool returnUnscaled) {
 				unscaled = Image::create(surface->w, surface->h, surface->format);
 				unscaled->blitFrom(*surface);
 
-				if (decoder->hasPalette()) {
-					int palCount = decoder->getPaletteColorCount();
-					const byte *pal = decoder->getPalette();
-					unscaled->setPalette(pal, palCount);
+				const Graphics::Palette &pal = decoder->getPalette();
+				if (pal.size() > 0) {
+					unscaled->setPalette(pal.data(), pal.size());
 				}
 
 				if (info->_width == -1) {
diff --git a/engines/ultima/ultima8/gumps/cru_credits_gump.cpp b/engines/ultima/ultima8/gumps/cru_credits_gump.cpp
index 2ddc4c621bf..ff5bc8400be 100644
--- a/engines/ultima/ultima8/gumps/cru_credits_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_credits_gump.cpp
@@ -63,7 +63,7 @@ CruCreditsGump::CruCreditsGump(Common::SeekableReadStream *txtrs,
 		const Graphics::Surface *bmpsurf = decoder.getSurface();
 		Graphics::ManagedSurface ms;
 		ms.copyFrom(*bmpsurf);
-		ms.setPalette(decoder.getPalette(), 0, decoder.getPaletteColorCount());
+		ms.setPalette(decoder.getPalette().data(), 0, decoder.getPalette().size());
 		Common::Rect srcRect(640, 480);
 		_background->Blit(ms, srcRect, 0, 0);
 	} else {
diff --git a/engines/ultima/ultima8/gumps/cru_demo_gump.cpp b/engines/ultima/ultima8/gumps/cru_demo_gump.cpp
index 4a6f0676ed0..5b92bf65cea 100644
--- a/engines/ultima/ultima8/gumps/cru_demo_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_demo_gump.cpp
@@ -54,7 +54,7 @@ CruDemoGump::CruDemoGump(Common::SeekableReadStream *bmprs, uint32 flags, int32
 		const Graphics::Surface *bmpsurf = decoder.getSurface();
 		Graphics::ManagedSurface ms;
 		ms.copyFrom(*bmpsurf);
-		ms.setPalette(decoder.getPalette(), 0, decoder.getPaletteColorCount());
+		ms.setPalette(decoder.getPalette().data(), 0, decoder.getPalette().size());
 		Common::Rect srcRect(640, 480);
 		_background->Blit(ms, srcRect, 0, 0);
 	} else {
diff --git a/engines/vcruise/runtime.cpp b/engines/vcruise/runtime.cpp
index c1c52a9fbe1..d3ce191d0ca 100644
--- a/engines/vcruise/runtime.cpp
+++ b/engines/vcruise/runtime.cpp
@@ -159,7 +159,7 @@ Common::SharedPtr<Graphics::Surface> AD2044Graphics::loadGraphic(const Common::S
 
 	const Graphics::Surface *bmpSurf = decoder.getSurface();
 
-	Common::SharedPtr<Graphics::Surface> surf(bmpSurf->convertTo(_pixFmt, decoder.getPalette(), decoder.getPaletteColorCount()), Graphics::SurfaceDeleter());
+	Common::SharedPtr<Graphics::Surface> surf(bmpSurf->convertTo(_pixFmt, decoder.getPalette().data(), decoder.getPalette().size()), Graphics::SurfaceDeleter());
 	return surf;
 }
 
@@ -6194,7 +6194,7 @@ Common::SharedPtr<Graphics::ManagedSurface> Runtime::loadGraphicFromPath(const C
 	Common::SharedPtr<Graphics::ManagedSurface> surf(new Graphics::ManagedSurface());
 	if (bmpDecoder.hasPalette()) {
 		surf->copyFrom(*bmpDecoder.getSurface());
-		surf->setPalette(bmpDecoder.getPalette(), 0, bmpDecoder.getPaletteColorCount());
+		surf->setPalette(bmpDecoder.getPalette().data(), 0, bmpDecoder.getPalette().size());
 	} else {
 		surf->convertFrom(*bmpDecoder.getSurface(), _system->getScreenFormat());
 	}
diff --git a/engines/wintermute/base/gfx/base_image.cpp b/engines/wintermute/base/gfx/base_image.cpp
index 2ece650548a..dca59acb974 100644
--- a/engines/wintermute/base/gfx/base_image.cpp
+++ b/engines/wintermute/base/gfx/base_image.cpp
@@ -84,8 +84,8 @@ bool BaseImage::loadFile(const Common::String &filename) {
 
 	_decoder->loadStream(*file);
 	_surface = _decoder->getSurface();
-	_palette = _decoder->getPalette();
-	_paletteCount = _decoder->getPaletteColorCount();
+	_palette = _decoder->getPalette().data();
+	_paletteCount = _decoder->getPalette().size();
 	_fileManager->closeFile(file);
 
 	return true;
diff --git a/graphics/macgui/macwindowborder.cpp b/graphics/macgui/macwindowborder.cpp
index 07a772262ab..97633f4deb5 100644
--- a/graphics/macgui/macwindowborder.cpp
+++ b/graphics/macgui/macwindowborder.cpp
@@ -230,18 +230,14 @@ void MacWindowBorder::loadBorder(Common::SeekableReadStream &file, uint32 flags,
 
 	Graphics::ManagedSurface *surface = new Graphics::ManagedSurface();
 	surface->copyFrom(*bmpDecoder.getSurface());
-	surface->setPalette(bmpDecoder.getPalette(), 0,
-	                    bmpDecoder.getPaletteColorCount());
+	surface->setPalette(bmpDecoder.getPalette().data(), 0,
+	                    bmpDecoder.getPalette().size());
 
 	if (surface->format.isCLUT8()) {
-		const byte *palette = bmpDecoder.getPalette();
-		for (int i = 0; i < bmpDecoder.getPaletteColorCount(); i++) {
-			if (palette[0] == 255 && palette[1] == 0 && palette[2] == 255) {
-				surface->setTransparentColor(i);
-				break;
-			}
-			palette += 3;
-		}
+		const Graphics::Palette &palette = bmpDecoder.getPalette();
+		uint i = palette.find(255, 0, 255);
+		if (i < palette.size())
+			surface->setTransparentColor(i);
 	} else {
 		const Graphics::PixelFormat requiredFormat_4byte(4, 8, 8, 8, 8, 24, 16, 8, 0);
 		surface->convertToInPlace(requiredFormat_4byte);
diff --git a/graphics/macgui/macwindowmanager.cpp b/graphics/macgui/macwindowmanager.cpp
index e610d1245a5..c27d02c1707 100644
--- a/graphics/macgui/macwindowmanager.cpp
+++ b/graphics/macgui/macwindowmanager.cpp
@@ -868,7 +868,7 @@ void MacWindowManager::loadDesktop() {
 	bmpDecoder.loadStream(*file);
 
 	const Graphics::PixelFormat requiredFormat_4byte(4, 8, 8, 8, 8, 24, 16, 8, 0);
-	_desktopBmp = bmpDecoder.getSurface()->convertTo(requiredFormat_4byte, bmpDecoder.getPalette());
+	_desktopBmp = bmpDecoder.getSurface()->convertTo(requiredFormat_4byte, bmpDecoder.getPalette().data(), bmpDecoder.getPalette().size());
 
 	delete file;
 }
diff --git a/image/bmp.h b/image/bmp.h
index 2614935012c..206b3ab4153 100644
--- a/image/bmp.h
+++ b/image/bmp.h
@@ -74,9 +74,8 @@ public:
 	// ImageDecoder API
 	void destroy();
 	virtual bool loadStream(Common::SeekableReadStream &stream);
-	virtual const Graphics::Surface *getSurface() const { return _surface; }
-	const byte *getPalette() const { return _palette.data(); }
-	uint16 getPaletteColorCount() const { return _palette.size(); }
+	const Graphics::Surface *getSurface() const override { return _surface; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 private:
 	Codec *_codec;
diff --git a/image/cel_3do.h b/image/cel_3do.h
index 7afc7698579..5f507c53b2e 100644
--- a/image/cel_3do.h
+++ b/image/cel_3do.h
@@ -56,9 +56,8 @@ public:
 	// ImageDecoder API
 	void destroy();
 	virtual bool loadStream(Common::SeekableReadStream &stream);
-	virtual const Graphics::Surface *getSurface() const { return _surface; }
-	const byte *getPalette() const { return _palette.data(); }
-	uint16 getPaletteColorCount() const { return _palette.size(); }
+	const Graphics::Surface *getSurface() const override { return _surface; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 private:
 	const Graphics::Surface *_surface;
diff --git a/image/cicn.h b/image/cicn.h
index 70c3a1ad7ca..3bfd9a75051 100644
--- a/image/cicn.h
+++ b/image/cicn.h
@@ -47,8 +47,7 @@ public:
 	void destroy() override;
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	const Graphics::Surface *getSurface() const override { return _surface; }
-	const byte *getPalette() const override { return _palette.data(); }
-	uint16 getPaletteColorCount() const override { return _palette.size(); }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	const Graphics::Surface *getMask() const override { return _mask; }
 
 private:
diff --git a/image/gif.h b/image/gif.h
index b569262f180..ce196bd4e02 100644
--- a/image/gif.h
+++ b/image/gif.h
@@ -56,8 +56,7 @@ public:
 
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	void destroy() override;
-	const byte *getPalette() const override { return _palette.data(); }
-	uint16 getPaletteColorCount() const override { return _palette.size(); }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	const Graphics::Surface *getSurface() const override { return _outputSurface; }
 	bool hasTransparentColor() const override { return _hasTransparentColor; }
 	uint32 getTransparentColor() const override { return _transparentColor; }
diff --git a/image/iff.h b/image/iff.h
index 0b1a821b928..56d4c60e2ad 100644
--- a/image/iff.h
+++ b/image/iff.h
@@ -85,10 +85,9 @@ public:
 	void destroy();
 	bool loadStream(Common::SeekableReadStream &stream);
 	const Header *getHeader() const { return &_header; }
-	const Graphics::Surface *getSurface() const { return _surface; }
-	const byte *getPalette() const { return _palette.data(); }
+	const Graphics::Surface *getSurface() const override { return _surface; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	const Common::Array<PaletteRange> &getPaletteRanges() const { return _paletteRanges; }
-	uint16 getPaletteColorCount() const { return _palette.size(); }
 
 	/**
 	* The number of planes to decode, also determines the pixel packing if _packPixels is true.
diff --git a/image/image_decoder.h b/image/image_decoder.h
index 9cf74bfdce6..13e1edda795 100644
--- a/image/image_decoder.h
+++ b/image/image_decoder.h
@@ -24,6 +24,7 @@
 
 #include "common/scummsys.h"
 #include "common/str.h"
+#include "graphics/palette.h"
 
 namespace Common {
 class SeekableReadStream;
@@ -94,20 +95,14 @@ public:
 	 * until destroy() or loadStream() is called, or until the destructor of
 	 * this ImageDecoder is called.
 	 *
-	 * The format of the palette is the same as that of the PaletteManager's palette.
-	 * (interleaved RGB values).
-	 *
-	 * @return The decoded palette, or undefined if no palette is present.
+	 * @return The decoded palette, or empty if no palette is present.
 	 */
-	virtual const byte *getPalette() const { return 0; }
+	virtual const Graphics::Palette &getPalette() const = 0;
 
 	/**
 	 * Query whether the decoded image has a palette.
 	 */
-	virtual bool hasPalette() const { return getPaletteColorCount() != 0; }
-
-	/** Return the number of colors in the palette. */
-	virtual uint16 getPaletteColorCount() const { return 0; }
+	virtual bool hasPalette() const { return getPalette().size() != 0; }
 
 	/** Query whether the decoded image has a transparent color. */
 	virtual bool hasTransparentColor() const { return false; }
diff --git a/image/jpeg.cpp b/image/jpeg.cpp
index b02dd260828..be9c688bf23 100644
--- a/image/jpeg.cpp
+++ b/image/jpeg.cpp
@@ -46,6 +46,7 @@ namespace Image {
 
 JPEGDecoder::JPEGDecoder() :
 		_surface(),
+		_palette(0),
 		_colorSpace(kColorSpaceRGB),
 		_accuracy(CodecAccuracy::Default),
 		_requestedPixelFormat(getByteOrderRgbPixelFormat()) {
diff --git a/image/jpeg.h b/image/jpeg.h
index c59cb8786f3..912bde9a48b 100644
--- a/image/jpeg.h
+++ b/image/jpeg.h
@@ -22,6 +22,7 @@
 #ifndef IMAGE_JPEG_H
 #define IMAGE_JPEG_H
 
+#include "graphics/palette.h"
 #include "graphics/surface.h"
 #include "image/image_decoder.h"
 #include "image/codecs/codec.h"
@@ -55,6 +56,7 @@ public:
 	void destroy() override;
 	bool loadStream(Common::SeekableReadStream &str) override;
 	const Graphics::Surface *getSurface() const override;
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 	// Codec API
 	const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream) override;
@@ -104,6 +106,7 @@ public:
 
 private:
 	Graphics::Surface _surface;
+	Graphics::Palette _palette;
 	ColorSpace _colorSpace;
 	Graphics::PixelFormat _requestedPixelFormat;
 	CodecAccuracy _accuracy;
diff --git a/image/neo.cpp b/image/neo.cpp
index 04a182a4e23..13ec3c8cadf 100644
--- a/image/neo.cpp
+++ b/image/neo.cpp
@@ -28,11 +28,12 @@
 
 namespace Image {
 
-NeoDecoder::NeoDecoder(byte *palette) {
+NeoDecoder::NeoDecoder(byte *palette) : _palette(0) {
 	_surface = nullptr;
-	_paletteDestroy = palette ? false : true;
-	_palette = palette;
-	_paletteColorCount = 0;
+	if (palette) {
+		_palette.resize(16, false);
+		_palette.set(palette, 0, 16);
+	}
 }
 
 NeoDecoder::~NeoDecoder() {
@@ -46,17 +47,13 @@ void NeoDecoder::destroy() {
 		_surface = nullptr;
 	}
 
-	if (_paletteDestroy) {
-		delete[] _palette;
-		_palette = nullptr;
-	}
-	_paletteColorCount = 0;
+	_palette.clear();
 }
 
 bool NeoDecoder::loadStream(Common::SeekableReadStream &stream) {
 	destroy();
 
-	if (!_palette) {
+	if (_palette.size() == 0) {
 		int start = stream.pos();
 
 		if (stream.readUint16LE() != 0x00)
@@ -65,14 +62,15 @@ bool NeoDecoder::loadStream(Common::SeekableReadStream &stream) {
 		if (stream.readUint16LE() != 0x00)
 			warning("Header check failed for reading neo image");
 
-		_palette = new byte[16 * 3];
+		_palette.resize(16, false);
 		for (int i = 0; i < 16; ++i) {
 			byte v1 = stream.readByte();
 			byte v2 = stream.readByte();
 
-			_palette[i * 3 + 0] = floor((v1 & 0x07) * 255.0 / 7.0);
-			_palette[i * 3 + 1] = floor((v2 & 0x70) * 255.0 / 7.0 / 16.0);
-			_palette[i * 3 + 2] = floor((v2 & 0x07) * 255.0 / 7.0);
+			byte r = floor((v1 & 0x07) * 255.0 / 7.0);
+			byte g = floor((v2 & 0x70) * 255.0 / 7.0 / 16.0);
+			byte b = floor((v2 & 0x07) * 255.0 / 7.0);
+			_palette.set(i, r, g, b);
 		}
 
 		stream.seek(start + 128);
@@ -82,7 +80,6 @@ bool NeoDecoder::loadStream(Common::SeekableReadStream &stream) {
 	int height = 200;
 	_surface = new Graphics::Surface();
 	_surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
-	_paletteColorCount = 16;
 
 	// 200 rows of image:
 	for (int y = 0; y < 200; y++) {
diff --git a/image/neo.h b/image/neo.h
index 60db4154338..850681c4c95 100644
--- a/image/neo.h
+++ b/image/neo.h
@@ -22,6 +22,7 @@
 #ifndef IMAGE_NEO_H
 #define IMAGE_NEO_H
 
+#include "graphics/palette.h"
 #include "image/image_decoder.h"
 
 /**
@@ -51,14 +52,12 @@ public:
 	void destroy();
 	virtual bool loadStream(Common::SeekableReadStream &stream);
 	virtual const Graphics::Surface *getSurface() const { return _surface; }
-	const byte *getPalette() const { return _palette; }
-	uint16 getPaletteColorCount() const { return _paletteColorCount; }
+	const Graphics::Palette &getPalette() const { return _palette; }
+	uint16 getPaletteColorCount() const { return _palette.size(); }
 
 private:
 	Graphics::Surface *_surface;
-	bool _paletteDestroy;
-	byte *_palette;
-	uint16 _paletteColorCount;
+	Graphics::Palette _palette;
 };
 } // End of namespace Image
 
diff --git a/image/pcx.h b/image/pcx.h
index 951d5d8e584..42c7e1c21cd 100644
--- a/image/pcx.h
+++ b/image/pcx.h
@@ -56,9 +56,8 @@ public:
 	// ImageDecoder API
 	void destroy();
 	virtual bool loadStream(Common::SeekableReadStream &stream);
-	virtual const Graphics::Surface *getSurface() const { return _surface; }
-	const byte *getPalette() const { return _palette.data(); }
-	uint16 getPaletteColorCount() const { return _palette.size(); }
+	const Graphics::Surface *getSurface() const override { return _surface; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 private:
 	void decodeRLE(Common::SeekableReadStream &stream, byte *dst, uint32 bytesPerScanline, bool compressed);
diff --git a/image/pict.h b/image/pict.h
index 13fb07c278e..8f4c95c1b05 100644
--- a/image/pict.h
+++ b/image/pict.h
@@ -62,10 +62,8 @@ public:
 	// ImageDecoder API
 	bool loadStream(Common::SeekableReadStream &stream);
 	void destroy();
-	const Graphics::Surface *getSurface() const { return _outputSurface; }
-	const byte *getPalette() const { return _palette.data(); }
-	int getPaletteSize() const { return 256; }
-	uint16 getPaletteColorCount() const { return _palette.size(); }
+	const Graphics::Surface *getSurface() const override { return _outputSurface; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 	struct PixMap {
 		uint32 baseAddr;
diff --git a/image/png.h b/image/png.h
index 8bdb0503a81..460bd40d1fe 100644
--- a/image/png.h
+++ b/image/png.h
@@ -62,8 +62,7 @@ public:
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	void destroy() override;
 	const Graphics::Surface *getSurface() const override { return _outputSurface; }
-	const byte *getPalette() const override { return _palette.data(); }
-	uint16 getPaletteColorCount() const override { return _palette.size(); }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 	bool hasTransparentColor() const override { return _hasTransparentColor; }
 	uint32 getTransparentColor() const override { return _transparentColor; }
 	void setSkipSignature(bool skip) { _skipSignature = skip; }
diff --git a/image/scr.cpp b/image/scr.cpp
index 84b336ec352..360d0827b52 100644
--- a/image/scr.cpp
+++ b/image/scr.cpp
@@ -28,8 +28,7 @@
 
 namespace Image {
 
-ScrDecoder::ScrDecoder() {
-	_surface = nullptr;
+ScrDecoder::ScrDecoder() : _surface(nullptr), _palette(0) {
 }
 
 ScrDecoder::~ScrDecoder() {
diff --git a/image/scr.h b/image/scr.h
index 6c4799598d7..50d12d465fd 100644
--- a/image/scr.h
+++ b/image/scr.h
@@ -22,6 +22,7 @@
 #ifndef IMAGE_SCR_H
 #define IMAGE_SCR_H
 
+#include "graphics/palette.h"
 #include "image/image_decoder.h"
 
 /**
@@ -52,8 +53,10 @@ public:
 	void destroy();
 	virtual bool loadStream(Common::SeekableReadStream &stream);
 	virtual const Graphics::Surface *getSurface() const { return _surface; }
+	const Graphics::Palette &getPalette() const { return _palette; }
 private:
 	Graphics::Surface *_surface;
+	Graphics::Palette _palette;
 	uint32 getPixelAddress(int x, int y);
 	uint32 getAttributeAddress(int x, int y);
 };
diff --git a/image/tga.h b/image/tga.h
index e6ecf9aeda6..f99f00465d7 100644
--- a/image/tga.h
+++ b/image/tga.h
@@ -68,9 +68,8 @@ public:
 	TGADecoder();
 	virtual ~TGADecoder();
 	virtual void destroy();
-	virtual const Graphics::Surface *getSurface() const { return &_surface; }
-	virtual const byte *getPalette() const { return _colorMap.data(); }
-	virtual uint16 getPaletteColorCount() const { return _colorMap.size(); }
+	const Graphics::Surface *getSurface() const override { return &_surface; }
+	const Graphics::Palette &getPalette() const override { return _colorMap; }
 	virtual bool loadStream(Common::SeekableReadStream &stream);
 private:
 	// Format-spec from:
diff --git a/image/xbm.cpp b/image/xbm.cpp
index c67e3986eb6..2304f448ded 100644
--- a/image/xbm.cpp
+++ b/image/xbm.cpp
@@ -27,13 +27,12 @@
 
 namespace Image {
 
-const byte XBMDecoder::_palette[2 * 3] = {
+static const byte xbmPalette[2 * 3] = {
 	0xFF, 0xFF, 0xFF,
 	0x00, 0x00, 0x00
 };
 
-XBMDecoder::XBMDecoder() {
-	_surface = 0;
+XBMDecoder::XBMDecoder() : _surface(nullptr), _palette(xbmPalette, 2) {
 }
 
 XBMDecoder::~XBMDecoder() {
diff --git a/image/xbm.h b/image/xbm.h
index 44e3955d2be..c83bb063bd8 100644
--- a/image/xbm.h
+++ b/image/xbm.h
@@ -22,6 +22,7 @@
 #ifndef IMAGE_XBM_H
 #define IMAGE_XBM_H
 
+#include "graphics/palette.h"
 #include "image/image_decoder.h"
 
 namespace Image {
@@ -46,8 +47,7 @@ public:
 	void destroy() override;
 	bool loadStream(Common::SeekableReadStream &stream) override;
 	const Graphics::Surface *getSurface() const override { return _surface; }
-	const byte *getPalette() const override { return _palette; }
-	uint16 getPaletteColorCount() const override { return 2; }
+	const Graphics::Palette &getPalette() const override { return _palette; }
 
 	/**
 	 * Load an image from an embedded XBM file.
@@ -67,7 +67,7 @@ public:
 
 private:
 	Graphics::Surface *_surface;
-	static const byte _palette[2 * 3];
+	Graphics::Palette _palette;
 };
 
 /** @} */


Commit: 1b58e6dd9079680020ad76a66aad20c549262a09
    https://github.com/scummvm/scummvm/commit/1b58e6dd9079680020ad76a66aad20c549262a09
Author: Matthew Jimenez (matthew.jimenez at outlook.com)
Date: 2025-04-12T15:47:17+03:00

Commit Message:
GRAPHICS: Add method to check empty for Palette

Changed paths:
    engines/glk/debugger.cpp
    engines/ultima/ultima4/gfx/imagemgr.cpp
    graphics/palette.h
    image/image_decoder.h
    image/neo.cpp


diff --git a/engines/glk/debugger.cpp b/engines/glk/debugger.cpp
index 996e47e9fd5..85941d25e72 100644
--- a/engines/glk/debugger.cpp
+++ b/engines/glk/debugger.cpp
@@ -108,7 +108,7 @@ void Debugger::saveRawPicture(const RawDecoder &rd, Common::WriteStream &ws) {
 	uint32 transColor = rd.getTransparentColor();
 
 	// If the image doesn't have a palette, we can directly write out the image
-	if (palette.size() == 0) {
+	if (palette.empty()) {
 		Image::writePNG(ws, *surface);
 		return;
 	}
diff --git a/engines/ultima/ultima4/gfx/imagemgr.cpp b/engines/ultima/ultima4/gfx/imagemgr.cpp
index c052a8ee43d..e37b31b1ac7 100644
--- a/engines/ultima/ultima4/gfx/imagemgr.cpp
+++ b/engines/ultima/ultima4/gfx/imagemgr.cpp
@@ -566,7 +566,7 @@ ImageInfo *ImageMgr::get(const Common::String &name, bool returnUnscaled) {
 				unscaled->blitFrom(*surface);
 
 				const Graphics::Palette &pal = decoder->getPalette();
-				if (pal.size() > 0) {
+				if (!pal.empty()) {
 					unscaled->setPalette(pal.data(), pal.size());
 				}
 
diff --git a/graphics/palette.h b/graphics/palette.h
index 90e6323e4a1..e63299c7d52 100644
--- a/graphics/palette.h
+++ b/graphics/palette.h
@@ -95,6 +95,11 @@ public:
 	 */
 	void clear();
 
+	/**
+	 * Check whether the palette is empty.
+	 */
+	bool empty() const { return _size == 0; }
+
 	/**
 	 * Changes the number of palette entries.
 	 * 
diff --git a/image/image_decoder.h b/image/image_decoder.h
index 13e1edda795..c973c9f5ca9 100644
--- a/image/image_decoder.h
+++ b/image/image_decoder.h
@@ -102,7 +102,7 @@ public:
 	/**
 	 * Query whether the decoded image has a palette.
 	 */
-	virtual bool hasPalette() const { return getPalette().size() != 0; }
+	virtual bool hasPalette() const { return !getPalette().empty(); }
 
 	/** Query whether the decoded image has a transparent color. */
 	virtual bool hasTransparentColor() const { return false; }
diff --git a/image/neo.cpp b/image/neo.cpp
index 13ec3c8cadf..51fd1710bc0 100644
--- a/image/neo.cpp
+++ b/image/neo.cpp
@@ -53,7 +53,7 @@ void NeoDecoder::destroy() {
 bool NeoDecoder::loadStream(Common::SeekableReadStream &stream) {
 	destroy();
 
-	if (_palette.size() == 0) {
+	if (_palette.empty()) {
 		int start = stream.pos();
 
 		if (stream.readUint16LE() != 0x00)




More information about the Scummvm-git-logs mailing list