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 2 : cairo_surface_set_mime_data(
402 : sfc, CAIRO_MIME_TYPE_JPEG, data, len, free, data
403 : );
404 2 : return sfc;
405 : }
406 :
407 :
408 : /*! This function reads a JPEG image from a stream and creates a Cairo image
409 : * surface.
410 : * @param read_func Pointer to function which reads data.
411 : * @param closure Pointer which is passed to read_func().
412 : * @return Returns a pointer to a cairo_surface_t structure. It should be
413 : * checked with cairo_surface_status() for errors.
414 : * @note If the surface returned is invalid you can use errno(3) to determine
415 : * further reasons. Errno is set according to realloc(3). If you
416 : * intend to check errno you shall set it to 0 before calling this function
417 : * because it modifies errno only in case of an error.
418 : */
419 : #ifdef USE_CAIRO_READ_FUNC_LEN_T
420 : cairo_surface_t *cairo_image_surface_create_from_jpeg_stream(cairo_read_func_len_t read_func, void *closure)
421 : #else
422 1 : cairo_surface_t *cairo_image_surface_create_from_jpeg_stream(cairo_read_func_t read_func, void *closure)
423 : #endif
424 : {
425 : cairo_surface_t *sfc;
426 : unsigned char *data, *tmp;
427 : ssize_t len, rlen;
428 1 : int eof = 0;
429 :
430 : // read all data into memory buffer in blocks of CAIRO_JPEG_IO_BLOCK_SIZE
431 636 : for (len = 0, data = NULL; !eof; len += rlen)
432 : {
433 : // grow memory buffer and check for error
434 635 : if ((tmp = realloc(data, len + CAIRO_JPEG_IO_BLOCK_SIZE)) == NULL)
435 0 : break;
436 635 : data = tmp;
437 :
438 : // read bytes into buffer and check for error
439 635 : rlen = read_func(closure, data + len, CAIRO_JPEG_IO_BLOCK_SIZE);
440 : #ifdef USE_CAIRO_READ_FUNC_LEN_T
441 : // check for error
442 : if (rlen == -1)
443 : break;
444 :
445 : // check if EOF occurred
446 : if (rlen < CAIRO_JPEG_IO_BLOCK_SIZE)
447 : eof++;
448 : #else
449 : // check for error
450 635 : if (rlen == CAIRO_STATUS_READ_ERROR)
451 1 : eof++;
452 :
453 : // manually increase read length because cairo_read_func_t
454 : // does not return the actual number of bytes read
455 635 : rlen = CAIRO_JPEG_IO_BLOCK_SIZE;
456 : #endif
457 : }
458 :
459 : // check for error in read loop
460 1 : if (!eof)
461 : {
462 0 : free(data);
463 0 : return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
464 : }
465 :
466 : // call jpeg decompression and return surface
467 1 : sfc = cairo_image_surface_create_from_jpeg_mem(data, len);
468 1 : if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS) {
469 0 : free(data);
470 : }
471 :
472 1 : return sfc;
473 : }
474 :
475 :
476 : #ifdef CAIRO_JPEG_USE_FSTAT
477 : /*! This function reads an JPEG image from a file an creates a Cairo image
478 : * surface. Internally the filesize is determined with fstat(2) and then the
479 : * whole data is read at once.
480 : * @param filename Pointer to filename of JPEG file.
481 : * @return Returns a pointer to a cairo_surface_t structure. It should be
482 : * checked with cairo_surface_status() for errors.
483 : * @note If the returned surface is invalid you can use errno to determine
484 : * further reasons. Errno is set according to fopen(3) and malloc(3). If you
485 : * intend to check errno you shall set it to 0 before calling this function
486 : * because it does not modify errno itself.
487 : */
488 1 : cairo_surface_t *cairo_image_surface_create_from_jpeg(const char *filename)
489 : {
490 : void *data;
491 : int infile;
492 : struct stat stat;
493 : cairo_surface_t *sfc;
494 :
495 : // open input file
496 1 : if ((infile = open(filename, O_BINARY | O_RDONLY)) == -1) {
497 0 : close(infile);
498 0 : return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
499 : }
500 :
501 : // get stat structure for file size
502 1 : if (fstat(infile, &stat) == -1) {
503 0 : close(infile);
504 0 : return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
505 : }
506 :
507 : // allocate memory
508 1 : if ((data = malloc(stat.st_size)) == NULL) {
509 0 : close(infile);
510 0 : return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
511 : }
512 :
513 : // read data
514 1 : if (read(infile, data, stat.st_size) < stat.st_size) {
515 0 : free(data);
516 0 : close(infile);
517 0 : return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
518 : }
519 :
520 1 : close(infile);
521 :
522 1 : sfc = cairo_image_surface_create_from_jpeg_mem(data, stat.st_size);
523 1 : if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS) {
524 0 : free(data);
525 : }
526 :
527 1 : return sfc;
528 : }
529 :
530 : #else
531 :
532 :
533 : /*! This is the read function which is called by
534 : * cairo_image_surface_create_from_jpeg_stream() (non-fstat-version below). It
535 : * is not exported.
536 : */
537 : #ifdef USE_CAIRO_READ_FUNC_LEN_T
538 : static ssize_t cj_read(void *closure, unsigned char *data, unsigned int length)
539 : {
540 : return read((intptr_t) closure, data, length);
541 : }
542 : #else
543 : static cairo_status_t cj_read(void *closure, unsigned char *data, unsigned int length)
544 : {
545 : return read((intptr_t) closure, data, length) < length ? CAIRO_STATUS_READ_ERROR : CAIRO_STATUS_SUCCESS;
546 : }
547 : #endif
548 :
549 :
550 : /*! This function reads an JPEG image from a file an creates a Cairo image
551 : * surface. Internally the function calls
552 : * cairo_image_surface_create_from_jpeg_stream() to actually read the data.
553 : * @param filename Pointer to filename of JPEG file.
554 : * @return Returns a pointer to a cairo_surface_t structure. It should be
555 : * checked with cairo_surface_status() for errors.
556 : * @note If the returned surface is invalid you can use errno to determine
557 : * further reasons. Errno is set according to fopen(3) and malloc(3). If you
558 : * intend to check errno you shall set it to 0 before calling this function
559 : * because it does not modify errno itself.
560 : */
561 : cairo_surface_t *cairo_image_surface_create_from_jpeg(const char *filename)
562 : {
563 : cairo_surface_t *sfc;
564 : int infile;
565 :
566 : // open input file
567 : if ((infile = open(filename, O_RDONLY)) == -1)
568 : return cairo_image_surface_create(CAIRO_FORMAT_INVALID, 0, 0);
569 :
570 : // call stream loading function
571 : sfc = cairo_image_surface_create_from_jpeg_stream(cj_read, (void*)(intptr_t) infile);
572 : close(infile);
573 :
574 : return sfc;
575 : }
576 :
577 : #endif
578 :
579 :
580 : #ifdef CAIRO_JPEG_MAIN
581 : #include <string.h>
582 : #include <strings.h>
583 :
584 : int strrcasecmp(const char *s1, const char *s2)
585 : {
586 : int off = (int) strlen(s1) - (int) strlen(s2); // typecast size_t to int because size_t typically is unsigned
587 : return strcasecmp(s1 + (off < 0 ? 0 : off), s2);
588 : }
589 :
590 : /*! Main routine, only for testing. #undef CAIRO_JPEG_MAIN or simply delete
591 : * this part if you link this file to your own program.
592 : */
593 : int main(int argc, char **argv)
594 : {
595 : cairo_surface_t *sfc;
596 :
597 : #ifndef CAIRO_JPEG_TEST_SIMILAR
598 : if (argc < 3)
599 : {
600 : fprintf(stderr, "usage: %s <infile> <outfile>\n", argv[0]);
601 : return 1;
602 : }
603 :
604 : // test input file type and read file
605 : if (!strrcasecmp(argv[1], ".png"))
606 : {
607 : // read PNG file
608 : sfc = cairo_image_surface_create_from_png(argv[1]);
609 : }
610 : else if (!strrcasecmp(argv[1], ".jpg"))
611 : {
612 : // read JPEG file
613 : sfc = cairo_image_surface_create_from_jpeg(argv[1]);
614 : }
615 : else
616 : {
617 : fprintf(stderr, "source file is neither JPG nor PNG\n");
618 : return 1;
619 : }
620 :
621 : // check surface status
622 : if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS)
623 : {
624 : fprintf(stderr, "error loading image: %s", cairo_status_to_string(cairo_surface_status(sfc)));
625 : return 2;
626 : }
627 :
628 : // test output file type and write file
629 : if (!strrcasecmp(argv[2], ".png"))
630 : {
631 : // write PNG file
632 : cairo_surface_write_to_png(sfc, argv[2]);
633 : }
634 : else if (!strrcasecmp(argv[2], ".jpg"))
635 : {
636 : // write JPEG file
637 : cairo_image_surface_write_to_jpeg(sfc, argv[2], 90);
638 : }
639 : else
640 : {
641 : fprintf(stderr, "destination file is neither JPG nor PNG\n");
642 : return 1;
643 : }
644 :
645 : cairo_surface_destroy(sfc);
646 :
647 : #else
648 : sfc = cairo_pdf_surface_create("xyz.pdf", 595.276, 841.890);
649 :
650 : cairo_t *ctx = cairo_create(sfc);
651 : cairo_set_source_rgb(ctx, 1, 1, 1);
652 : cairo_paint(ctx);
653 : cairo_move_to(ctx, 100, 100);
654 : cairo_set_source_rgb(ctx, 1, 0, 0);
655 : cairo_set_line_width(ctx, 3);
656 : cairo_line_to(ctx, 400, 400);
657 : cairo_stroke(ctx);
658 : cairo_destroy(ctx);
659 :
660 : cairo_image_surface_write_to_jpeg(sfc, "xyz.jpg", 90);
661 : cairo_surface_destroy(sfc);
662 : #endif
663 :
664 : return 0;
665 : }
666 :
667 : #endif
668 :
669 : #endif
|