Mercurial > foo_out_sdl
diff foosdk/sdk/libPPUI/ImageEncoder.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/ImageEncoder.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,157 @@ +#include "stdafx.h" +#include "ImageEncoder.h" +#include "gdiplus_helpers.h" +#include <memory> +#include <vector> + +using namespace Gdiplus; +static GdiplusErrorHandler EH; + +int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) +{ + UINT num = 0; // number of image encoders + UINT size = 0; // size of the image encoder array in bytes + + ImageCodecInfo* pImageCodecInfo = NULL; + + GetImageEncodersSize(&num, &size); + if(size == 0) + return -1; // Failure + + pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); + if(pImageCodecInfo == NULL) + return -1; // Failure + + GetImageEncoders(num, size, pImageCodecInfo); + + for(UINT j = 0; j < num; ++j) + { + if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) + { + *pClsid = pImageCodecInfo[j].Clsid; + free(pImageCodecInfo); + return j; // Success + } + } + + free(pImageCodecInfo); + return -1; // Failure +} + +void ConvertImage(const TCHAR * in, const TCHAR * out, const TCHAR * format, ULONG quality) { + GdiplusScope scope; + Bitmap image (in); + EH << image.GetLastStatus(); + SaveImage(&image, out, format, quality); +} + +static void add16clip(uint16_t& v, int d) { + int v2 = (int) v + d; + if ( v2 < 0 ) v2 = 0; + if ( v2 > (int) UINT16_MAX ) v2 = UINT16_MAX; + v = (uint16_t) v2; +} + +std::unique_ptr<Gdiplus::Bitmap> image16bpcto8(Gdiplus::Bitmap* img) { + + const unsigned channels = [img] { + switch (img->GetPixelFormat()) { + case PixelFormat48bppRGB: + return 3; + case PixelFormat16bppGrayScale: + return 1; + default: + throw std::runtime_error("Invalid pixel format"); + } + } (); + + + const unsigned Width = img->GetWidth(); + const unsigned Height = img->GetHeight(); + + if ( Width == 0 || Height == 0 ) throw std::runtime_error("Invalid dimensions"); + + std::unique_ptr< Gdiplus::Bitmap > ret ( new Gdiplus::Bitmap( Width, Height, channels == 3 ? PixelFormat24bppRGB : PixelFormat8bppIndexed ) ); + + + Gdiplus::Rect rcWhole = {}; + rcWhole.Width = Width; rcWhole.Height = Height; + Gdiplus::BitmapData dataIn, dataOut; + EH << ret->LockBits( &rcWhole, ImageLockModeWrite, PixelFormat24bppRGB, &dataOut); + EH << img->LockBits(&rcWhole, ImageLockModeRead, PixelFormat48bppRGB, &dataIn); + + + + + const uint8_t * inLine = (const uint8_t*)dataIn.Scan0; + uint8_t * outLine = (uint8_t*)dataOut.Scan0; + + std::vector<uint16_t> curLineBuf, nextLineBuf; + curLineBuf.resize( (Width + 2) * channels ); + nextLineBuf.resize( (Width + 2) * channels ); + + memcpy(&nextLineBuf[channels], inLine, Width * channels * 2 ); + + for (unsigned y = 0; y < Height; ++y) { + std::swap( curLineBuf, nextLineBuf ); + if (y + 1 < Height) { + inLine += dataIn.Stride; + memcpy(&nextLineBuf[channels], inLine, Width * channels * 2 ); + } + + auto & inPix = curLineBuf; + auto & inPixNext = nextLineBuf; + size_t inOffset = channels; + uint8_t * outPix = outLine; + for (unsigned x = 0; x < Width; ++x) { + for (int c = 0; c < (int)channels; ++c) { + uint16_t orig = inPix[inOffset]; + uint16_t v8 = orig >> 8; + uint16_t v16 = v8 | (v8 << 8); + + outPix[c] = (uint8_t) v8; + + int d = (int) orig - (int) v16; + + add16clip(inPix [inOffset + channels], d * 7 / 16 ); // x+1 + add16clip(inPixNext[inOffset - channels], d * 3 / 16 ); // x-1, y+1 + add16clip(inPixNext[inOffset ], d * 5 / 16 ); // y+1 + add16clip(inPixNext[inOffset + channels], d * 1 / 16 ); // x+1, y+1 + + ++ inOffset; + } + + outPix += channels; + } + + outLine += dataOut.Stride; + } + + EH << img->UnlockBits(&dataIn); + EH << ret->UnlockBits(&dataOut); + + return ret; +} + +void SaveImage(Gdiplus::Image* bmp, const TCHAR* out, const TCHAR* format, ULONG quality) { + if (bmp->GetType() != Gdiplus::ImageTypeBitmap) throw std::runtime_error("Bitmap expected"); + SaveImage(static_cast<Gdiplus::Bitmap*>(bmp), out, format, quality); +} +void SaveImage(Gdiplus::Bitmap* image, const TCHAR* out, const TCHAR* format, ULONG quality) { + CLSID encoderClsid; + EncoderParameters encoderParameters; + + if (GetEncoderClsid(format, &encoderClsid) < 0) throw std::runtime_error("Encoder not found"); + + if (_tcscmp(format, _T("image/jpeg")) == 0) { + encoderParameters.Count = 1; + encoderParameters.Parameter[0].Guid = EncoderQuality; + encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong; + encoderParameters.Parameter[0].NumberOfValues = 1; + encoderParameters.Parameter[0].Value = &quality; + + EH << image->Save(out, &encoderClsid, &encoderParameters); + } else { + EH << image->Save(out, &encoderClsid, NULL); + } +}
