LCOV - code coverage report
Current view: top level - src - cairo_jpg.c (source / functions) Coverage Total Hit
Test: PHP Cairo Extension Coverage Lines: 68.6 % 105 72
Test Date: 2025-09-10 21:28:33 Functions: 71.4 % 7 5

            Line data    Source code
       1              : /* Copyright 2018-2024 Bernhard R. Fischer, 4096R/8E24F29D <bf@abenteuerland.at>
       2              :  *
       3              :  * This file is part of Cairo_JPG.
       4              :  *
       5              :  * Cairo_JPG is free software: you can redistribute it and/or modify
       6              :  * it under the terms of the GNU Lesser General Public License as published by
       7              :  * the Free Software Foundation, either version 3 of the License, or
       8              :  * (at your option) any later version.
       9              :  *
      10              :  * Cairo_JPG is distributed in the hope that it will be useful,
      11              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13              :  * GNU Lesser General Public License for more details.
      14              :  *
      15              :  * You should have received a copy of the GNU General Public License
      16              :  * along with Cairo_JPG.  If not, see <https://www.gnu.org/licenses/>.
      17              :  */
      18              : 
      19              : /*! \file cairo_jpg.c
      20              :  * This file contains two functions for reading and writing JPEG files from
      21              :  * and to Cairo image surfaces. It uses the functions from the libjpeg.
      22              :  * Most of the code is directly derived from the online example at
      23              :  * http://libjpeg-turbo.virtualgl.org/Documentation/Documentation
      24              :  *
      25              :  * All prototypes are defined in cairo_jpg.h All functions and their parameters
      26              :  * and return values are described below directly at the functions. You may
      27              :  * also have a look at the preprocessor macros defined below.
      28              :  *
      29              :  * To compile this code you need to have installed the packages libcairo2-dev
      30              :  * and libjpeg-dev. Compile with the following to create an object file to link
      31              :  * with your code:
      32              :  * gcc -std=c99 -Wall -c `pkg-config cairo libjpeg --cflags` cairo_jpg.c
      33              :  * Use the following command to include the main() function and create an
      34              :  * executable for testing of this code:
      35              :  * gcc -std=c99 -Wall -o cairo_jpg -DCAIRO_JPEG_MAIN `pkg-config cairo libjpeg --cflags` cairo_jpg.c `pkg-config cairo libjpeg --libs`
      36              :  *
      37              :  * @author Bernhard R. Fischer, 4096R/8E24F29D bf@abenteuerland.at
      38              :  * @version 2020/01/18
      39              :  * @license LGPL3.
      40              :  */
      41              : 
      42              : #ifdef HAVE_CONFIG_H
      43              : #include "config.h"
      44              : #endif
      45              : #include <stdio.h>
      46              : #include <stdlib.h>
      47              : #include <stdint.h>
      48              : #include <sys/types.h>
      49              : #include <sys/stat.h>
      50              : #include <fcntl.h>
      51              : #if defined(_WIN32) || defined(_WIN64)
      52              : #include <io.h>
      53              : #ifndef S_IRUSR
      54              : #define S_IRUSR 0400
      55              : #endif
      56              : #ifndef S_IWUSR
      57              : #define S_IWUSR 0200
      58              : #endif
      59              : #ifndef S_IRGRP
      60              : #define S_IRGRP 0040
      61              : #endif
      62              : #ifndef S_IROTH
      63              : #define S_IROTH 0004
      64              : #endif
      65              : #else
      66              : #include <unistd.h>
      67              : #ifndef O_BINARY
      68              : #define O_BINARY 0
      69              : #endif
      70              : #endif
      71              : 
      72              : #include <cairo.h>
      73              : #include "php_cairo_internal.h"
      74              : 
      75              : #if defined(HAVE_LIBJPEG)
      76              : 
      77              : /*! Macro to activate main() function. This is only used for testing. Comment
      78              :  * it out (#undef) if you link this file to your own program.
      79              :  */
      80              : //#define CAIRO_JPEG_MAIN
      81              : //
      82              : /*! Define this to use an alternate implementation of
      83              :  * cairo_image_surface_create_from_jpeg() which fstat(3)s the file before
      84              :  * reading (see below). For huge files this /may/ be slightly faster.
      85              :  */
      86              : #undef CAIRO_JPEG_USE_FSTAT
      87              : 
      88              : /*! This is the read block size for the stream reader
      89              :  * cairo_image_surface_create_from_jpeg_stream().
      90              :  */
      91              : #ifdef USE_CAIRO_READ_FUNC_LEN_T
      92              : #define CAIRO_JPEG_IO_BLOCK_SIZE 4096
      93              : #else
      94              : /*! Block size has to be one if cairo_read_func_t is in use because of the lack
      95              :  * to detect EOF (truncated reads).
      96              :  */
      97              : #define CAIRO_JPEG_IO_BLOCK_SIZE 1
      98              : /*! In case of original cairo_read_func_t is used fstat() should be used for
      99              :  * performance reasons (see CAIRO_JPEG_USE_FSTAT above).
     100              :  */
     101              : #define CAIRO_JPEG_USE_FSTAT
     102              : #endif
     103              : 
     104              : /*! Define this to test jpeg creation with non-image surfaces. This is only for
     105              :  * testing and is to be used together with CAIRO_JPEG_MAIN.
     106              :  */
     107              : #undef CAIRO_JPEG_TEST_SIMILAR
     108              : #if defined(CAIRO_JPEG_TEST_SIMILAR) && defined(CAIRO_JPEG_MAIN)
     109              : #include <cairo-pdf.h>
     110              : #endif
     111              : 
     112              : 
     113              : #ifndef LIBJPEG_TURBO_VERSION
     114              : /*! This function makes a conversion for "odd" pixel sizes which typically is a
     115              :  * conversion from a 3-byte to a 4-byte (or more) pixel size or vice versa.
     116              :  * The conversion is done from the source buffer src to the destination buffer
     117              :  * dst. The caller MUST ensure that src and dst have the correct memory size.
     118              :  * This is dw * num for dst and sw * num for src. src and dst may point to the
     119              :  * same memory address.
     120              :  * @param dst Pointer to destination buffer.
     121              :  * @param dw Pixel width (in bytes) of pixels in destination buffer, dw >= 3.
     122              :  * @param src Pointer to source buffer.
     123              :  * @param sw Pixel width (in bytes) of pixels in source buffer, sw >= 3.
     124              :  * @param num Number of pixels to convert, num >= 1;
     125              :  */
     126              : static void pix_conv(unsigned char *dst, int dw, const unsigned char *src, int sw, int num)
     127              : {
     128              :    int si, di;
     129              : 
     130              :    // safety check
     131              :    if (dw < 3 || sw < 3 || dst == NULL || src == NULL)
     132              :       return;
     133              : 
     134              :    num--;
     135              :    for (si = num * sw, di = num * dw; si >= 0; si -= sw, di -= dw)
     136              :    {
     137              : #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
     138              :       dst[di + 2] = src[si    ];
     139              :       dst[di + 1] = src[si + 1];
     140              :       dst[di + 0] = src[si + 2];
     141              : #else
     142              :       // FIXME: This is untested, it may be wrong.
     143              :       dst[di - 3] = src[si - 3];
     144              :       dst[di - 2] = src[si - 2];
     145              :       dst[di - 1] = src[si - 1];
     146              : #endif
     147              :    }
     148              : }
     149              : #endif
     150              : 
     151              : 
     152              : /*! This function creates a JPEG file in memory from a Cairo image surface.
     153              :  * @param sfc Pointer to a Cairo surface. It should be an image surface of
     154              :  * either CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_RGB24. Other formats are
     155              :  * converted to CAIRO_FORMAT_RGB24 before compression.
     156              :  * Please note that this may give unexpected results because JPEG does not
     157              :  * support transparency. Thus, default background color is used to replace
     158              :  * transparent regions. The default background color is black if not specified
     159              :  * explicitly. Thus converting e.g. PDF surfaces without having any specific
     160              :  * background color set will appear with black background and not white as you
     161              :  * might expect. In such cases it is suggested to manually convert the surface
     162              :  * to RGB24 before calling this function.
     163              :  * @param data Pointer to a memory pointer. This parameter receives a pointer
     164              :  * to the memory area where the final JPEG data is found in memory. This
     165              :  * function reserves the memory properly and it has to be freed by the caller
     166              :  * with free(3).
     167              :  * @param len Pointer to a variable of type size_t which will receive the final
     168              :  * length of the memory buffer.
     169              :  * @param quality Compression quality, 0-100.
     170              :  * @return On success the function returns CAIRO_STATUS_SUCCESS. In case of
     171              :  * error CAIRO_STATUS_INVALID_FORMAT is returned.
     172              :  */
     173            2 : cairo_status_t cairo_image_surface_write_to_jpeg_mem(cairo_surface_t *sfc, unsigned char **data, size_t *len, int quality)
     174              : {
     175              :    struct jpeg_compress_struct cinfo;
     176              :    struct jpeg_error_mgr jerr;
     177              :    JSAMPROW row_pointer[1];
     178            2 :    cairo_surface_t *other = NULL;
     179              : 
     180              :    // check valid input format (must be IMAGE_SURFACE && (ARGB32 || RGB24))
     181            4 :    if (cairo_surface_get_type(sfc) != CAIRO_SURFACE_TYPE_IMAGE ||
     182            2 :          (cairo_image_surface_get_format(sfc) != CAIRO_FORMAT_ARGB32 &&
     183            0 :          cairo_image_surface_get_format(sfc) != CAIRO_FORMAT_RGB24))
     184              :    {
     185              :       // create a similar surface with a proper format if supplied input format
     186              :       // does not fulfill the requirements
     187              :       double x1, y1, x2, y2;
     188            0 :       other = sfc;
     189            0 :       cairo_t *ctx = cairo_create(other);
     190              :       // get extents of original surface
     191            0 :       cairo_clip_extents(ctx, &x1, &y1, &x2, &y2);
     192            0 :       cairo_destroy(ctx);
     193              : 
     194              :       // create new image surface
     195            0 :       sfc = cairo_surface_create_similar_image(other, CAIRO_FORMAT_RGB24, x2 - x1, y2 - y1);
     196            0 :       if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS)
     197            0 :          return CAIRO_STATUS_INVALID_FORMAT;
     198              : 
     199              :       // paint original surface to new surface
     200            0 :       ctx = cairo_create(sfc);
     201            0 :       cairo_set_source_surface(ctx, other, 0, 0);
     202            0 :       cairo_paint(ctx);
     203            0 :       cairo_destroy(ctx);
     204              :    }
     205              : 
     206              :    // finish queued drawing operations
     207            2 :    cairo_surface_flush(sfc);
     208              : 
     209              :    // init jpeg compression structures
     210            2 :    cinfo.err = jpeg_std_error(&jerr);
     211            2 :    jpeg_create_compress(&cinfo);
     212              : 
     213              :    // set compression parameters
     214            2 :    unsigned long jpeg_len = *len;
     215            2 :    jpeg_mem_dest(&cinfo, data, &jpeg_len);
     216            2 :    cinfo.image_width = cairo_image_surface_get_width(sfc);
     217            2 :    cinfo.image_height = cairo_image_surface_get_height(sfc);
     218              : #ifdef LIBJPEG_TURBO_VERSION
     219              : #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
     220              :    //cinfo.in_color_space = JCS_EXT_BGRX;
     221            2 :    cinfo.in_color_space = cairo_image_surface_get_format(sfc) == CAIRO_FORMAT_ARGB32 ? JCS_EXT_BGRA : JCS_EXT_BGRX;
     222              : #else
     223              :    //cinfo.in_color_space = JCS_EXT_XRGB;
     224              :    cinfo.in_color_space = cairo_image_surface_get_format(sfc) == CAIRO_FORMAT_ARGB32 ? JCS_EXT_ARGB : JCS_EXT_XRGB;
     225              : #endif
     226            2 :    cinfo.input_components = 4;
     227              : #else
     228              :    cinfo.in_color_space = JCS_RGB;
     229              :    cinfo.input_components = 3;
     230              : #endif
     231            2 :    jpeg_set_defaults(&cinfo);
     232            2 :    jpeg_set_quality(&cinfo, quality, TRUE);
     233              : 
     234              :    // start compressor
     235            2 :    jpeg_start_compress(&cinfo, TRUE);
     236              : 
     237            2 :    unsigned char * pixels = cairo_image_surface_get_data(sfc);
     238            2 :    int stride = cairo_image_surface_get_stride(sfc);
     239              : 
     240              :    // loop over all lines and compress
     241          102 :    while (cinfo.next_scanline < cinfo.image_height)
     242              :    {
     243              : #ifdef LIBJPEG_TURBO_VERSION
     244          100 :       row_pointer[0] = pixels + (cinfo.next_scanline * stride);
     245              : #else
     246              :       unsigned char row_buf[3 * cinfo.image_width];
     247              :       pix_conv(row_buf, 3, pixels +
     248              :             (cinfo.next_scanline * stride), 4, cinfo.image_width);
     249              :       row_pointer[0] = row_buf;
     250              : #endif
     251          100 :       (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
     252              :    }
     253              : 
     254              :    // finalize and close everything
     255            2 :    jpeg_finish_compress(&cinfo);
     256            2 :    jpeg_destroy_compress(&cinfo);
     257            2 :    *len = jpeg_len;
     258              : 
     259              :    // destroy temporary image surface (if available)
     260            2 :    if (other != NULL)
     261            0 :       cairo_surface_destroy(sfc);
     262              : 
     263            2 :    return CAIRO_STATUS_SUCCESS;
     264              : }
     265              : 
     266              : 
     267              : /*! This is the internal write function which is called by
     268              :  * cairo_image_surface_write_to_jpeg(). It is not exported.
     269              :  */
     270            0 : static cairo_status_t cj_write(void *closure, const unsigned char *data, unsigned int length)
     271              : {
     272            0 :    return write((intptr_t) closure, data, (size_t)length) < (ssize_t)length ?
     273            0 :       CAIRO_STATUS_WRITE_ERROR : CAIRO_STATUS_SUCCESS;
     274              : }
     275              : 
     276              : 
     277              : /*! This function writes JPEG file data from a Cairo image surface by using the
     278              :  * user-supplied stream writer function write_func().
     279              :  * @param sfc Pointer to a Cairo *image* surface. Its format must either be
     280              :  * CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_RGB24. Other formats are not supported
     281              :  * by this function, yet.
     282              :  * @param write_func Function pointer to a function which is actually writing
     283              :  * the data.
     284              :  * @param closure Pointer to user-supplied variable which is directly passed to
     285              :  * write_func().
     286              :  * @param quality Compression quality, 0-100.
     287              :  * @return This function calls cairo_image_surface_write_to_jpeg_mem() and
     288              :  * returns its return value.
     289              :  */
     290            2 : cairo_status_t cairo_image_surface_write_to_jpeg_stream(cairo_surface_t *sfc, cairo_write_func_t write_func, void *closure, int quality)
     291              : {
     292              :    cairo_status_t e;
     293            2 :    unsigned char *data = NULL;
     294            2 :    size_t len = 0;
     295              : 
     296              :    // create JPEG data in memory from surface
     297            2 :    if ((e = cairo_image_surface_write_to_jpeg_mem(sfc, &data, &len, quality)) != CAIRO_STATUS_SUCCESS)
     298            0 :       return e;
     299              : 
     300              :    // write whole memory block with stream function
     301            2 :    e = write_func(closure, data, len);
     302              : 
     303              :    // free JPEG memory again and return the return value
     304            2 :    free(data);
     305            2 :    return e;
     306              : 
     307              : }
     308              : 
     309              : 
     310              : /*! This function creates a JPEG file from a Cairo image surface.
     311              :  * @param sfc Pointer to a Cairo *image* surface. Its format must either be
     312              :  * CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_RGB24. Other formats are not supported
     313              :  * by this function, yet.
     314              :  * @param filename Pointer to the filename.
     315              :  * @param quality Compression quality, 0-100.
     316              :  * @return In case of success CAIRO_STATUS_SUCCESS is returned. If an error
     317              :  * occurred while opening/creating the file CAIRO_STATUS_DEVICE_ERROR is
     318              :  * returned. The error can be tracked down by inspecting errno(3). The function
     319              :  * internally calls cairo_image_surface_write_to_jpeg_stream() and returns
     320              :  * its return value respectively (see there).
     321              :  */
     322            0 : cairo_status_t cairo_image_surface_write_to_jpeg(cairo_surface_t *sfc, const char *filename, int quality)
     323              : {
     324              :    cairo_status_t e;
     325              :    int outfile;
     326              : 
     327              :    // Open/create new file
     328            0 :    if ((outfile = open(filename, O_BINARY | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
     329            0 :       return CAIRO_STATUS_DEVICE_ERROR;
     330              : 
     331              :    // write surface to file
     332            0 :    e = cairo_image_surface_write_to_jpeg_stream(sfc, cj_write, (void*)(intptr_t) outfile, quality);
     333              : 
     334              :    // close file again and return
     335            0 :    close(outfile);
     336            0 :    return e;
     337              : }
     338              : 
     339              : 
     340              : 
     341              : /*! This function decompresses a JPEG image from a memory buffer and creates a
     342              :  * Cairo image surface.
     343              :  * @param data Pointer to JPEG data (i.e. the full contents of a JPEG file read
     344              :  * into this buffer).
     345              :  * @param len Length of buffer in bytes.
     346              :  * @return Returns a pointer to a cairo_surface_t structure. It should be
     347              :  * checked with cairo_surface_status() for errors.
     348              :  */
     349            2 : cairo_surface_t *cairo_image_surface_create_from_jpeg_mem(void *data, size_t len)
     350              : {
     351              :    struct jpeg_decompress_struct cinfo;
     352              :    struct jpeg_error_mgr jerr;
     353              :    JSAMPROW row_pointer[1];
     354              :    cairo_surface_t *sfc;
     355              : 
     356              :    // initialize jpeg decompression structures
     357            2 :    cinfo.err = jpeg_std_error(&jerr);
     358            2 :    jpeg_create_decompress(&cinfo);
     359            2 :    jpeg_mem_src(&cinfo, data, len);
     360            2 :    (void) jpeg_read_header(&cinfo, TRUE);
     361              : 
     362              : #ifdef LIBJPEG_TURBO_VERSION
     363              : #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
     364            2 :    cinfo.out_color_space = JCS_EXT_BGRA;
     365              : #else
     366              :    cinfo.out_color_space = JCS_EXT_ARGB;
     367              : #endif
     368              : #else
     369              :    cinfo.out_color_space = JCS_RGB;
     370              : #endif
     371              : 
     372              :    // start decompressor
     373            2 :    (void) jpeg_start_decompress(&cinfo);
     374              : 
     375              :    // create Cairo image surface
     376            2 :    sfc = cairo_image_surface_create(CAIRO_FORMAT_RGB24, cinfo.output_width, cinfo.output_height);
     377            2 :    if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS)
     378              :    {
     379            0 :       jpeg_destroy_decompress(&cinfo);
     380            0 :       return sfc;
     381              :    }
     382              : 
     383              :    // loop over all scanlines and fill Cairo image surface
     384           22 :    while (cinfo.output_scanline < cinfo.output_height)
     385              :    {
     386           20 :       unsigned char *row_address = cairo_image_surface_get_data(sfc) +
     387           20 :          (cinfo.output_scanline * cairo_image_surface_get_stride(sfc));
     388           20 :       row_pointer[0] = row_address;
     389           20 :       (void) jpeg_read_scanlines(&cinfo, row_pointer, 1);
     390              : #ifndef LIBJPEG_TURBO_VERSION
     391              :       pix_conv(row_address, 4, row_address, 3, cinfo.output_width);
     392              : #endif
     393              :    }
     394              : 
     395              :    // finish and close everything
     396            2 :    cairo_surface_mark_dirty(sfc);
     397            2 :    (void) jpeg_finish_decompress(&cinfo);
     398            2 :    jpeg_destroy_decompress(&cinfo);
     399              : 
     400              :    // set jpeg mime data
     401              :    // cairo_surface_set_mime_data(sfc, CAIRO_MIME_TYPE_JPEG, data, len, free, data);
     402              :    // don't free data
     403            2 :    cairo_surface_set_mime_data(sfc, CAIRO_MIME_TYPE_JPEG, data, len, free, NULL);
     404              : 
     405            2 :    return sfc;
     406              : }
     407              : 
     408              : 
     409              : /*! This function reads a JPEG image from a stream and creates a Cairo image
     410              :  * surface.
     411              :  * @param read_func Pointer to function which reads data.
     412              :  * @param closure Pointer which is passed to read_func().
     413              :  * @return Returns a pointer to a cairo_surface_t structure. It should be
     414              :  * checked with cairo_surface_status() for errors.
     415              :  * @note If the surface returned is invalid you can use errno(3) to determine
     416              :  * further reasons. Errno is set according to realloc(3). If you
     417              :  * intend to check errno you shall set it to 0 before calling this function
     418              :  * because it modifies errno only in case of an error.
     419              :  */
     420              : #ifdef USE_CAIRO_READ_FUNC_LEN_T
     421              : cairo_surface_t *cairo_image_surface_create_from_jpeg_stream(cairo_read_func_len_t read_func, void *closure)
     422              : #else
     423            1 : cairo_surface_t *cairo_image_surface_create_from_jpeg_stream(cairo_read_func_t read_func, void *closure)
     424              : #endif
     425              : {
     426              :    cairo_surface_t *sfc;
     427              :    unsigned char *data, *tmp;
     428              :    ssize_t len, rlen;
     429            1 :    int eof = 0;
     430              : 
     431              :    // read all data into memory buffer in blocks of CAIRO_JPEG_IO_BLOCK_SIZE
     432          636 :    for (len = 0, data = NULL; !eof; len += rlen)
     433              :    {
     434              :       // grow memory buffer and check for error
     435          635 :       if ((tmp = realloc(data, len + CAIRO_JPEG_IO_BLOCK_SIZE)) == NULL)
     436            0 :          break;
     437          635 :       data = tmp;
     438              : 
     439              :       // read bytes into buffer and check for error
     440          635 :       rlen = read_func(closure, data + len, CAIRO_JPEG_IO_BLOCK_SIZE);
     441              : #ifdef USE_CAIRO_READ_FUNC_LEN_T
     442              :       // check for error
     443              :       if (rlen == -1)
     444              :          break;
     445              : 
     446              :       // check if EOF occurred
     447              :       if (rlen < CAIRO_JPEG_IO_BLOCK_SIZE)
     448              :          eof++;
     449              : #else
     450              :       // check for error
     451          635 :       if (rlen == CAIRO_STATUS_READ_ERROR)
     452            1 :          eof++;
     453              : 
     454              :       // manually increase read length because cairo_read_func_t
     455              :       // does not return the actual number of bytes read
     456          635 :       rlen = CAIRO_JPEG_IO_BLOCK_SIZE;
     457              : #endif
     458              :    }
     459              : 
     460              :    // check for error in read loop
     461            1 :    if (!eof)
     462              :    {
     463            0 :       free(data);
     464            0 :       return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
     465              :    }
     466              : 
     467              :    // call jpeg decompression and return surface
     468            1 :    sfc = cairo_image_surface_create_from_jpeg_mem(data, len);
     469            1 :    if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS) {
     470            0 :       free(data);
     471              :     }
     472              : 
     473            1 :    return sfc;
     474              : }
     475              : 
     476              : 
     477              : #ifdef CAIRO_JPEG_USE_FSTAT
     478              : /*! This function reads an JPEG image from a file an creates a Cairo image
     479              :  * surface. Internally the filesize is determined with fstat(2) and then the
     480              :  * whole data is read at once.
     481              :  * @param filename Pointer to filename of JPEG file.
     482              :  * @return Returns a pointer to a cairo_surface_t structure. It should be
     483              :  * checked with cairo_surface_status() for errors.
     484              :  * @note If the returned surface is invalid you can use errno to determine
     485              :  * further reasons. Errno is set according to fopen(3) and malloc(3). If you
     486              :  * intend to check errno you shall set it to 0 before calling this function
     487              :  * because it does not modify errno itself.
     488              :  */
     489            1 : cairo_surface_t *cairo_image_surface_create_from_jpeg(const char *filename)
     490              : {
     491              :    void *data;
     492              :    int infile;
     493              :    struct stat stat;
     494              : 
     495              :    // open input file
     496            1 :    if ((infile = open(filename, O_BINARY | O_RDONLY)) == -1)
     497            0 :       return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
     498              : 
     499              :    // get stat structure for file size
     500            1 :    if (fstat(infile, &stat) == -1)
     501            0 :       return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
     502              : 
     503              :    // allocate memory
     504            1 :    if ((data = malloc(stat.st_size)) == NULL)
     505            0 :       return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
     506              : 
     507              :    // read data
     508            1 :    if (read(infile, data, stat.st_size) < stat.st_size)
     509            0 :       return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
     510              : 
     511            1 :    close(infile);
     512              : 
     513            1 :    return cairo_image_surface_create_from_jpeg_mem(data, stat.st_size);
     514              : }
     515              : 
     516              : #else
     517              : 
     518              : 
     519              : /*! This is the read function which is called by
     520              :  * cairo_image_surface_create_from_jpeg_stream() (non-fstat-version below). It
     521              :  * is not exported.
     522              :  */
     523              : #ifdef USE_CAIRO_READ_FUNC_LEN_T
     524              : static ssize_t cj_read(void *closure, unsigned char *data, unsigned int length)
     525              : {
     526              :    return read((intptr_t) closure, data, length);
     527              : }
     528              : #else
     529              : static cairo_status_t cj_read(void *closure, unsigned char *data, unsigned int length)
     530              : {
     531              :    return read((intptr_t) closure, data, length) < length ? CAIRO_STATUS_READ_ERROR : CAIRO_STATUS_SUCCESS;
     532              : }
     533              : #endif
     534              : 
     535              : 
     536              : /*! This function reads an JPEG image from a file an creates a Cairo image
     537              :  * surface. Internally the function calls
     538              :  * cairo_image_surface_create_from_jpeg_stream() to actually read the data.
     539              :  * @param filename Pointer to filename of JPEG file.
     540              :  * @return Returns a pointer to a cairo_surface_t structure. It should be
     541              :  * checked with cairo_surface_status() for errors.
     542              :  * @note If the returned surface is invalid you can use errno to determine
     543              :  * further reasons. Errno is set according to fopen(3) and malloc(3). If you
     544              :  * intend to check errno you shall set it to 0 before calling this function
     545              :  * because it does not modify errno itself.
     546              :  */
     547              : cairo_surface_t *cairo_image_surface_create_from_jpeg(const char *filename)
     548              : {
     549              :    cairo_surface_t *sfc;
     550              :    int infile;
     551              : 
     552              :    // open input file
     553              :    if ((infile = open(filename, O_RDONLY)) == -1)
     554              :       return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
     555              : 
     556              :    // call stream loading function
     557              :    sfc = cairo_image_surface_create_from_jpeg_stream(cj_read, (void*)(intptr_t) infile);
     558              :    close(infile);
     559              : 
     560              :    return sfc;
     561              : }
     562              : 
     563              : #endif
     564              : 
     565              : 
     566              : #ifdef CAIRO_JPEG_MAIN
     567              : #include <string.h>
     568              : #include <strings.h>
     569              : 
     570              : int strrcasecmp(const char *s1, const char *s2)
     571              : {
     572              :    int off = (int) strlen(s1) - (int) strlen(s2); // typecast size_t to int because size_t typically is unsigned
     573              :    return strcasecmp(s1 + (off < 0 ? 0 : off), s2);
     574              : }
     575              : 
     576              : /*! Main routine, only for testing. #undef CAIRO_JPEG_MAIN or simply delete
     577              :  * this part if you link this file to your own program.
     578              :  */
     579              : int main(int argc, char **argv)
     580              : {
     581              :    cairo_surface_t *sfc;
     582              : 
     583              : #ifndef CAIRO_JPEG_TEST_SIMILAR
     584              :    if (argc < 3)
     585              :    {
     586              :       fprintf(stderr, "usage: %s <infile> <outfile>\n", argv[0]);
     587              :       return 1;
     588              :    }
     589              : 
     590              :    // test input file type and read file
     591              :    if (!strrcasecmp(argv[1], ".png"))
     592              :    {
     593              :       // read PNG file
     594              :       sfc = cairo_image_surface_create_from_png(argv[1]);
     595              :    }
     596              :    else if (!strrcasecmp(argv[1], ".jpg"))
     597              :    {
     598              :       // read JPEG file
     599              :       sfc = cairo_image_surface_create_from_jpeg(argv[1]);
     600              :    }
     601              :    else
     602              :    {
     603              :       fprintf(stderr, "source file is neither JPG nor PNG\n");
     604              :       return 1;
     605              :    }
     606              : 
     607              :    // check surface status
     608              :    if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS)
     609              :    {
     610              :       fprintf(stderr, "error loading image: %s", cairo_status_to_string(cairo_surface_status(sfc)));
     611              :       return 2;
     612              :    }
     613              : 
     614              :    // test output file type and write file
     615              :    if (!strrcasecmp(argv[2], ".png"))
     616              :    {
     617              :        // write PNG file
     618              :       cairo_surface_write_to_png(sfc, argv[2]);
     619              :    }
     620              :    else if (!strrcasecmp(argv[2], ".jpg"))
     621              :    {
     622              :       // write JPEG file
     623              :       cairo_image_surface_write_to_jpeg(sfc, argv[2], 90);
     624              :    }
     625              :    else
     626              :    {
     627              :       fprintf(stderr, "destination file is neither JPG nor PNG\n");
     628              :       return 1;
     629              :    }
     630              : 
     631              :    cairo_surface_destroy(sfc);
     632              : 
     633              : #else
     634              :    sfc = cairo_pdf_surface_create("xyz.pdf", 595.276, 841.890);
     635              : 
     636              :    cairo_t *ctx = cairo_create(sfc);
     637              :    cairo_set_source_rgb(ctx, 1, 1, 1);
     638              :    cairo_paint(ctx);
     639              :    cairo_move_to(ctx, 100, 100);
     640              :    cairo_set_source_rgb(ctx, 1, 0, 0);
     641              :    cairo_set_line_width(ctx, 3);
     642              :    cairo_line_to(ctx, 400, 400);
     643              :    cairo_stroke(ctx);
     644              :    cairo_destroy(ctx);
     645              : 
     646              :    cairo_image_surface_write_to_jpeg(sfc, "xyz.jpg", 90);
     647              :    cairo_surface_destroy(sfc);
     648              : #endif
     649              : 
     650              :    return 0;
     651              : }
     652              : 
     653              : #endif
     654              : 
     655              : #endif
        

Generated by: LCOV version 2.0-1