diff foosdk/sdk/libPPUI/gdiplus_helpers.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/foosdk/sdk/libPPUI/gdiplus_helpers.cpp	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,224 @@
+#include "stdafx.h"
+#include "gdiplus_helpers.h"
+
+static bool _Once() {
+	ULONG_PTR token = 0;
+	Gdiplus::GdiplusStartupInput input;
+	Gdiplus::GdiplusStartupOutput output;
+	GdiplusErrorHandler() << Gdiplus::GdiplusStartup(&token, &input, &output);
+	return true;
+}
+
+void GdiplusScope::Once() {
+	static bool done = _Once();
+	(void)done; // suppress warning
+}
+
+void GdiplusErrorHandler::Handle(Gdiplus::Status p_code) {
+	if (p_code != Gdiplus::Ok) {
+		switch (p_code) {
+		case Gdiplus::InvalidParameter:
+			throw pfc::exception_invalid_params();
+		default:
+			throw std::runtime_error(pfc::format("Gdiplus error (", (unsigned)p_code, ")"));
+		}
+		
+	}
+}
+
+HBITMAP GdiplusLoadBitmap(UINT id, const TCHAR* resType, CSize size) {
+	using namespace Gdiplus;
+	try {
+		auto stream = WinLoadResourceAsStream(GetThisModuleHandle(), MAKEINTRESOURCE(id), resType);
+
+		GdiplusErrorHandler EH;
+		Image source ( stream );
+		EH << source.GetLastStatus();
+
+		Bitmap resized (size.cx, size.cy, PixelFormat32bppARGB);
+		EH << resized.GetLastStatus();
+
+		{
+			Graphics target(&resized);
+			EH << target.GetLastStatus();
+			EH << target.SetInterpolationMode(InterpolationModeHighQuality);
+			EH << target.Clear(Color(0, 0, 0, 0));
+			EH << target.DrawImage(&source, Rect(0, 0, size.cx, size.cy));
+		}
+
+		HBITMAP bmp = NULL;
+		EH << resized.GetHBITMAP(Gdiplus::Color::White, &bmp);
+		return bmp;
+	} catch (...) {
+		PFC_ASSERT(!"Should not get here");
+		return NULL;
+	}
+}
+
+std::unique_ptr<Gdiplus::Image> GdiplusImageFromMem(const void* ptr, size_t bytes) {
+	using namespace Gdiplus;
+	GdiplusErrorHandler EH;
+
+	CComPtr<IStream> stream;
+	stream.p = SHCreateMemStream((const BYTE*)ptr, pfc::downcast_guarded<UINT>(bytes));
+	if (!stream) throw std::bad_alloc();
+	std::unique_ptr<Image> source ( new Image(stream.p) );
+	EH << source->GetLastStatus();
+	return source;
+}
+
+std::unique_ptr< Gdiplus::Bitmap > GdiplusResizeImage(Gdiplus::Image* source, CSize size, Gdiplus::PixelFormat pf) {
+	PFC_ASSERT(size.cx > 0 && size.cy > 0);
+	using namespace Gdiplus;
+	GdiplusErrorHandler EH;
+	std::unique_ptr<Bitmap> resized ( new Bitmap(size.cx, size.cy, pf) );
+	EH << resized->GetLastStatus();
+	Graphics target (resized.get() );
+	EH << target.GetLastStatus();
+	EH << target.SetInterpolationMode(InterpolationModeHighQuality);
+	EH << target.Clear(Color(0, 0, 0, 0));
+	EH << target.DrawImage(source, Rect(0, 0, size.cx, size.cy));
+	return resized;
+}
+
+HICON GdiplusLoadIconFromMem(const void* ptr, size_t bytes, CSize size) {
+	using namespace Gdiplus;
+	try {
+
+		GdiplusErrorHandler EH;
+		auto source = GdiplusImageFromMem(ptr, bytes);
+		auto resized = GdiplusResizeImage(source.get(), size);
+		HICON icon = NULL;
+		EH << resized->GetHICON(&icon);
+		return icon;
+	} catch (...) {
+		PFC_ASSERT(!"Should not get here");
+		return NULL;
+	}
+}
+
+HICON GdiplusLoadIcon(UINT id, const TCHAR* resType, CSize size) {
+	GdiplusIconArg_t arg = { size };
+	return GdiplusLoadIconEx(id, resType, arg);
+}
+
+HICON GdiplusLoadIconEx(UINT id, const TCHAR* resType, GdiplusIconArg_t const& arg) {
+	using namespace Gdiplus;
+	try {
+		auto stream = WinLoadResourceAsStream(GetThisModuleHandle(), MAKEINTRESOURCE(id), resType);
+
+		GdiplusErrorHandler EH;
+
+		Bitmap resized(arg.size.cx, arg.size.cy, PixelFormat32bppARGB);
+		EH << resized.GetLastStatus();
+		
+		{
+			Image source(stream);
+			EH << source.GetLastStatus();
+
+			Graphics target(&resized);
+			EH << target.GetLastStatus();
+			EH << target.SetInterpolationMode(InterpolationModeHighQuality);
+			EH << target.Clear(Color(0, 0, 0, 0));
+			EH << target.DrawImage(&source, Rect(0, 0, arg.size.cx, arg.size.cy));
+		}
+
+
+		if (arg.transform) arg.transform(&resized);
+
+		HICON icon = NULL;
+		EH << resized.GetHICON(&icon);
+		return icon;
+	} catch (...) {
+		PFC_ASSERT(!"Should not get here");
+		return NULL;
+	}
+}
+
+HICON GdiplusLoadPNGIcon(UINT id, CSize size) { 
+	return GdiplusLoadIcon(id, _T("PNG"), size); 
+}
+
+HICON LoadPNGIcon(UINT id, CSize size) {
+	GdiplusScope scope;
+	return GdiplusLoadPNGIcon(id, size);
+}
+
+void GdiplusLoadButtonPNG(CIcon& icon, HWND btn_, UINT image, GdiplusBitmapTransform_t transform) {
+	CButton btn(btn_);
+	if (icon == NULL) {
+		CRect client; WIN32_OP_D(btn.GetClientRect(client));
+		CSize size = client.Size();
+		int v = MulDiv(pfc::min_t<int>(size.cx, size.cy), 3, 4);
+		if (v < 8) v = 8;
+
+		GdiplusIconArg_t arg;
+		arg.size = CSize(v, v);
+		arg.transform = transform;
+		icon = GdiplusLoadIconEx(image, L"PNG", arg);
+	}
+	btn.SetIcon(icon);
+}
+
+std::unique_ptr<Gdiplus::Bitmap> GdiplusLoadResource(UINT id, const TCHAR* resType) {
+	using namespace Gdiplus;
+	GdiplusErrorHandler EH;
+
+	auto stream = WinLoadResourceAsStream(GetThisModuleHandle(), MAKEINTRESOURCE(id), resType);
+
+	std::unique_ptr<Bitmap> img ( new Bitmap(stream) );
+	EH << img->GetLastStatus();
+	return img;
+}
+
+std::unique_ptr<Gdiplus::Bitmap> GdiplusLoadResourceAsSize(UINT id, const TCHAR* resType, CSize size) {
+	auto source = GdiplusLoadResource(id, resType);
+	return GdiplusResizeImage(source.get(), size);
+}
+
+void GdiplusDimImage(Gdiplus::Bitmap* bmp) {
+	using namespace Gdiplus;
+	GdiplusErrorHandler EH;
+	Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight());
+	BitmapData data = {};
+	EH << bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat32bppARGB, &data);
+
+	BYTE* scan = (BYTE*)data.Scan0;
+	for (UINT y = 0; y < data.Height; ++y) {
+		BYTE* px = scan;
+		for (UINT x = 0; x < data.Width; ++x) {
+			//px[0] = _dimPixel(px[0]);
+			//px[1] = _dimPixel(px[1]);
+			//px[2] = _dimPixel(px[2]);
+			px[3] /= 3;
+			px += 4;
+		}
+		scan += data.Stride;
+	}
+
+	EH << bmp->UnlockBits(&data);
+}
+
+void GdiplusInvertImage(Gdiplus::Bitmap* bmp) {
+	using namespace Gdiplus;
+	GdiplusErrorHandler EH;
+	Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight());
+	BitmapData data = {};
+	EH << bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat32bppARGB, &data);
+
+	BYTE* scan = (BYTE*)data.Scan0;
+	for (UINT y = 0; y < data.Height; ++y) {
+		BYTE* px = scan;
+		for (UINT x = 0; x < data.Width; ++x) {
+			unsigned v = (unsigned)px[0] + (unsigned)px[1] + (unsigned)px[2];
+			v /= 3;
+			px[0] = px[1] = px[2] = (BYTE)(255 - v);
+			px += 4;
+		}
+		scan += data.Stride;
+	}
+
+	EH << bmp->UnlockBits(&data);
+}
+
+#pragma comment(lib, "gdiplus.lib")