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