comparison mupdf-source/thirdparty/leptonica/src/webpanimio.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27 /*!
28 * \file webpanimio.c
29 * <pre>
30 *
31 * Writing animated WebP
32 * l_int32 pixaWriteWebPAnim()
33 * l_int32 pixaWriteStreamWebPAnim()
34 * l_int32 pixaWriteMemWebPAnim()
35 * </pre>
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include <config_auto.h>
40 #endif /* HAVE_CONFIG_H */
41
42 #include "allheaders.h"
43
44 /* -----------------------------------------------*/
45 #if HAVE_LIBWEBP_ANIM /* defined in environ.h */
46 /* -----------------------------------------------*/
47 #include "webp/encode.h"
48 #include "webp/mux.h"
49
50 /*---------------------------------------------------------------------*
51 * Writing animated WebP *
52 *---------------------------------------------------------------------*/
53 /*!
54 * \brief pixaWriteWebPAnim()
55 *
56 * \param[in] filename
57 * \param[in] pixa with images of all depths; cmap OK
58 * \param[in] loopcount [0 for infinite]
59 * \param[in] duration in ms, for each image
60 * \param[in] quality 0 - 100 for lossy; default ~80
61 * \param[in] lossless use 1 for lossless; 0 for lossy
62 * \return 0 if OK, 1 on error
63 *
64 * <pre>
65 * Notes:
66 * (1) Special top-level function allowing specification of quality.
67 * </pre>
68 */
69 l_ok
70 pixaWriteWebPAnim(const char *filename,
71 PIXA *pixa,
72 l_int32 loopcount,
73 l_int32 duration,
74 l_int32 quality,
75 l_int32 lossless)
76 {
77 l_int32 ret;
78 FILE *fp;
79
80 if (!filename)
81 return ERROR_INT("filename not defined", __func__, 1);
82 if (!pixa)
83 return ERROR_INT("pixa not defined", __func__, 1);
84
85 if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
86 return ERROR_INT_1("stream not opened", filename, __func__, 1);
87 ret = pixaWriteStreamWebPAnim(fp, pixa, loopcount, duration,
88 quality, lossless);
89 fclose(fp);
90 if (ret)
91 return ERROR_INT_1("pixs not compressed to stream",
92 filename, __func__, 1);
93 return 0;
94 }
95
96
97 /*!
98 * \brief pixaWriteStreamWebPAnim()
99 *
100 * \param[in] fp file stream
101 * \param[in] pixa with images of all depths; cmap OK
102 * \param[in] loopcount [0 for infinite]
103 * \param[in] duration in ms, for each image
104 * \param[in] quality 0 - 100 for lossy; default ~80
105 * \param[in] lossless use 1 for lossless; 0 for lossy
106 * \return 0 if OK, 1 on error
107 *
108 * <pre>
109 * Notes:
110 * (1) See pixWriteMemWebP() for details.
111 * (2) Use 'free', and not leptonica's 'LEPT_FREE', for all heap data
112 * that is returned from the WebP library.
113 * </pre>
114 */
115 l_ok
116 pixaWriteStreamWebPAnim(FILE *fp,
117 PIXA *pixa,
118 l_int32 loopcount,
119 l_int32 duration,
120 l_int32 quality,
121 l_int32 lossless)
122 {
123 l_uint8 *filedata;
124 size_t filebytes, nbytes;
125
126 if (!fp)
127 return ERROR_INT("stream not open", __func__, 1);
128 if (!pixa)
129 return ERROR_INT("pixa not defined", __func__, 1);
130
131 filedata = NULL;
132 pixaWriteMemWebPAnim(&filedata, &filebytes, pixa, loopcount,
133 duration, quality, lossless);
134 rewind(fp);
135 if (!filedata)
136 return ERROR_INT("filedata not made", __func__, 1);
137 nbytes = fwrite(filedata, 1, filebytes, fp);
138 free(filedata);
139 if (nbytes != filebytes)
140 return ERROR_INT("Write error", __func__, 1);
141 return 0;
142 }
143
144
145 /*!
146 * \brief pixaWriteMemWebPAnim()
147 *
148 * \param[out] pencdata webp encoded data of pixs
149 * \param[out] pencsize size of webp encoded data
150 * \param[in] pixa with images of any depth, cmapped OK
151 * \param[in] loopcount [0 for infinite]
152 * \param[in] duration in ms, for each image
153 * \param[in] quality 0 - 100 for lossy; default ~80
154 * \param[in] lossless use 1 for lossless; 0 for lossy
155 * \return 0 if OK, 1 on error
156 *
157 * <pre>
158 * Notes:
159 * (1) See pixWriteMemWebP() for details of webp encoding of images.
160 * </pre>
161 */
162 l_ok
163 pixaWriteMemWebPAnim(l_uint8 **pencdata,
164 size_t *pencsize,
165 PIXA *pixa,
166 l_int32 loopcount,
167 l_int32 duration,
168 l_int32 quality,
169 l_int32 lossless)
170 {
171 l_int32 i, n, same, w, h, wpl, ret, ret_webp;
172 l_uint8 *data;
173 PIX *pix1, *pix2;
174 WebPAnimEncoder *enc;
175 WebPAnimEncoderOptions enc_options;
176 WebPConfig config;
177 WebPData webp_data;
178 WebPMux *mux = NULL;
179 WebPMuxAnimParams newparams;
180 WebPPicture frame;
181
182 if (!pencdata)
183 return ERROR_INT("&encdata not defined", __func__, 1);
184 *pencdata = NULL;
185 if (!pencsize)
186 return ERROR_INT("&encsize not defined", __func__, 1);
187 *pencsize = 0;
188 if (!pixa)
189 return ERROR_INT("&pixa not defined", __func__, 1);
190 if ((n = pixaGetCount(pixa)) == 0)
191 return ERROR_INT("no images in pixa", __func__, 1);
192 if (loopcount < 0) loopcount = 0;
193 if (lossless == 0 && (quality < 0 || quality > 100))
194 return ERROR_INT("quality not in [0 ... 100]", __func__, 1);
195
196 pixaVerifyDimensions(pixa, &same, &w, &h);
197 if (!same)
198 return ERROR_INT("sizes of all pix are not the same", __func__, 1);
199
200 /* Set up the encoder */
201 if (!WebPAnimEncoderOptionsInit(&enc_options))
202 return ERROR_INT("cannot initialize WebP encoder options", __func__, 1);
203 if (!WebPConfigInit(&config))
204 return ERROR_INT("cannot initialize WebP config", __func__, 1);
205 config.lossless = lossless;
206 config.quality = quality;
207 if ((enc = WebPAnimEncoderNew(w, h, &enc_options)) == NULL)
208 return ERROR_INT("cannot create WebP encoder", __func__, 1);
209
210 for (i = 0; i < n; i++) {
211 /* Make a frame for each image. Convert the pix to RGBA with
212 * an opaque alpha layer, and put the raster data in the frame. */
213 if (!WebPPictureInit(&frame)) {
214 WebPAnimEncoderDelete(enc);
215 return ERROR_INT("cannot initialize WebP picture", __func__, 1);
216 }
217 pix1 = pixaGetPix(pixa, i, L_CLONE);
218 pix2 = pixConvertTo32(pix1);
219 pixSetComponentArbitrary(pix2, L_ALPHA_CHANNEL, 255);
220 pixEndianByteSwap(pix2);
221 data = (l_uint8 *)pixGetData(pix2);
222 wpl = pixGetWpl(pix2);
223 frame.width = w;
224 frame.height = h;
225 ret_webp = WebPPictureImportRGBA(&frame, data, 4 * wpl);
226 pixDestroy(&pix1);
227 pixDestroy(&pix2);
228 if (!ret_webp) {
229 WebPAnimEncoderDelete(enc);
230 return ERROR_INT("cannot import RGBA picture", __func__, 1);
231 }
232
233 /* Add the frame data to the encoder, and clear its memory */
234 ret_webp = WebPAnimEncoderAdd(enc, &frame, duration * i, &config);
235 WebPPictureFree(&frame);
236 if (!ret_webp) {
237 WebPAnimEncoderDelete(enc);
238 return ERROR_INT("cannot add frame to animation", __func__, 1);
239 }
240 }
241 /* Add a blank frame */
242 if (!WebPAnimEncoderAdd(enc, NULL, duration * i, NULL)) {
243 WebPAnimEncoderDelete(enc);
244 return ERROR_INT("blank frame not added to animation", __func__, 1);
245 }
246
247 /* Encode the data */
248 ret_webp = WebPAnimEncoderAssemble(enc, &webp_data);
249 WebPAnimEncoderDelete(enc);
250 if (!ret_webp)
251 return ERROR_INT("cannot assemble animation", __func__, 1);
252
253 /* Set the loopcount if requested. Note that when you make a mux,
254 * it imports the webp_data that was previously made, including
255 * the webp encoded images. Before you re-export that data using
256 * WebPMuxAssemble(), free the heap data in webp_data. There is an
257 * example for setting the loop count in the webp distribution;
258 * see gif2webp.c. */
259 if (loopcount > 0) {
260 mux = WebPMuxCreate(&webp_data, 1);
261 if (!mux) {
262 L_ERROR("could not re-mux to add loop count\n", __func__);
263 } else {
264 ret = WebPMuxGetAnimationParams(mux, &newparams);
265 if (ret != WEBP_MUX_OK) {
266 L_ERROR("failed to get loop count\n", __func__);
267 } else {
268 newparams.loop_count = loopcount;
269 ret = WebPMuxSetAnimationParams(mux, &newparams);
270 if (ret != WEBP_MUX_OK)
271 L_ERROR("failed to set loop count\n", __func__);
272 }
273 WebPDataClear(&webp_data);
274 if (WebPMuxAssemble(mux, &webp_data) != WEBP_MUX_OK)
275 L_ERROR("failed to assemble in the WebP muxer\n", __func__);
276 WebPMuxDelete(mux);
277 }
278 }
279
280 *pencdata = (l_uint8 *)webp_data.bytes;
281 *pencsize = webp_data.size;
282 L_INFO("data size = %zu\n", __func__, webp_data.size);
283 return 0;
284 }
285
286
287 /* --------------------------------------------*/
288 #endif /* HAVE_LIBWEBP_ANIM */
289 /* --------------------------------------------*/