chiark / gitweb /
gtk/gtk.lisp: Apparently when you ask for a stock Button, you get a Bin.
[clg] / cairo / alien / cairo-jpeg.c
CommitLineData
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
60struct clg_error_mgr {
61 struct jpeg_error_mgr pub;
62 jmp_buf setjmp_buffer;
63};
64
65typedef struct clg_error_mgr *error_ptr;
66
67static 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
77typedef unsigned int (*cairo_jpeg_read_func_t)
78 (void *closure,
79 unsigned char *data,
80 unsigned int length);
81
82struct 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 */
106static
107unsigned 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 */
118static 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 */
127static 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 */
159static 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 */
175static void term_source_custom (j_decompress_ptr cinfo)
176{
177}
178
179/*
180 * read jpeg from any source.
181 */
182static cairo_surface_t *
183read_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
311cairo_surface_t *
312cairo_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
344cairo_surface_t *
345cairo_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
360typedef struct _cairo_jpeg_parameter {
361 int quality;
362 cairo_bool_t interlace;
363} cairo_jpeg_parameter_t;
364
365void cairo_get_default_jpeg_parameter (cairo_jpeg_parameter_t *param);
366
367typedef unsigned int (*cairo_jpeg_write_func_t)
368 (void *closure,
369 const unsigned char *data,
370 unsigned int length);
371
372struct 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 */
391static
392cairo_status_t stdio_write_func (void *closure,
393 const unsigned char *data,
394 unsigned int length)
395{
e3d7a90d 396 int bytes_written;
397 do {
398 bytes_written = fwrite(data, 1, length, (FILE *)closure);
399 data += bytes_written;
400 length -= bytes_written;
401 } while (bytes_written > 0 && length > 0);
402
403 return CAIRO_STATUS_SUCCESS;
e59e8502 404}
405
406/*
407 * Initialize destination.
408 * called by jpeg_start_compress before any data is actually written.
409 */
410static void init_destination_jpeg_custom (j_compress_ptr cinfo)
411{
412 struct write_closure *closure = (struct write_closure*) (cinfo->client_data);
413 cinfo->dest->next_output_byte = closure->block;
414 cinfo->dest->free_in_buffer = BUF_SIZE_JPEG;
415}
416
417/*
418 * Empty buffer.
419 * called whenever buffer fills up.
420 * In typical applications, this should write the entire output buffer
421 * (ignoring the current state of next_output_byte & free_in_buffer),
422 * reset the pointer & count to the start of the buffer, and return TRUE
423 * indicating that the buffer has been dumped.
424 *
425 * In applications that need to be able to suspend compression due to output
426 * overrun, a FALSE return indicates that the buffer cannot be emptied now.
427 * In this situation, the compressor will return to its caller (possibly with
428 * an indication that it has not accepted all the supplied scanlines). The
429 * application should resume compression after it has made more room in the
430 * output buffer. Note that there are substantial restrictions on the use of
431 * suspension --- see the documentation.
432 *
433 * When suspending, the compressor will back up to a convenient restart point
434 * (typically the start of the current MCU). next_output_byte & free_in_buffer
435 * indicate where the restart point will be if the current call returns FALSE.
436 * Data beyond this point will be regenerated after resumption, so do not
437 * write it out when emptying the buffer externally.
438 */
439static boolean empty_output_buffer_jpeg_custom (j_compress_ptr cinfo)
440{
441 struct write_closure *closure = (struct write_closure*) (cinfo->client_data);
442 int len;
443 len = (*closure->jpeg_func) (closure->user_data,
444 closure->block, BUF_SIZE_JPEG);
445 if (len != BUF_SIZE_JPEG) {
446 /* seems not all remaining bytes in buffer has been dumped yet. */
447 /* by return FALSE, we reply on JPEG's error handling machnism? */
448 return FALSE;
449 }
450 cinfo->dest->next_output_byte = closure->block;
451 cinfo->dest->free_in_buffer = BUF_SIZE_JPEG;
452 return TRUE;
453}
454
455/*
456 * Terminate destination.
457 * called by jpeg_finish_compress afer all data has been written.
458 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
459 * application must deal with any cleanup that should happen even
460 * for error exit.
461 */
462static void term_destination_jpeg_custom (j_compress_ptr cinfo)
463{
464 struct write_closure *closure = (struct write_closure*) (cinfo->client_data);
465 unsigned int len;
466 len = BUF_SIZE_JPEG - cinfo->dest->free_in_buffer;
467 if (len > 0)
468 (*closure->jpeg_func) (closure->user_data, closure->block, len);
469}
470
471static cairo_status_t
472write_jpeg (cairo_surface_t *surface, void* closure,
473 const cairo_jpeg_parameter_t *parameter)
474{
475 cairo_status_t status = CAIRO_STATUS_SUCCESS;
476
477 struct jpeg_compress_struct cinfo;
478 struct clg_error_mgr jerr;
479 struct jpeg_destination_mgr dest;
480 cairo_jpeg_parameter_t *param, default_parameters;
481
482 JSAMPROW row = NULL;
483 JSAMPROW rowptr[1];
484
485 register uint32_t *src_pixel;
486 register uint8_t *src_pixel_gray;
487 register JSAMPROW dst_pixel;
488 unsigned int i, j;
489 int convert_alpha;
490
491 param = (cairo_jpeg_parameter_t *)parameter;
492 if (param == NULL) {
493 param = &default_parameters;
494 cairo_get_default_jpeg_parameter(param);
495 }
496
497
498 /* Step 1: Allocate and initialize a JPEG compression object. */
499 memset (&cinfo, 0, sizeof (cinfo));
500 memset (&jerr, 0, sizeof (jerr));
501
502 cinfo.err = jpeg_std_error (&jerr.pub);
503 jerr.pub.error_exit = _error_exit;
504 if (setjmp(jerr.setjmp_buffer))
505 goto BAIL;
506
507 jpeg_create_compress (&cinfo);
508
509 /* Step 2: Specify the destination for the compressed data. */
510 cinfo.client_data = closure;
511
512 dest.init_destination = init_destination_jpeg_custom;
513 dest.empty_output_buffer = empty_output_buffer_jpeg_custom;
514 dest.term_destination = term_destination_jpeg_custom;
515 dest.next_output_byte = NULL;
516 dest.free_in_buffer = 0;
517 cinfo.dest = &dest;
518
519 /* Step 3: Set parameters for compression, image size & colorspace, etc. */
520 cinfo.image_width = cairo_image_surface_get_width (surface);
521 cinfo.image_height = cairo_image_surface_get_height (surface);
522 convert_alpha = 0;
523
524 switch (cairo_image_surface_get_format (surface)) {
525 case CAIRO_FORMAT_RGB24:
526 cinfo.input_components = 3; /* # of color components per pixel */
527 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
528 break;
529 case CAIRO_FORMAT_ARGB32:
530 cinfo.input_components = 3; /* # of color components per pixel */
531 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
532 convert_alpha = 1;
533 break;
534 case CAIRO_FORMAT_A8: /* Put A channel into a grayscale JPEG image. */
535 case CAIRO_FORMAT_A1: /* Put A channel into a "binary" JPEG image. */
536 cinfo.input_components = 1;
537 cinfo.in_color_space = JCS_GRAYSCALE;
538 default:
539 status = CAIRO_STATUS_NULL_POINTER;
540 goto BAIL;
541 }
542
543 jpeg_set_defaults (&cinfo); /* set compression parameters all default values. */
544
545 /* the fastest, but less accurate integer method for DCT. */
546 /* not recommende if high quality is a concern. we do not have this issue. */
547 cinfo.dct_method = JDCT_IFAST;
548
549 if (param->quality >= 0)
550 jpeg_set_quality(&cinfo, param->quality, TRUE);
551
552 /* If user requests interlace, translate that to progressive JPEG */
553 if (param->interlace)
554 jpeg_simple_progression(&cinfo);
555
556 row = (JSAMPROW) malloc (cinfo.image_width * cinfo.input_components
557 * sizeof (JSAMPLE));
558 if (row == NULL) {
559 status = CAIRO_STATUS_NO_MEMORY;
560 goto BAIL;
561 }
562
563 rowptr[0] = row;
564
565 /* Step 4: jpeg_start_compress(...); */
566 jpeg_start_compress (&cinfo, TRUE);
567
568 /* Step 5: while (scan lines remain to be written) */
569 /* jpeg_write_scanlines(...); */
570 uint8_t *data = cairo_image_surface_get_data (surface);
571 int stride = cairo_image_surface_get_stride (surface);
572
573 if (cinfo.input_components == 3) { /* truecolor JPEG. */
574 for (i = 0; i < cinfo.image_height; i++) {
575 src_pixel = (uint32_t *) (data + i * stride);
576 dst_pixel = row;
577 /*
578 * If the pixels have an alpha channel, convert
579 * the pixels to normal RGB
580 */
581 if (convert_alpha) {
582 for (j = 0; j < cinfo.image_width; j++, dst_pixel += 3) {
583 uint8_t r, g, b;
584 cairo_to_rgb(*src_pixel++, &r, &g, &b);
585 dst_pixel[0] = r;
586 dst_pixel[1] = g;
587 dst_pixel[2] = b;
588 }
589 } else {
590 for (j = 0; j < cinfo.image_width; j++, dst_pixel += 3) {
591 unsigned int pix;
592 pix = *src_pixel++;
593 dst_pixel[0] = _get_red(pix);
594 dst_pixel[1] = _get_green(pix);
595 dst_pixel[2] = _get_blue(pix);
596 }
597 }
598 jpeg_write_scanlines (&cinfo, rowptr, 1);
599 }
600 } else { /* write to a grayscale JPEG. */
601 src_pixel_gray = (uint8_t *) data;
602 for (i = 0; i < cinfo.image_height; i++) {
603 memcpy (row, src_pixel_gray, cinfo.image_width);
604 src_pixel_gray += stride;
605 jpeg_write_scanlines (&cinfo, rowptr, 1);
606 }
607 }
608
609 /* Step 6: jpeg_finish_compress(...); */
610 jpeg_finish_compress (&cinfo);
611
612 BAIL:
613 if (row)
614 free (row);
615
616 /* Step 7: Release the JPEG compression object. */
617 jpeg_destroy_compress (&cinfo);
618
619 return status;
620}
621
622void
623cairo_get_default_jpeg_parameter (cairo_jpeg_parameter_t *param)
624{
625 param->quality = 75;
626 param->interlace = TRUE;
627}
628
629cairo_status_t
630cairo_surface_write_to_jpeg (cairo_surface_t *surface,
631 const char *filename,
632 const cairo_jpeg_parameter_t *parameter)
633{
634 FILE *fp;
635 struct write_closure jpeg_closure;
636 cairo_status_t status;
637
638 fp = fopen (filename, "wb");
639 if (fp == NULL)
640 return CAIRO_STATUS_WRITE_ERROR;
641
642 jpeg_closure.jpeg_func = stdio_write_func;
643 jpeg_closure.user_data = fp;
644
645 status = write_jpeg (surface, &jpeg_closure, parameter);
646 if (fclose(fp) < 0)
647 status = CAIRO_STATUS_WRITE_ERROR;
648
649 return status;
650}
651
652cairo_status_t
653cairo_surface_write_to_jpeg_stream (cairo_surface_t *surface,
654 cairo_jpeg_write_func_t write_func,
655 void *closure,
656 const cairo_jpeg_parameter_t *parameter)
657{
658 struct write_closure jpeg_closure;
659 jpeg_closure.jpeg_func = write_func;
660 jpeg_closure.user_data = closure;
661
662 return write_jpeg (surface, &jpeg_closure, parameter);
663}