1 /* 2 * Copyright 2020 Esme Povirk 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 HRESULT CDECL decoder_initialize(struct decoder *decoder, IStream *stream, struct decoder_stat *st) 20 { 21 return decoder->vtable->initialize(decoder, stream, st); 22 } 23 24 HRESULT CDECL decoder_get_frame_info(struct decoder *decoder, UINT frame, struct decoder_frame *info) 25 { 26 return decoder->vtable->get_frame_info(decoder, frame, info); 27 } 28 29 HRESULT CDECL decoder_copy_pixels(struct decoder *decoder, UINT frame, 30 const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer) 31 { 32 return decoder->vtable->copy_pixels(decoder, frame, prc, stride, buffersize, buffer); 33 } 34 35 HRESULT CDECL decoder_get_metadata_blocks(struct decoder *decoder, UINT frame, UINT *count, struct decoder_block **blocks) 36 { 37 return decoder->vtable->get_metadata_blocks(decoder, frame, count, blocks); 38 } 39 40 HRESULT CDECL decoder_get_color_context(struct decoder *decoder, UINT frame, 41 UINT num, BYTE **data, DWORD *datasize) 42 { 43 return decoder->vtable->get_color_context(decoder, frame, num, data, datasize); 44 } 45 46 void CDECL decoder_destroy(struct decoder *decoder) 47 { 48 decoder->vtable->destroy(decoder); 49 } 50 51 HRESULT CDECL encoder_initialize(struct encoder *encoder, IStream *stream) 52 { 53 return encoder->vtable->initialize(encoder, stream); 54 } 55 56 HRESULT CDECL encoder_get_supported_format(struct encoder* encoder, GUID *pixel_format, DWORD *bpp, BOOL *indexed) 57 { 58 return encoder->vtable->get_supported_format(encoder, pixel_format, bpp, indexed); 59 } 60 61 HRESULT CDECL encoder_create_frame(struct encoder* encoder, const struct encoder_frame *frame) 62 { 63 return encoder->vtable->create_frame(encoder, frame); 64 } 65 66 HRESULT CDECL encoder_write_lines(struct encoder* encoder, BYTE *data, DWORD line_count, DWORD stride) 67 { 68 return encoder->vtable->write_lines(encoder, data, line_count, stride); 69 } 70 71 HRESULT CDECL encoder_commit_frame(struct encoder* encoder) 72 { 73 return encoder->vtable->commit_frame(encoder); 74 } 75 76 HRESULT CDECL encoder_commit_file(struct encoder* encoder) 77 { 78 return encoder->vtable->commit_file(encoder); 79 } 80 81 void CDECL encoder_destroy(struct encoder *encoder) 82 { 83 encoder->vtable->destroy(encoder); 84 } 85 86 HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer, 87 UINT srcwidth, UINT srcheight, INT srcstride, 88 const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer) 89 { 90 UINT bytesperrow; 91 UINT row_offset; /* number of bits into the source rows where the data starts */ 92 WICRect rect; 93 94 if (!rc) 95 { 96 rect.X = 0; 97 rect.Y = 0; 98 rect.Width = srcwidth; 99 rect.Height = srcheight; 100 rc = ▭ 101 } 102 else 103 { 104 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight) 105 return E_INVALIDARG; 106 } 107 108 bytesperrow = ((bpp * rc->Width)+7)/8; 109 110 if (dststride < bytesperrow) 111 return E_INVALIDARG; 112 113 if ((dststride * (rc->Height-1)) + bytesperrow > dstbuffersize) 114 return E_INVALIDARG; 115 116 /* if the whole bitmap is copied and the buffer format matches then it's a matter of a single memcpy */ 117 if (rc->X == 0 && rc->Y == 0 && rc->Width == srcwidth && rc->Height == srcheight && 118 srcstride == dststride && srcstride == bytesperrow) 119 { 120 memcpy(dstbuffer, srcbuffer, srcstride * srcheight); 121 return S_OK; 122 } 123 124 row_offset = rc->X * bpp; 125 126 if (row_offset % 8 == 0) 127 { 128 /* everything lines up on a byte boundary */ 129 INT row; 130 const BYTE *src; 131 BYTE *dst; 132 133 src = srcbuffer + (row_offset / 8) + srcstride * rc->Y; 134 dst = dstbuffer; 135 for (row=0; row < rc->Height; row++) 136 { 137 memcpy(dst, src, bytesperrow); 138 src += srcstride; 139 dst += dststride; 140 } 141 return S_OK; 142 } 143 else 144 { 145 /* we have to do a weird bitwise copy. eww. */ 146 FIXME("cannot reliably copy bitmap data if bpp < 8\n"); 147 return E_FAIL; 148 } 149 } 150 151 static inline ULONG read_ulong_be(BYTE* data) 152 { 153 return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; 154 } 155 156 HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *data_size) 157 { 158 BYTE header[8]; 159 HRESULT hr; 160 ULONG bytesread; 161 162 hr = stream_read(stream, header, 8, &bytesread); 163 if (FAILED(hr) || bytesread < 8) 164 { 165 if (SUCCEEDED(hr)) 166 hr = E_FAIL; 167 return hr; 168 } 169 170 *data_size = read_ulong_be(&header[0]); 171 172 memcpy(type, &header[4], 4); 173 174 if (data) 175 { 176 *data = malloc(*data_size); 177 if (!*data) 178 return E_OUTOFMEMORY; 179 180 hr = stream_read(stream, *data, *data_size, &bytesread); 181 182 if (FAILED(hr) || bytesread < *data_size) 183 { 184 if (SUCCEEDED(hr)) 185 hr = E_FAIL; 186 free(*data); 187 *data = NULL; 188 return hr; 189 } 190 191 /* Windows ignores CRC of the chunk */ 192 } 193 194 return S_OK; 195 } 196 197 void reverse_bgr8(UINT bytesperpixel, LPBYTE bits, UINT width, UINT height, INT stride) 198 { 199 UINT x, y; 200 BYTE *pixel, temp; 201 202 for (y=0; y<height; y++) 203 { 204 pixel = bits + stride * (INT)y; 205 206 for (x=0; x<width; x++) 207 { 208 temp = pixel[2]; 209 pixel[2] = pixel[0]; 210 pixel[0] = temp; 211 pixel += bytesperpixel; 212 } 213 } 214 } 215