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 }