1 /*
2  * wincodecs_common.c - Functions shared with other WIC libraries.
3  *
4  * Copyright 2020 Esme Povirk
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #define COBJMACROS
22 
23 #include <stdarg.h>
24 
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winternl.h"
28 #include "objbase.h"
29 
30 #include "wincodecs_private.h"
31 
32 #include "wine/debug.h"
33 
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
35 
36 #include "wincodecs_common.h"
37 
38 HRESULT configure_write_source(IWICBitmapFrameEncode *iface,
39     IWICBitmapSource *source, const WICRect *prc,
40     const WICPixelFormatGUID *format,
41     INT width, INT height, double xres, double yres)
42 {
43     UINT src_width, src_height;
44     HRESULT hr = S_OK;
45 
46     if (width == 0 && height == 0)
47     {
48         if (prc)
49         {
50             if (prc->Width <= 0 || prc->Height <= 0) return E_INVALIDARG;
51             width = prc->Width;
52             height = prc->Height;
53         }
54         else
55         {
56             hr = IWICBitmapSource_GetSize(source, &src_width, &src_height);
57             if (FAILED(hr)) return hr;
58             if (src_width == 0 || src_height == 0) return E_INVALIDARG;
59             width = src_width;
60             height = src_height;
61         }
62         hr = IWICBitmapFrameEncode_SetSize(iface, (UINT)width, (UINT)height);
63         if (FAILED(hr)) return hr;
64     }
65     if (width == 0 || height == 0) return E_INVALIDARG;
66 
67     if (!format)
68     {
69         WICPixelFormatGUID src_format;
70 
71         hr = IWICBitmapSource_GetPixelFormat(source, &src_format);
72         if (FAILED(hr)) return hr;
73 
74         hr = IWICBitmapFrameEncode_SetPixelFormat(iface, &src_format);
75         if (FAILED(hr)) return hr;
76     }
77 
78     if (xres == 0.0 || yres == 0.0)
79     {
80         hr = IWICBitmapSource_GetResolution(source, &xres, &yres);
81         if (FAILED(hr)) return hr;
82         hr = IWICBitmapFrameEncode_SetResolution(iface, xres, yres);
83         if (FAILED(hr)) return hr;
84     }
85 
86     return hr;
87 }
88 
89 HRESULT write_source(IWICBitmapFrameEncode *iface,
90     IWICBitmapSource *source, const WICRect *prc,
91     const WICPixelFormatGUID *format, UINT bpp, BOOL need_palette,
92     INT width, INT height)
93 {
94     IWICBitmapSource *converted_source;
95     HRESULT hr=S_OK;
96     WICRect rc;
97     UINT stride;
98     BYTE* pixeldata;
99 
100     if (!prc)
101     {
102         UINT src_width, src_height;
103         hr = IWICBitmapSource_GetSize(source, &src_width, &src_height);
104         if (FAILED(hr)) return hr;
105         rc.X = 0;
106         rc.Y = 0;
107         rc.Width = src_width;
108         rc.Height = src_height;
109         prc = &rc;
110     }
111 
112     if (prc->Width != width || prc->Height <= 0)
113         return E_INVALIDARG;
114 
115     hr = WICConvertBitmapSource(format, source, &converted_source);
116     if (FAILED(hr))
117     {
118         ERR("Failed to convert source, target format %s, %#lx\n", debugstr_guid(format), hr);
119         return E_NOTIMPL;
120     }
121 
122     if (need_palette)
123     {
124         IWICImagingFactory *factory;
125         IWICPalette *palette;
126 
127         hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICImagingFactory, (void**)&factory);
128 
129         if (SUCCEEDED(hr))
130         {
131             hr = IWICImagingFactory_CreatePalette(factory, &palette);
132             IWICImagingFactory_Release(factory);
133         }
134 
135         if (SUCCEEDED(hr))
136         {
137             hr = IWICBitmapSource_CopyPalette(converted_source, palette);
138 
139             if (SUCCEEDED(hr))
140                 hr = IWICBitmapFrameEncode_SetPalette(iface, palette);
141 
142             IWICPalette_Release(palette);
143         }
144 
145         if (FAILED(hr))
146         {
147             IWICBitmapSource_Release(converted_source);
148             return hr;
149         }
150     }
151 
152     stride = (bpp * width + 7)/8;
153 
154     pixeldata = malloc(stride * prc->Height);
155     if (!pixeldata)
156     {
157         IWICBitmapSource_Release(converted_source);
158         return E_OUTOFMEMORY;
159     }
160 
161     hr = IWICBitmapSource_CopyPixels(converted_source, prc, stride,
162         stride*prc->Height, pixeldata);
163 
164     if (SUCCEEDED(hr))
165     {
166         hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride,
167             stride*prc->Height, pixeldata);
168     }
169 
170     free(pixeldata);
171     IWICBitmapSource_Release(converted_source);
172 
173     return hr;
174 }
175 
176 HRESULT CDECL stream_getsize(IStream *stream, ULONGLONG *size)
177 {
178     STATSTG statstg;
179     HRESULT hr;
180 
181     hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
182 
183     if (SUCCEEDED(hr))
184         *size = statstg.cbSize.QuadPart;
185 
186     return hr;
187 }
188 
189 HRESULT CDECL stream_read(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read)
190 {
191     return IStream_Read(stream, buffer, read, bytes_read);
192 }
193 
194 HRESULT CDECL stream_seek(IStream *stream, LONGLONG ofs, DWORD origin, ULONGLONG *new_position)
195 {
196     HRESULT hr;
197     LARGE_INTEGER ofs_large;
198     ULARGE_INTEGER pos_large;
199 
200     ofs_large.QuadPart = ofs;
201     hr = IStream_Seek(stream, ofs_large, origin, &pos_large);
202     if (new_position)
203         *new_position = pos_large.QuadPart;
204 
205     return hr;
206 }
207 
208 HRESULT CDECL stream_write(IStream *stream, const void *buffer, ULONG write, ULONG *bytes_written)
209 {
210     return IStream_Write(stream, buffer, write, bytes_written);
211 }
212