Mercurial > hgrepos > Python2 > PyMuPDF
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 /* --------------------------------------------*/ |
