e59e8502 |
1 | /* Modified for clg by esj */ |
2 | |
3 | /* Copyright 2005 Google Inc. All Rights Reserved. |
4 | * Author: yangzh@google.com (Zhonghao Yang) |
5 | * |
6 | * Google's own patch to add jpeg I/O support for cairo. |
7 | * |
8 | */ |
9 | |
10 | /* cairo - a vector graphics library with display and print output |
11 | * |
12 | * Copyright © 2003 University of Southern California |
13 | * |
14 | * This library is free software; you can redistribute it and/or |
15 | * modify it either under the terms of the GNU Lesser General Public |
16 | * License version 2.1 as published by the Free Software Foundation |
17 | * (the "LGPL") or, at your option, under the terms of the Mozilla |
18 | * Public License Version 1.1 (the "MPL"). If you do not alter this |
19 | * notice, a recipient may use your version of this file under either |
20 | * the MPL or the LGPL. |
21 | * |
22 | * You should have received a copy of the LGPL along with this library |
23 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
25 | * You should have received a copy of the MPL along with this library |
26 | * in the file COPYING-MPL-1.1 |
27 | * |
28 | * The contents of this file are subject to the Mozilla Public License |
29 | * Version 1.1 (the "License"); you may not use this file except in |
30 | * compliance with the License. You may obtain a copy of the License at |
31 | * http://www.mozilla.org/MPL/ |
32 | * |
33 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
34 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
35 | * the specific language governing rights and limitations. |
36 | * |
37 | * The Original Code is the cairo graphics library. |
38 | * |
39 | * The Initial Developer of the Original Code is University of Southern |
40 | * California. |
41 | * |
42 | * Contributor(s): |
43 | * Carl D. Worth <cworth@cworth.org> |
44 | * Kristian Høgsberg <krh@redhat.com> |
45 | */ |
46 | |
47 | #include <stdio.h> |
48 | #include <stdint.h> |
49 | #include <string.h> |
50 | #include <stdlib.h> |
51 | #include <setjmp.h> |
52 | #include <errno.h> |
53 | #include <jpeglib.h> |
54 | #include <cairo.h> |
55 | #include "cairo-lut-private.h" |
56 | #include "cairo-prebuilt-lut.h" |
57 | |
58 | #define BUF_SIZE_JPEG 4096 |
59 | |
60 | struct clg_error_mgr { |
61 | struct jpeg_error_mgr pub; |
62 | jmp_buf setjmp_buffer; |
63 | }; |
64 | |
65 | typedef struct clg_error_mgr *error_ptr; |
66 | |
67 | static void |
68 | _error_exit (j_common_ptr cinfo) |
69 | { |
70 | error_ptr err = (error_ptr) cinfo->err; |
71 | |
72 | (*cinfo->err->output_message) (cinfo); |
73 | longjmp(err->setjmp_buffer, 1); |
74 | } |
75 | |
76 | |
77 | typedef unsigned int (*cairo_jpeg_read_func_t) |
78 | (void *closure, |
79 | unsigned char *data, |
80 | unsigned int length); |
81 | |
82 | struct read_closure { |
83 | /** |
84 | * Model underlying system's read behavior: |
85 | * data can be read from stdio, stream, or anything. |
86 | */ |
87 | cairo_jpeg_read_func_t jpeg_func; |
88 | |
89 | /** |
90 | * Auxiliary data: |
91 | * For stdio, this should be struct file_closure * |
92 | */ |
93 | void *user_data; |
94 | /* |
95 | * Buffer for reading from |
96 | */ |
97 | unsigned char block[BUF_SIZE_JPEG]; |
98 | |
99 | cairo_status_t status; |
100 | }; |
101 | |
102 | /* |
103 | * Read function for stdio. |
104 | * Check length of read and return error if necessary. |
105 | */ |
106 | static |
107 | unsigned int stdio_read_func (void *closure, |
108 | unsigned char *data, |
109 | unsigned int length) |
110 | { |
111 | return fread((void *)data, 1, length, (FILE *)closure); |
112 | } |
113 | |
114 | /* |
115 | * Initialize source. |
116 | * called by jpeg_read_header before any data is actually read. |
117 | */ |
118 | static void init_source_custom (j_decompress_ptr cinfo) |
119 | { |
120 | cinfo->src->bytes_in_buffer = 0; |
121 | } |
122 | |
123 | /* |
124 | * Fill the input buffer. |
125 | * called whenever buffer is emptied. |
126 | */ |
127 | static boolean fill_input_buffer_custom (j_decompress_ptr cinfo) |
128 | { |
129 | struct read_closure *closure = (struct read_closure*) (cinfo->client_data); |
130 | unsigned int len; |
131 | |
132 | len = (*closure->jpeg_func) (closure->user_data, |
133 | closure->block, BUF_SIZE_JPEG); |
134 | |
135 | if (len == 0) { |
136 | /* really hit EOF in the beginning: insert a fake EOI marker. */ |
137 | static const unsigned char jpeg_eof[] = { 0xFF, JPEG_EOI }; |
138 | cinfo->src->bytes_in_buffer = 2; |
139 | cinfo->src->next_input_byte = jpeg_eof; |
140 | } else { |
141 | cinfo->src->bytes_in_buffer = len; |
142 | cinfo->src->next_input_byte = closure->block; |
143 | } |
144 | return TRUE; |
145 | } |
146 | |
147 | |
148 | /* |
149 | * Skip data. |
150 | * used to skip over a potentially large amount of uninteresting |
151 | * data (such as APPn marker). |
152 | * Writers of suspendable-input applications must note that skip_input_data |
153 | * is not granted the right to give a suspension return. If the skip extends |
154 | * beyond the data currently in the buffer, the buffer can be marked empty so |
155 | * that the next read will cause a fill_input_buffer call that can suspend. |
156 | * Arranging for additional bytes to be discarded before reloading the input |
157 | * buffer is the application writer's problem. |
158 | */ |
159 | static void skip_input_data_custom (j_decompress_ptr cinfo, long num_bytes) |
160 | { |
161 | while (num_bytes > (long) (cinfo->src->bytes_in_buffer)) { |
162 | num_bytes -= (long) (cinfo->src->bytes_in_buffer); |
163 | fill_input_buffer_custom (cinfo); |
164 | } |
165 | |
166 | cinfo->src->next_input_byte += (size_t) num_bytes; |
167 | cinfo->src->bytes_in_buffer -= (size_t) num_bytes; |
168 | } |
169 | |
170 | /* |
171 | * Terminate source. |
172 | * called by jpeg_finish_decompress after all data has been read. |
173 | * Often a no-op. |
174 | */ |
175 | static void term_source_custom (j_decompress_ptr cinfo) |
176 | { |
177 | } |
178 | |
179 | /* |
180 | * read jpeg from any source. |
181 | */ |
182 | static cairo_surface_t * |
183 | read_jpeg (struct read_closure *closure) |
184 | { |
185 | cairo_surface_t *surface = NULL; |
186 | |
187 | struct jpeg_decompress_struct cinfo; |
188 | struct clg_error_mgr jerr; |
189 | struct jpeg_source_mgr src; |
190 | |
191 | int channels; |
192 | uint8_t *data; |
193 | int stride; |
194 | |
195 | JSAMPROW row = NULL; |
196 | JSAMPROW rowptr[1]; |
197 | |
198 | register JSAMPROW src_pixel; |
199 | register uint32_t *dst_pixel; |
200 | unsigned int i, j; |
201 | |
202 | closure->status = CAIRO_STATUS_SUCCESS; |
203 | |
204 | /* Step 1: Allocate and initialize a JPEG decompression object */ |
205 | /* Step 2: Specify the source of the compressed data (eg, a file) */ |
206 | memset (&cinfo, 0, sizeof (cinfo)); |
207 | memset (&jerr, 0, sizeof (jerr)); |
208 | |
209 | cinfo.err = jpeg_std_error (&jerr.pub); |
210 | jerr.pub.error_exit = _error_exit; |
211 | if (setjmp(jerr.setjmp_buffer)) |
212 | goto ERROR; |
213 | |
214 | jpeg_create_decompress (&cinfo); |
215 | |
216 | cinfo.client_data = closure; |
217 | |
218 | src.init_source = init_source_custom; |
219 | src.fill_input_buffer = fill_input_buffer_custom; |
220 | src.skip_input_data = skip_input_data_custom; |
221 | src.resync_to_restart = jpeg_resync_to_restart; /* JPEG library default */ |
222 | src.term_source = term_source_custom; |
223 | src.bytes_in_buffer = 0; /* forces fill_input_buffer on first read. */ |
224 | src.next_input_byte = NULL; /* until buffer loaded. */ |
225 | cinfo.src = &src; |
226 | |
227 | /* save the APP14 marker to check for Adobe Photoshop CMYK */ |
228 | /* files with inverted components. */ |
229 | jpeg_save_markers (&cinfo, JPEG_APP0 + 14, 256); |
230 | |
231 | /* Step 3: Call jpeg_read_header() to obtain image info. */ |
232 | if (jpeg_read_header (&cinfo, TRUE) != JPEG_HEADER_OK) |
233 | goto ERROR; |
234 | |
235 | /* if (cinfo.image_height > INT_MAX || cinfo.image_width > INT_MAX) */ |
236 | /* goto BAIL1; */ |
237 | |
238 | /* NOTE(yangzh): do not support these two yet. */ |
239 | if (cinfo.jpeg_color_space == JCS_CMYK || cinfo.jpeg_color_space == JCS_YCCK) |
240 | goto ERROR; |
241 | |
242 | cinfo.out_color_space = JCS_RGB; |
243 | |
244 | /* the fastest, but less accurate integer method for DCT. */ |
245 | /* not recommende if high quality is a concern. we do not have this issue. */ |
246 | cinfo.dct_method = JDCT_IFAST; |
247 | |
248 | /* Step 4: Set target cairo image. |
249 | * for CAIRO_FORMAT_ARGB32, every pixel will take 4 bytes. |
250 | */ |
251 | surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, |
252 | cinfo.image_width, |
253 | cinfo.image_height); |
254 | if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) { |
255 | closure->status = cairo_surface_status (surface); |
256 | goto ERROR; |
257 | } |
258 | |
259 | /* Step 5: jpeg_start_decompress(...); */ |
260 | jpeg_start_decompress (&cinfo); |
261 | |
262 | /* Step 6: while (scan lines remain to be read) */ |
263 | /* jpeg_read_scanlines(...); */ |
264 | channels = 3; |
265 | row = (JSAMPROW) malloc (cinfo.output_width * channels * sizeof (JSAMPLE)); |
266 | if (row == NULL) { |
267 | closure->status = CAIRO_STATUS_NO_MEMORY; |
268 | goto ERROR; |
269 | } |
270 | |
271 | data = cairo_image_surface_get_data (surface); |
272 | stride = cairo_image_surface_get_stride (surface); |
273 | |
274 | rowptr[0] = row; |
275 | for (i = 0; i < cinfo.output_height; i++) { |
276 | jpeg_read_scanlines (&cinfo, rowptr, 1); |
277 | src_pixel = row; |
278 | dst_pixel = (uint32_t*)(data + i * stride); |
279 | for (j = 0; j < cinfo.output_width; j++, src_pixel += channels, dst_pixel++) { |
280 | /* Store ARGB in native endian. */ |
281 | *dst_pixel = (0xFF << 24) /* always 0xFF in alpha channel. */ |
282 | + (src_pixel[0] << 16) |
283 | + (src_pixel[1] << 8) |
284 | + (src_pixel[2]); |
285 | } |
286 | } |
287 | |
288 | /* Step 7: jpeg_finish_decompress(...); */ |
289 | jpeg_finish_decompress (&cinfo); |
290 | goto EXIT; |
291 | |
292 | ERROR: |
293 | if (surface) { |
294 | cairo_surface_destroy (surface); |
295 | surface = NULL; |
296 | } |
297 | if (closure->status == CAIRO_STATUS_SUCCESS) |
298 | closure->status = CAIRO_STATUS_READ_ERROR; |
299 | |
300 | EXIT: |
301 | /* Release other buffers used in this function. */ |
302 | if (row) |
303 | free (row); |
304 | |
305 | /* Step 8: Release the JPEG decompression object. */ |
306 | jpeg_destroy_decompress (&cinfo); |
307 | |
308 | return surface; |
309 | } |
310 | |
311 | cairo_surface_t * |
312 | cairo_image_surface_create_from_jpeg (const char *filename, |
313 | cairo_status_t *status) |
314 | { |
315 | struct read_closure jpeg_closure; |
316 | FILE *fp; |
317 | cairo_surface_t *surface; |
318 | |
319 | fp = fopen (filename, "rb"); |
320 | if (fp == NULL) { |
321 | switch (errno) { |
322 | case ENOMEM: |
323 | *status = CAIRO_STATUS_NO_MEMORY; |
324 | return NULL; |
325 | case ENOENT: |
326 | *status = CAIRO_STATUS_FILE_NOT_FOUND; |
327 | return NULL; |
328 | default: |
329 | *status = CAIRO_STATUS_READ_ERROR; |
330 | return NULL; |
331 | } |
332 | } |
333 | |
334 | jpeg_closure.jpeg_func = stdio_read_func; |
335 | jpeg_closure.user_data = (void*) fp; |
336 | |
337 | surface = read_jpeg (&jpeg_closure); |
338 | fclose (fp); |
339 | |
340 | *status = jpeg_closure.status; |
341 | return surface; |
342 | } |
343 | |
344 | cairo_surface_t * |
345 | cairo_image_surface_create_from_jpeg_stream (cairo_jpeg_read_func_t read_func, |
346 | void *closure, |
347 | cairo_status_t *status) |
348 | { |
349 | struct read_closure jpeg_closure; |
350 | jpeg_closure.jpeg_func = read_func; |
351 | jpeg_closure.user_data = closure; |
352 | |
353 | cairo_surface_t *surface = read_jpeg (&jpeg_closure); |
354 | |
355 | *status = jpeg_closure.status; |
356 | return surface; |
357 | } |
358 | |
359 | |
360 | typedef struct _cairo_jpeg_parameter { |
361 | int quality; |
362 | cairo_bool_t interlace; |
363 | } cairo_jpeg_parameter_t; |
364 | |
365 | void cairo_get_default_jpeg_parameter (cairo_jpeg_parameter_t *param); |
366 | |
367 | typedef unsigned int (*cairo_jpeg_write_func_t) |
368 | (void *closure, |
369 | const unsigned char *data, |
370 | unsigned int length); |
371 | |
372 | struct write_closure { |
373 | cairo_jpeg_write_func_t jpeg_func; |
374 | |
375 | /** |
376 | * Auxiliary data: |
377 | * For stdio, this should be struct file_closure * |
378 | */ |
379 | void *user_data; |
380 | /* |
381 | * Buffer for writing to. |
382 | */ |
383 | unsigned char block[BUF_SIZE_JPEG]; |
384 | }; |
385 | |
386 | /* |
387 | * write func for stdio. |
388 | * since closure_data->byte_written contains enough diagnostic information, |
389 | * we always return SUCCESS here. |
390 | */ |
391 | static |
392 | cairo_status_t stdio_write_func (void *closure, |
393 | const unsigned char *data, |
394 | unsigned int length) |
395 | { |
396 | return fwrite(data, 1, length, (FILE *)closure); |
397 | } |
398 | |
399 | /* |
400 | * Initialize destination. |
401 | * called by jpeg_start_compress before any data is actually written. |
402 | */ |
403 | static void init_destination_jpeg_custom (j_compress_ptr cinfo) |
404 | { |
405 | struct write_closure *closure = (struct write_closure*) (cinfo->client_data); |
406 | cinfo->dest->next_output_byte = closure->block; |
407 | cinfo->dest->free_in_buffer = BUF_SIZE_JPEG; |
408 | } |
409 | |
410 | /* |
411 | * Empty buffer. |
412 | * called whenever buffer fills up. |
413 | * In typical applications, this should write the entire output buffer |
414 | * (ignoring the current state of next_output_byte & free_in_buffer), |
415 | * reset the pointer & count to the start of the buffer, and return TRUE |
416 | * indicating that the buffer has been dumped. |
417 | * |
418 | * In applications that need to be able to suspend compression due to output |
419 | * overrun, a FALSE return indicates that the buffer cannot be emptied now. |
420 | * In this situation, the compressor will return to its caller (possibly with |
421 | * an indication that it has not accepted all the supplied scanlines). The |
422 | * application should resume compression after it has made more room in the |
423 | * output buffer. Note that there are substantial restrictions on the use of |
424 | * suspension --- see the documentation. |
425 | * |
426 | * When suspending, the compressor will back up to a convenient restart point |
427 | * (typically the start of the current MCU). next_output_byte & free_in_buffer |
428 | * indicate where the restart point will be if the current call returns FALSE. |
429 | * Data beyond this point will be regenerated after resumption, so do not |
430 | * write it out when emptying the buffer externally. |
431 | */ |
432 | static boolean empty_output_buffer_jpeg_custom (j_compress_ptr cinfo) |
433 | { |
434 | struct write_closure *closure = (struct write_closure*) (cinfo->client_data); |
435 | int len; |
436 | len = (*closure->jpeg_func) (closure->user_data, |
437 | closure->block, BUF_SIZE_JPEG); |
438 | if (len != BUF_SIZE_JPEG) { |
439 | /* seems not all remaining bytes in buffer has been dumped yet. */ |
440 | /* by return FALSE, we reply on JPEG's error handling machnism? */ |
441 | return FALSE; |
442 | } |
443 | cinfo->dest->next_output_byte = closure->block; |
444 | cinfo->dest->free_in_buffer = BUF_SIZE_JPEG; |
445 | return TRUE; |
446 | } |
447 | |
448 | /* |
449 | * Terminate destination. |
450 | * called by jpeg_finish_compress afer all data has been written. |
451 | * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding |
452 | * application must deal with any cleanup that should happen even |
453 | * for error exit. |
454 | */ |
455 | static void term_destination_jpeg_custom (j_compress_ptr cinfo) |
456 | { |
457 | struct write_closure *closure = (struct write_closure*) (cinfo->client_data); |
458 | unsigned int len; |
459 | len = BUF_SIZE_JPEG - cinfo->dest->free_in_buffer; |
460 | if (len > 0) |
461 | (*closure->jpeg_func) (closure->user_data, closure->block, len); |
462 | } |
463 | |
464 | static cairo_status_t |
465 | write_jpeg (cairo_surface_t *surface, void* closure, |
466 | const cairo_jpeg_parameter_t *parameter) |
467 | { |
468 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
469 | |
470 | struct jpeg_compress_struct cinfo; |
471 | struct clg_error_mgr jerr; |
472 | struct jpeg_destination_mgr dest; |
473 | cairo_jpeg_parameter_t *param, default_parameters; |
474 | |
475 | JSAMPROW row = NULL; |
476 | JSAMPROW rowptr[1]; |
477 | |
478 | register uint32_t *src_pixel; |
479 | register uint8_t *src_pixel_gray; |
480 | register JSAMPROW dst_pixel; |
481 | unsigned int i, j; |
482 | int convert_alpha; |
483 | |
484 | param = (cairo_jpeg_parameter_t *)parameter; |
485 | if (param == NULL) { |
486 | param = &default_parameters; |
487 | cairo_get_default_jpeg_parameter(param); |
488 | } |
489 | |
490 | |
491 | /* Step 1: Allocate and initialize a JPEG compression object. */ |
492 | memset (&cinfo, 0, sizeof (cinfo)); |
493 | memset (&jerr, 0, sizeof (jerr)); |
494 | |
495 | cinfo.err = jpeg_std_error (&jerr.pub); |
496 | jerr.pub.error_exit = _error_exit; |
497 | if (setjmp(jerr.setjmp_buffer)) |
498 | goto BAIL; |
499 | |
500 | jpeg_create_compress (&cinfo); |
501 | |
502 | /* Step 2: Specify the destination for the compressed data. */ |
503 | cinfo.client_data = closure; |
504 | |
505 | dest.init_destination = init_destination_jpeg_custom; |
506 | dest.empty_output_buffer = empty_output_buffer_jpeg_custom; |
507 | dest.term_destination = term_destination_jpeg_custom; |
508 | dest.next_output_byte = NULL; |
509 | dest.free_in_buffer = 0; |
510 | cinfo.dest = &dest; |
511 | |
512 | /* Step 3: Set parameters for compression, image size & colorspace, etc. */ |
513 | cinfo.image_width = cairo_image_surface_get_width (surface); |
514 | cinfo.image_height = cairo_image_surface_get_height (surface); |
515 | convert_alpha = 0; |
516 | |
517 | switch (cairo_image_surface_get_format (surface)) { |
518 | case CAIRO_FORMAT_RGB24: |
519 | cinfo.input_components = 3; /* # of color components per pixel */ |
520 | cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ |
521 | break; |
522 | case CAIRO_FORMAT_ARGB32: |
523 | cinfo.input_components = 3; /* # of color components per pixel */ |
524 | cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ |
525 | convert_alpha = 1; |
526 | break; |
527 | case CAIRO_FORMAT_A8: /* Put A channel into a grayscale JPEG image. */ |
528 | case CAIRO_FORMAT_A1: /* Put A channel into a "binary" JPEG image. */ |
529 | cinfo.input_components = 1; |
530 | cinfo.in_color_space = JCS_GRAYSCALE; |
531 | default: |
532 | status = CAIRO_STATUS_NULL_POINTER; |
533 | goto BAIL; |
534 | } |
535 | |
536 | jpeg_set_defaults (&cinfo); /* set compression parameters all default values. */ |
537 | |
538 | /* the fastest, but less accurate integer method for DCT. */ |
539 | /* not recommende if high quality is a concern. we do not have this issue. */ |
540 | cinfo.dct_method = JDCT_IFAST; |
541 | |
542 | if (param->quality >= 0) |
543 | jpeg_set_quality(&cinfo, param->quality, TRUE); |
544 | |
545 | /* If user requests interlace, translate that to progressive JPEG */ |
546 | if (param->interlace) |
547 | jpeg_simple_progression(&cinfo); |
548 | |
549 | row = (JSAMPROW) malloc (cinfo.image_width * cinfo.input_components |
550 | * sizeof (JSAMPLE)); |
551 | if (row == NULL) { |
552 | status = CAIRO_STATUS_NO_MEMORY; |
553 | goto BAIL; |
554 | } |
555 | |
556 | rowptr[0] = row; |
557 | |
558 | /* Step 4: jpeg_start_compress(...); */ |
559 | jpeg_start_compress (&cinfo, TRUE); |
560 | |
561 | /* Step 5: while (scan lines remain to be written) */ |
562 | /* jpeg_write_scanlines(...); */ |
563 | uint8_t *data = cairo_image_surface_get_data (surface); |
564 | int stride = cairo_image_surface_get_stride (surface); |
565 | |
566 | if (cinfo.input_components == 3) { /* truecolor JPEG. */ |
567 | for (i = 0; i < cinfo.image_height; i++) { |
568 | src_pixel = (uint32_t *) (data + i * stride); |
569 | dst_pixel = row; |
570 | /* |
571 | * If the pixels have an alpha channel, convert |
572 | * the pixels to normal RGB |
573 | */ |
574 | if (convert_alpha) { |
575 | for (j = 0; j < cinfo.image_width; j++, dst_pixel += 3) { |
576 | uint8_t r, g, b; |
577 | cairo_to_rgb(*src_pixel++, &r, &g, &b); |
578 | dst_pixel[0] = r; |
579 | dst_pixel[1] = g; |
580 | dst_pixel[2] = b; |
581 | } |
582 | } else { |
583 | for (j = 0; j < cinfo.image_width; j++, dst_pixel += 3) { |
584 | unsigned int pix; |
585 | pix = *src_pixel++; |
586 | dst_pixel[0] = _get_red(pix); |
587 | dst_pixel[1] = _get_green(pix); |
588 | dst_pixel[2] = _get_blue(pix); |
589 | } |
590 | } |
591 | jpeg_write_scanlines (&cinfo, rowptr, 1); |
592 | } |
593 | } else { /* write to a grayscale JPEG. */ |
594 | src_pixel_gray = (uint8_t *) data; |
595 | for (i = 0; i < cinfo.image_height; i++) { |
596 | memcpy (row, src_pixel_gray, cinfo.image_width); |
597 | src_pixel_gray += stride; |
598 | jpeg_write_scanlines (&cinfo, rowptr, 1); |
599 | } |
600 | } |
601 | |
602 | /* Step 6: jpeg_finish_compress(...); */ |
603 | jpeg_finish_compress (&cinfo); |
604 | |
605 | BAIL: |
606 | if (row) |
607 | free (row); |
608 | |
609 | /* Step 7: Release the JPEG compression object. */ |
610 | jpeg_destroy_compress (&cinfo); |
611 | |
612 | return status; |
613 | } |
614 | |
615 | void |
616 | cairo_get_default_jpeg_parameter (cairo_jpeg_parameter_t *param) |
617 | { |
618 | param->quality = 75; |
619 | param->interlace = TRUE; |
620 | } |
621 | |
622 | cairo_status_t |
623 | cairo_surface_write_to_jpeg (cairo_surface_t *surface, |
624 | const char *filename, |
625 | const cairo_jpeg_parameter_t *parameter) |
626 | { |
627 | FILE *fp; |
628 | struct write_closure jpeg_closure; |
629 | cairo_status_t status; |
630 | |
631 | fp = fopen (filename, "wb"); |
632 | if (fp == NULL) |
633 | return CAIRO_STATUS_WRITE_ERROR; |
634 | |
635 | jpeg_closure.jpeg_func = stdio_write_func; |
636 | jpeg_closure.user_data = fp; |
637 | |
638 | status = write_jpeg (surface, &jpeg_closure, parameter); |
639 | if (fclose(fp) < 0) |
640 | status = CAIRO_STATUS_WRITE_ERROR; |
641 | |
642 | return status; |
643 | } |
644 | |
645 | cairo_status_t |
646 | cairo_surface_write_to_jpeg_stream (cairo_surface_t *surface, |
647 | cairo_jpeg_write_func_t write_func, |
648 | void *closure, |
649 | const cairo_jpeg_parameter_t *parameter) |
650 | { |
651 | struct write_closure jpeg_closure; |
652 | jpeg_closure.jpeg_func = write_func; |
653 | jpeg_closure.user_data = closure; |
654 | |
655 | return write_jpeg (surface, &jpeg_closure, parameter); |
656 | } |