Mercurial > foo_out_sdl
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 1 #include "stdafx.h" | |
| 2 #include "ImageEncoder.h" | |
| 3 #include "gdiplus_helpers.h" | |
| 4 #include <memory> | |
| 5 #include <vector> | |
| 6 | |
| 7 using namespace Gdiplus; | |
| 8 static GdiplusErrorHandler EH; | |
| 9 | |
| 10 int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) | |
| 11 { | |
| 12 UINT num = 0; // number of image encoders | |
| 13 UINT size = 0; // size of the image encoder array in bytes | |
| 14 | |
| 15 ImageCodecInfo* pImageCodecInfo = NULL; | |
| 16 | |
| 17 GetImageEncodersSize(&num, &size); | |
| 18 if(size == 0) | |
| 19 return -1; // Failure | |
| 20 | |
| 21 pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); | |
| 22 if(pImageCodecInfo == NULL) | |
| 23 return -1; // Failure | |
| 24 | |
| 25 GetImageEncoders(num, size, pImageCodecInfo); | |
| 26 | |
| 27 for(UINT j = 0; j < num; ++j) | |
| 28 { | |
| 29 if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) | |
| 30 { | |
| 31 *pClsid = pImageCodecInfo[j].Clsid; | |
| 32 free(pImageCodecInfo); | |
| 33 return j; // Success | |
| 34 } | |
| 35 } | |
| 36 | |
| 37 free(pImageCodecInfo); | |
| 38 return -1; // Failure | |
| 39 } | |
| 40 | |
| 41 void ConvertImage(const TCHAR * in, const TCHAR * out, const TCHAR * format, ULONG quality) { | |
| 42 GdiplusScope scope; | |
| 43 Bitmap image (in); | |
| 44 EH << image.GetLastStatus(); | |
| 45 SaveImage(&image, out, format, quality); | |
| 46 } | |
| 47 | |
| 48 static void add16clip(uint16_t& v, int d) { | |
| 49 int v2 = (int) v + d; | |
| 50 if ( v2 < 0 ) v2 = 0; | |
| 51 if ( v2 > (int) UINT16_MAX ) v2 = UINT16_MAX; | |
| 52 v = (uint16_t) v2; | |
| 53 } | |
| 54 | |
| 55 std::unique_ptr<Gdiplus::Bitmap> image16bpcto8(Gdiplus::Bitmap* img) { | |
| 56 | |
| 57 const unsigned channels = [img] { | |
| 58 switch (img->GetPixelFormat()) { | |
| 59 case PixelFormat48bppRGB: | |
| 60 return 3; | |
| 61 case PixelFormat16bppGrayScale: | |
| 62 return 1; | |
| 63 default: | |
| 64 throw std::runtime_error("Invalid pixel format"); | |
| 65 } | |
| 66 } (); | |
| 67 | |
| 68 | |
| 69 const unsigned Width = img->GetWidth(); | |
| 70 const unsigned Height = img->GetHeight(); | |
| 71 | |
| 72 if ( Width == 0 || Height == 0 ) throw std::runtime_error("Invalid dimensions"); | |
| 73 | |
| 74 std::unique_ptr< Gdiplus::Bitmap > ret ( new Gdiplus::Bitmap( Width, Height, channels == 3 ? PixelFormat24bppRGB : PixelFormat8bppIndexed ) ); | |
| 75 | |
| 76 | |
| 77 Gdiplus::Rect rcWhole = {}; | |
| 78 rcWhole.Width = Width; rcWhole.Height = Height; | |
| 79 Gdiplus::BitmapData dataIn, dataOut; | |
| 80 EH << ret->LockBits( &rcWhole, ImageLockModeWrite, PixelFormat24bppRGB, &dataOut); | |
| 81 EH << img->LockBits(&rcWhole, ImageLockModeRead, PixelFormat48bppRGB, &dataIn); | |
| 82 | |
| 83 | |
| 84 | |
| 85 | |
| 86 const uint8_t * inLine = (const uint8_t*)dataIn.Scan0; | |
| 87 uint8_t * outLine = (uint8_t*)dataOut.Scan0; | |
| 88 | |
| 89 std::vector<uint16_t> curLineBuf, nextLineBuf; | |
| 90 curLineBuf.resize( (Width + 2) * channels ); | |
| 91 nextLineBuf.resize( (Width + 2) * channels ); | |
| 92 | |
| 93 memcpy(&nextLineBuf[channels], inLine, Width * channels * 2 ); | |
| 94 | |
| 95 for (unsigned y = 0; y < Height; ++y) { | |
| 96 std::swap( curLineBuf, nextLineBuf ); | |
| 97 if (y + 1 < Height) { | |
| 98 inLine += dataIn.Stride; | |
| 99 memcpy(&nextLineBuf[channels], inLine, Width * channels * 2 ); | |
| 100 } | |
| 101 | |
| 102 auto & inPix = curLineBuf; | |
| 103 auto & inPixNext = nextLineBuf; | |
| 104 size_t inOffset = channels; | |
| 105 uint8_t * outPix = outLine; | |
| 106 for (unsigned x = 0; x < Width; ++x) { | |
| 107 for (int c = 0; c < (int)channels; ++c) { | |
| 108 uint16_t orig = inPix[inOffset]; | |
| 109 uint16_t v8 = orig >> 8; | |
| 110 uint16_t v16 = v8 | (v8 << 8); | |
| 111 | |
| 112 outPix[c] = (uint8_t) v8; | |
| 113 | |
| 114 int d = (int) orig - (int) v16; | |
| 115 | |
| 116 add16clip(inPix [inOffset + channels], d * 7 / 16 ); // x+1 | |
| 117 add16clip(inPixNext[inOffset - channels], d * 3 / 16 ); // x-1, y+1 | |
| 118 add16clip(inPixNext[inOffset ], d * 5 / 16 ); // y+1 | |
| 119 add16clip(inPixNext[inOffset + channels], d * 1 / 16 ); // x+1, y+1 | |
| 120 | |
| 121 ++ inOffset; | |
| 122 } | |
| 123 | |
| 124 outPix += channels; | |
| 125 } | |
| 126 | |
| 127 outLine += dataOut.Stride; | |
| 128 } | |
| 129 | |
| 130 EH << img->UnlockBits(&dataIn); | |
| 131 EH << ret->UnlockBits(&dataOut); | |
| 132 | |
| 133 return ret; | |
| 134 } | |
| 135 | |
| 136 void SaveImage(Gdiplus::Image* bmp, const TCHAR* out, const TCHAR* format, ULONG quality) { | |
| 137 if (bmp->GetType() != Gdiplus::ImageTypeBitmap) throw std::runtime_error("Bitmap expected"); | |
| 138 SaveImage(static_cast<Gdiplus::Bitmap*>(bmp), out, format, quality); | |
| 139 } | |
| 140 void SaveImage(Gdiplus::Bitmap* image, const TCHAR* out, const TCHAR* format, ULONG quality) { | |
| 141 CLSID encoderClsid; | |
| 142 EncoderParameters encoderParameters; | |
| 143 | |
| 144 if (GetEncoderClsid(format, &encoderClsid) < 0) throw std::runtime_error("Encoder not found"); | |
| 145 | |
| 146 if (_tcscmp(format, _T("image/jpeg")) == 0) { | |
| 147 encoderParameters.Count = 1; | |
| 148 encoderParameters.Parameter[0].Guid = EncoderQuality; | |
| 149 encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong; | |
| 150 encoderParameters.Parameter[0].NumberOfValues = 1; | |
| 151 encoderParameters.Parameter[0].Value = &quality; | |
| 152 | |
| 153 EH << image->Save(out, &encoderClsid, &encoderParameters); | |
| 154 } else { | |
| 155 EH << image->Save(out, &encoderClsid, NULL); | |
| 156 } | |
| 157 } |
