Leptonica 1.68
C Image Processing Library

webpio.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  -  Author: krish@google.com (krish Chaudhury)
00015  *====================================================================*/
00016 
00017 /*
00018  *  webpio.c
00019  *
00020  *    Read WebP from file
00021  *          PIX             *pixReadStreamWebP()
00022  *          l_int32          readHeaderWebP()
00023  *
00024  *    Write WebP to file
00025  *          l_int32          pixWriteWebP()  [ special top level ]
00026  *          l_int32          pixWriteStreamWebP()
00027  *
00028  *    Write WebP to file with target psnr
00029  *          l_int32          pixWriteWebPwithTargetPSNR
00030  *
00031  */
00032 
00033 #include <math.h>
00034 #include "allheaders.h"
00035 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config_auto.h"
00038 #endif  /* HAVE_CONFIG_H */
00039 
00040 /* --------------------------------------------*/
00041 #if  HAVE_LIBWEBP   /* defined in environ.h */
00042 /* --------------------------------------------*/
00043 #include "webp/decode.h"
00044 #include "webp/encode.h"
00045 
00046 /*---------------------------------------------------------------------*
00047  *                              Reading WebP                            *
00048  *---------------------------------------------------------------------*/
00049 
00050 /*!
00051  *  pixReadStreamWebP()
00052  *
00053  *      Input:  stream corresponding to WebP image
00054  *      Return: pix (32 bpp), or null on error
00055  *
00056  *  Notes:
00057  *      (1) Use 'free', and not leptonica's 'FREE', for all heap data
00058  *          that is returned from the WebP library.
00059  */
00060 PIX *
00061 pixReadStreamWebP(FILE  *fp)
00062 {
00063 l_uint8   *filedata;
00064 l_uint8   *out = NULL;
00065 l_int32    w, h, wpl, stride;
00066 l_uint32  *data;
00067 size_t     nbytes, sz, out_size;
00068 PIX       *pix;
00069 
00070     PROCNAME("pixReadStreamWebP");
00071 
00072     if (!fp)
00073         return (PIX *)ERROR_PTR("fp not defined", procName, NULL);
00074 
00075         /* Read data from file and decode into Y,U,V arrays */
00076     rewind(fp);
00077     if ((filedata = l_binaryReadStream(fp, &nbytes)) == NULL)
00078         return (PIX *)ERROR_PTR("filedata not read", procName, NULL);
00079 
00080     sz = WebPGetInfo(filedata, nbytes, &w, &h);
00081     if (sz == 0) {
00082         FREE(filedata);
00083         return (PIX *)ERROR_PTR("Bad WebP: Can't find size", procName, NULL);
00084     }
00085 
00086         /* Write from Y,U,V arrays to pix data */
00087     pix = pixCreate(w, h, 32);
00088     data = pixGetData(pix);
00089     wpl = pixGetWpl(pix);
00090     stride = wpl * 4;
00091     out_size = stride * h;
00092     out = WebPDecodeRGBAInto(filedata, nbytes, (uint8_t *)data, out_size,
00093                              stride);
00094     FREE(filedata);
00095     if (out == NULL) {
00096         pixDestroy(&pix);
00097         return (PIX *)ERROR_PTR("WebP decode failed", procName, NULL);
00098     }
00099     pixEndianByteSwap(pix);
00100 
00101     return pix;
00102 }
00103 
00104 
00105 /*!
00106  *  readHeaderWebP()
00107  *
00108  *      Input:  filename
00109  *              &width (<return>)
00110  *              &height (<return>)
00111  *      Return: 0 if OK, 1 on error
00112  */
00113 l_int32
00114 readHeaderWebP(const char *filename,
00115                l_int32    *pwidth,
00116                l_int32    *pheight)
00117 {
00118 l_uint8  data[10];
00119 l_int32  sz;
00120 FILE    *fp;
00121 
00122     PROCNAME("readHeaderWebP");
00123 
00124     if (!filename)
00125         return ERROR_INT("filename not defined", procName, 1);
00126     if (!pwidth || !pheight)
00127         return ERROR_INT("input ptr(s) not defined", procName, 1);
00128     if ((fp = fopenReadStream(filename)) == NULL)
00129         return ERROR_INT("image file not found", procName, 1);
00130     if (fread((char *)data, 1, 10, fp) != 10)
00131         return ERROR_INT("failed to read 10 bytes of file", procName, 1);
00132 
00133     sz = WebPGetInfo(data, 10, pwidth, pheight);
00134     if (sz == 0)
00135         return ERROR_INT("Bad WebP: Can't find size", procName, 1);
00136 
00137     fclose(fp);
00138     return 0;
00139 }
00140 
00141 
00142 /*---------------------------------------------------------------------*
00143  *                             Writing WebP                             *
00144  *---------------------------------------------------------------------*/
00145 /*!
00146  *  pixWriteWebP()
00147  *
00148  *      Input:  filename
00149  *              pixs
00150  *              quality (1 - 100; 75 is default)
00151  *      Return: 0 if OK, 1 on error
00152  */
00153 l_int32
00154 pixWriteWebP(const char  *filename,
00155              PIX         *pixs,
00156              l_int32      quality)
00157 {
00158 FILE  *fp;
00159 
00160     PROCNAME("pixWriteWebP");
00161 
00162     if (!pixs)
00163         return ERROR_INT("pixs not defined", procName, 1);
00164     if (!filename)
00165         return ERROR_INT("filename not defined", procName, 1);
00166 
00167     if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
00168         return ERROR_INT("stream not opened", procName, 1);
00169 
00170     if (pixWriteStreamWebP(fp, pixs, quality) != 0) {
00171         fclose(fp);
00172         return ERROR_INT("pixs not written to stream", procName, 1);
00173     }
00174 
00175     fclose(fp);
00176     return 0;
00177 }
00178 
00179 
00180 /*!
00181  *  pixWriteStreampWebP()
00182  *
00183  *      Input:  stream
00184  *              pix  (all depths)
00185  *              quality (1 - 100; 75 is default)
00186  *      Return: 0 if OK, 1 on error
00187  *
00188  *  Notes:
00189  *      (1) webp only encodes rgb images, so the input image is converted to rgb
00190  *          if necessary.
00191  */
00192 l_int32
00193 pixWriteStreamWebP(FILE    *fp,
00194                    PIX     *pixs,
00195                    l_int32  quality)
00196 {
00197 l_int32    w, h, d, wpl, stride, ret;
00198 l_uint8   *filedata = NULL;
00199 l_uint32  *data;
00200 size_t     nbytes;
00201 PIX       *pix, *pixt, *pix32;
00202 
00203     PROCNAME("pixWriteStreamWebP");
00204 
00205     if (!fp)
00206         return ERROR_INT("stream not open", procName, 1);
00207     if (!pixs)
00208         return ERROR_INT("pixs not defined", procName, 1);
00209 
00210     if (quality < 1)
00211         quality = 1;
00212     if (quality > 100)
00213         quality = 100;
00214 
00215     if ((pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR)) == NULL)
00216         return ERROR_INT("failure to remove color map", procName, 1);
00217     pix = pixEndianByteSwapNew(pixt);
00218     pixDestroy(&pixt);
00219     pixGetDimensions(pix, &w, &h, &d);
00220 
00221         /* Convert to rgb if not 32 bpp */
00222     if (d != 32) {
00223         if ((pix32 = pixConvertTo32(pix)) != NULL) {
00224             pixDestroy(&pix);
00225             pix = pix32;
00226             d = pixGetDepth(pix);
00227         }
00228     }
00229 
00230     wpl = pixGetWpl(pix);
00231     data = pixGetData(pix);
00232     if (d != 32 || w <= 0 || h <= 0 || wpl <= 0 || !data) {
00233         pixDestroy(&pix);
00234         return ERROR_INT("bad or empty input pix", procName, 1);
00235     }
00236 
00237     stride = wpl * 4;
00238     nbytes = WebPEncodeRGBA((uint8_t *)data, w, h, stride, quality, &filedata);
00239 
00240     if (nbytes == 0) {
00241         if (filedata) free(filedata);
00242         pixDestroy(&pix);
00243         return ERROR_INT("WebPEncode failed", procName, 1);
00244     }
00245 
00246     rewind(fp);
00247 
00248     ret = (fwrite(filedata, 1, nbytes, fp) != nbytes);
00249     free(filedata);
00250     pixDestroy(&pix);
00251     if (ret)
00252         return ERROR_INT("Write error", procName, 1);
00253 
00254     return 0;
00255 }
00256 
00257 
00258 /*!
00259  *  pixWriteWebPwithTargetPSNR()
00260  *
00261  *      Input:  filename
00262  *              pix  (all depths)
00263  *              target_psnr (target psnr to control the quality [1 ... 100])
00264  *              pquality (<optional return> final quality value used to obtain
00265  *                   the target_psnr; can be null)
00266  *      Return: 0 if OK, 1 on error
00267  *
00268  *  Notes:
00269  *      (1) The parameter to control quality while encoding WebP is quality.
00270  *          This function does a line search over the quality values between
00271  *          MIN_QUALITY and MAX_QUALITY to achieve the target PSNR as close as
00272  *          possible.
00273  */
00274 l_int32
00275 pixWriteWebPwithTargetPSNR(const char  *filename,
00276                            PIX         *pixs,
00277                            l_float64    target_psnr,
00278                            l_int32     *pquality)
00279 {
00280 l_uint8   *filedata = NULL;
00281 l_uint8   *tmp_filedata = NULL;
00282 l_int32    MIN_QUALITY = 1;    /* min allowed value of quality */
00283 l_int32    MAX_QUALITY = 100;  /* max allowed value of quality */
00284 l_int32    w, h, d, wpl, stride, ret;
00285 l_int32    quality, delta_quality, quality_test, accept;
00286 l_uint32  *data;
00287 l_float64  psnr, psnr_test;
00288 size_t     nbytes, tmp_nbytes = 0;
00289 FILE      *fp;
00290 PIX       *pix, *pix32;
00291 
00292     PROCNAME("pixWriteWebPwithTargetPSNR");
00293 
00294     if (!filename)
00295         return ERROR_INT("filename not defined", procName, 1);
00296     if (!pixs)
00297         return ERROR_INT("pixs not defined", procName, 1);
00298     if (target_psnr <= 0 || target_psnr >= 100)
00299         return ERROR_INT("Target psnr out of range", procName, 1);
00300 
00301     if ((pix = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR)) == NULL)
00302         return ERROR_INT("cannot remove color map", procName, 1);
00303     pixGetDimensions(pix, &w, &h, &d);
00304 
00305         /* Convert to rgb if not 32 bpp */
00306     if (d != 32) {
00307         if ((pix32 = pixConvertTo32(pix)) != NULL) {
00308             pixDestroy(&pix);
00309             pix = pix32;
00310             d = pixGetDepth(pix);
00311         }
00312     }
00313 
00314     wpl = pixGetWpl(pix);
00315     data = pixGetData(pix);
00316     if (d != 32 || w <= 0 || h <= 0 || wpl <= 0 || !data) {
00317         pixDestroy(&pix);
00318         return ERROR_INT("bad or empty input pix", procName, 1);
00319     }
00320 
00321         /* Set the initial value of the Quality parameter.  In each iteration
00322          * it will then increase or decrease the Quality value, based on
00323          * whether the achieved psnr is higher or lower than the target_psnr */
00324     quality = 75;
00325     stride = wpl * 4;
00326 
00327     nbytes = WebPEncodeRGBA((uint8_t *)data, w, h, stride, quality, &filedata);
00328 
00329     if (nbytes == 0) {
00330         if (filedata) free(filedata);
00331         pixDestroy(&pix);
00332         return ERROR_INT("WebPEncode failed", procName, 1);
00333     }
00334 
00335         /* Rationale about the delta_quality being limited: we expect optimal
00336          * quality to be not too far from target quality in practice.
00337          * So instead of a full dichotomy for the whole range we cap
00338          * |delta_quality| to only explore quickly around the starting value
00339          * and maximize the return in investment. */
00340     delta_quality = (psnr > target_psnr) ?
00341         L_MAX((MAX_QUALITY - quality) / 4, 1) :
00342         L_MIN((MIN_QUALITY - quality) / 4, -1);
00343 
00344     while (delta_quality != 0) {
00345             /* Advance quality and clip to valid range */
00346         quality_test = L_MIN(L_MAX(quality + delta_quality, MIN_QUALITY),
00347                              MAX_QUALITY);
00348             /* Re-adjust delta value after Quality-clipping. */
00349         delta_quality = quality_test - quality;
00350 
00351         tmp_nbytes = WebPEncodeRGBA((uint8_t *)data, w, h, stride, quality_test,
00352                                     &tmp_filedata);
00353         if (tmp_nbytes == 0) {
00354             free(filedata);
00355             if (tmp_filedata) free(tmp_filedata);
00356             pixDestroy(&pix);
00357             return ERROR_INT("WebPEncode failed", procName, 1);
00358         }
00359 
00360             /* Accept or reject new settings */
00361         accept = (psnr_test > target_psnr) ^ (delta_quality < 0);
00362         if (accept) {
00363             free(filedata);
00364             filedata = tmp_filedata;
00365             nbytes = tmp_nbytes;
00366             quality = quality_test;
00367             psnr = psnr_test;
00368         }
00369         else {
00370             delta_quality /= 2;
00371             free(tmp_filedata);
00372         }
00373     }
00374     if (pquality) *pquality = quality;
00375 
00376     if ((fp = fopenWriteStream(filename, "wb+")) == NULL) {
00377         free(filedata);
00378         pixDestroy(&pix);
00379         return ERROR_INT("stream not opened", procName, 1);
00380     }
00381 
00382     ret = (fwrite(filedata, 1, nbytes, fp) != nbytes);
00383     fclose(fp);
00384     free(filedata);
00385     pixDestroy(&pix);
00386     if (ret)
00387         return ERROR_INT("Write error", procName, 1);
00388 
00389     return 0;
00390 }
00391 
00392 /* --------------------------------------------*/
00393 #endif  /* HAVE_LIBWEBP */
00394 /* --------------------------------------------*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines