1 #ifndef WIC_IMAGE_H
2 #define WIC_IMAGE_H
3 
4 // image decoder and encoder with WIC
5 #include <wincodec.h>
6 
wic_decode_image(const wchar_t * filepath,int * w,int * h,int * c)7 unsigned char* wic_decode_image(const wchar_t* filepath, int* w, int* h, int* c)
8 {
9     IWICImagingFactory* factory = 0;
10     IWICBitmapDecoder* decoder = 0;
11     IWICBitmapFrameDecode* frame = 0;
12     WICPixelFormatGUID pixel_format;
13     IWICFormatConverter* converter = 0;
14     IWICBitmap* bitmap = 0;
15     IWICBitmapLock* lock = 0;
16     int width = 0;
17     int height = 0;
18     int channels = 0;
19     WICRect rect = { 0, 0, 0, 0 };
20     unsigned int datasize = 0;
21     unsigned char* data = 0;
22     int stride = 0;
23     unsigned char* bgrdata = 0;
24 
25     if (CoCreateInstance(CLSID_WICImagingFactory1, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory)))
26         goto RETURN;
27 
28     if (factory->CreateDecoderFromFilename(filepath, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder))
29         goto RETURN;
30 
31     if (decoder->GetFrame(0, &frame))
32         goto RETURN;
33 
34     if (factory->CreateFormatConverter(&converter))
35         goto RETURN;
36 
37     if (frame->GetPixelFormat(&pixel_format))
38         goto RETURN;
39 
40     if (!IsEqualGUID(pixel_format, GUID_WICPixelFormat32bppBGRA))
41         pixel_format = GUID_WICPixelFormat24bppBGR;
42 
43     channels = IsEqualGUID(pixel_format, GUID_WICPixelFormat32bppBGRA) ? 4 : 3;
44 
45     if (converter->Initialize(frame, pixel_format, WICBitmapDitherTypeNone, 0, 0.0, WICBitmapPaletteTypeCustom))
46         goto RETURN;
47 
48     if (factory->CreateBitmapFromSource(converter, WICBitmapCacheOnDemand, &bitmap))
49         goto RETURN;
50 
51     if (bitmap->GetSize((UINT*)&width, (UINT*)&height))
52         goto RETURN;
53 
54     rect.Width = width;
55     rect.Height = height;
56     if (bitmap->Lock(&rect, WICBitmapLockRead, &lock))
57         goto RETURN;
58 
59     if (lock->GetDataPointer(&datasize, &data))
60         goto RETURN;
61 
62     if (lock->GetStride((UINT*)&stride))
63         goto RETURN;
64 
65     bgrdata = (unsigned char*)malloc(width * height * channels);
66     if (!bgrdata)
67         goto RETURN;
68 
69     for (int y = 0; y < height; y++)
70     {
71         const unsigned char* ptr = data + y * stride;
72         unsigned char* bgrptr = bgrdata + y * width * channels;
73         memcpy(bgrptr, ptr, width * channels);
74     }
75 
76     *w = width;
77     *h = height;
78     *c = channels;
79 
80 RETURN:
81     if (lock) lock->Release();
82     if (bitmap) bitmap->Release();
83     if (decoder) decoder->Release();
84     if (frame) frame->Release();
85     if (converter) converter->Release();
86     if (factory) factory->Release();
87 
88     return bgrdata;
89 }
90 
wic_encode_image(const wchar_t * filepath,int w,int h,int c,void * bgrdata)91 int wic_encode_image(const wchar_t* filepath, int w, int h, int c, void* bgrdata)
92 {
93     IWICImagingFactory* factory = 0;
94     IWICStream* stream = 0;
95     IWICBitmapEncoder* encoder = 0;
96     IWICBitmapFrameEncode* frame = 0;
97     WICPixelFormatGUID format = c == 4 ? GUID_WICPixelFormat32bppBGRA : GUID_WICPixelFormat24bppBGR;
98     int stride = (w * c * 8 + 7) / 8;
99     unsigned char* data = 0;
100     int ret = 0;
101 
102     if (CoCreateInstance(CLSID_WICImagingFactory1, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory)))
103         goto RETURN;
104 
105     if (factory->CreateStream(&stream))
106         goto RETURN;
107 
108     if (stream->InitializeFromFilename(filepath, GENERIC_WRITE))
109         goto RETURN;
110 
111     if (factory->CreateEncoder(GUID_ContainerFormatPng, 0, &encoder))
112         goto RETURN;
113 
114     if (encoder->Initialize(stream, WICBitmapEncoderNoCache))
115         goto RETURN;
116 
117     if (encoder->CreateNewFrame(&frame, 0))
118         goto RETURN;
119 
120     if (frame->Initialize(0))
121         goto RETURN;
122 
123     if (frame->SetSize((UINT)w, (UINT)h))
124         goto RETURN;
125 
126     if (frame->SetPixelFormat(&format))
127         goto RETURN;
128 
129     if (!IsEqualGUID(format, c == 4 ? GUID_WICPixelFormat32bppBGRA : GUID_WICPixelFormat24bppBGR))
130         goto RETURN;
131 
132     data = (unsigned char*)malloc(h * stride);
133     if (!data)
134         goto RETURN;
135 
136     for (int y = 0; y < h; y++)
137     {
138         const unsigned char* bgrptr = (const unsigned char*)bgrdata + y * w * c;
139         unsigned char* ptr = data + y * stride;
140         memcpy(ptr, bgrptr, w * c);
141     }
142 
143     if (frame->WritePixels(h, stride, h * stride, data))
144         goto RETURN;
145 
146     if (frame->Commit())
147         goto RETURN;
148 
149     if (encoder->Commit())
150         goto RETURN;
151 
152     ret = 1;
153 
154 RETURN:
155     if (data) free(data);
156     if (encoder) encoder->Release();
157     if (frame) frame->Release();
158     if (stream) stream->Release();
159     if (factory) factory->Release();
160 
161     return ret;
162 }
163 
wic_encode_jpeg_image(const wchar_t * filepath,int w,int h,int c,void * bgrdata)164 int wic_encode_jpeg_image(const wchar_t* filepath, int w, int h, int c, void* bgrdata)
165 {
166     // assert c == 3
167 
168     IWICImagingFactory* factory = 0;
169     IWICStream* stream = 0;
170     IWICBitmapEncoder* encoder = 0;
171     IWICBitmapFrameEncode* frame = 0;
172     IPropertyBag2* propertybag = 0;
173     WICPixelFormatGUID format = GUID_WICPixelFormat24bppBGR;
174     int stride = (w * c * 8 + 7) / 8;
175     unsigned char* data = 0;
176     int ret = 0;
177 
178     PROPBAG2 option = { 0 };
179     option.pstrName = L"ImageQuality";
180     VARIANT varValue;
181     VariantInit(&varValue);
182     varValue.vt = VT_R4;
183     varValue.fltVal = 1.0f;
184 
185     if (CoCreateInstance(CLSID_WICImagingFactory1, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory)))
186         goto RETURN;
187 
188     if (factory->CreateStream(&stream))
189         goto RETURN;
190 
191     if (stream->InitializeFromFilename(filepath, GENERIC_WRITE))
192         goto RETURN;
193 
194     if (factory->CreateEncoder(GUID_ContainerFormatJpeg, 0, &encoder))
195         goto RETURN;
196 
197     if (encoder->Initialize(stream, WICBitmapEncoderNoCache))
198         goto RETURN;
199 
200     if (encoder->CreateNewFrame(&frame, &propertybag))
201         goto RETURN;
202 
203     if (propertybag->Write(1, &option, &varValue))
204         goto RETURN;
205 
206     if (frame->Initialize(propertybag))
207         goto RETURN;
208 
209     if (frame->SetSize((UINT)w, (UINT)h))
210         goto RETURN;
211 
212     if (frame->SetPixelFormat(&format))
213         goto RETURN;
214 
215     if (!IsEqualGUID(format, GUID_WICPixelFormat24bppBGR))
216         goto RETURN;
217 
218     data = (unsigned char*)malloc(h * stride);
219     if (!data)
220         goto RETURN;
221 
222     for (int y = 0; y < h; y++)
223     {
224         const unsigned char* bgrptr = (const unsigned char*)bgrdata + y * w * c;
225         unsigned char* ptr = data + y * stride;
226         memcpy(ptr, bgrptr, w * c);
227     }
228 
229     if (frame->WritePixels(h, stride, h * stride, data))
230         goto RETURN;
231 
232     if (frame->Commit())
233         goto RETURN;
234 
235     if (encoder->Commit())
236         goto RETURN;
237 
238     ret = 1;
239 
240 RETURN:
241     if (data) free(data);
242     if (encoder) encoder->Release();
243     if (frame) frame->Release();
244     if (propertybag) propertybag->Release();
245     if (stream) stream->Release();
246     if (factory) factory->Release();
247 
248     return ret;
249 }
250 
251 #endif // WIC_IMAGE_H
252