1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2008 Adrian Johnson
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Adrian Johnson.
34 * Adrian Johnson <ajohnson@redneon.com>
39 #include "cairo-error-private.h"
40 #include "cairo-image-info-private.h"
44 * http://www.w3.org/Graphics/JPEG/itu-t81.pdf
47 /* Markers with no parameters. All other markers are followed by a two
48 * byte length of the parameters. */
50 #define RST_begin 0xd0
55 /* Start of frame markers. */
70 static const unsigned char *
71 _jpeg_skip_segment (const unsigned char *p
)
76 len
= (p
[0] << 8) | p
[1];
82 _jpeg_extract_info (cairo_image_info_t
*info
, const unsigned char *p
)
84 info
->width
= (p
[6] << 8) + p
[7];
85 info
->height
= (p
[4] << 8) + p
[5];
86 info
->num_components
= p
[8];
87 info
->bits_per_component
= p
[3];
91 _cairo_image_info_get_jpeg_info (cairo_image_info_t
*info
,
92 const unsigned char *data
,
95 const unsigned char *p
= data
;
97 while (p
+ 1 < data
+ length
) {
99 return CAIRO_INT_STATUS_UNSUPPORTED
;
103 /* skip fill bytes */
127 /* Start of frame found. Extract the image parameters. */
128 if (p
+ 8 > data
+ length
)
129 return CAIRO_INT_STATUS_UNSUPPORTED
;
131 _jpeg_extract_info (info
, p
);
132 return CAIRO_STATUS_SUCCESS
;
135 if (*p
>= RST_begin
&& *p
<= RST_end
) {
140 if (p
+ 2 > data
+ length
)
141 return CAIRO_INT_STATUS_UNSUPPORTED
;
143 p
= _jpeg_skip_segment (p
);
148 return CAIRO_STATUS_SUCCESS
;
151 /* JPEG 2000 (image/jp2)
153 * http://www.jpeg.org/public/15444-1annexi.pdf
156 #define JPX_FILETYPE 0x66747970
157 #define JPX_JP2_HEADER 0x6A703268
158 #define JPX_IMAGE_HEADER 0x69686472
160 static const unsigned char _jpx_signature
[] = {
161 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a
164 static const unsigned char *
165 _jpx_next_box (const unsigned char *p
)
167 return p
+ get_unaligned_be32 (p
);
170 static const unsigned char *
171 _jpx_get_box_contents (const unsigned char *p
)
177 _jpx_match_box (const unsigned char *p
, const unsigned char *end
, uint32_t type
)
182 length
= get_unaligned_be32 (p
);
183 if (get_unaligned_be32 (p
+ 4) == type
&& p
+ length
< end
)
190 static const unsigned char *
191 _jpx_find_box (const unsigned char *p
, const unsigned char *end
, uint32_t type
)
194 if (_jpx_match_box (p
, end
, type
))
196 p
= _jpx_next_box (p
);
203 _jpx_extract_info (const unsigned char *p
, cairo_image_info_t
*info
)
205 info
->height
= get_unaligned_be32 (p
);
206 info
->width
= get_unaligned_be32 (p
+ 4);
207 info
->num_components
= (p
[8] << 8) + p
[9];
208 info
->bits_per_component
= p
[10];
212 _cairo_image_info_get_jpx_info (cairo_image_info_t
*info
,
213 const unsigned char *data
,
214 unsigned long length
)
216 const unsigned char *p
= data
;
217 const unsigned char *end
= data
+ length
;
219 /* First 12 bytes must be the JPEG 2000 signature box. */
220 if (length
< ARRAY_LENGTH(_jpx_signature
) ||
221 memcmp(p
, _jpx_signature
, ARRAY_LENGTH(_jpx_signature
)) != 0)
222 return CAIRO_INT_STATUS_UNSUPPORTED
;
224 p
+= ARRAY_LENGTH(_jpx_signature
);
226 /* Next box must be a File Type Box */
227 if (! _jpx_match_box (p
, end
, JPX_FILETYPE
))
228 return CAIRO_INT_STATUS_UNSUPPORTED
;
230 p
= _jpx_next_box (p
);
232 /* Locate the JP2 header box. */
233 p
= _jpx_find_box (p
, end
, JPX_JP2_HEADER
);
235 return CAIRO_INT_STATUS_UNSUPPORTED
;
237 /* Step into the JP2 header box. First box must be the Image
239 p
= _jpx_get_box_contents (p
);
240 if (! _jpx_match_box (p
, end
, JPX_IMAGE_HEADER
))
241 return CAIRO_INT_STATUS_UNSUPPORTED
;
243 /* Get the image info */
244 p
= _jpx_get_box_contents (p
);
245 _jpx_extract_info (p
, info
);
247 return CAIRO_STATUS_SUCCESS
;
252 * http://www.w3.org/TR/2003/REC-PNG-20031110/
255 #define PNG_IHDR 0x49484452
257 static const unsigned char _png_magic
[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
260 _cairo_image_info_get_png_info (cairo_image_info_t
*info
,
261 const unsigned char *data
,
262 unsigned long length
)
264 const unsigned char *p
= data
;
265 const unsigned char *end
= data
+ length
;
267 if (length
< 8 || memcmp (data
, _png_magic
, 8) != 0)
268 return CAIRO_INT_STATUS_UNSUPPORTED
;
272 /* The first chunk must be IDHR. IDHR has 13 bytes of data plus
273 * the 12 bytes of overhead for the chunk. */
274 if (p
+ 13 + 12 > end
)
275 return CAIRO_INT_STATUS_UNSUPPORTED
;
278 if (get_unaligned_be32 (p
) != PNG_IHDR
)
279 return CAIRO_INT_STATUS_UNSUPPORTED
;
282 info
->width
= get_unaligned_be32 (p
);
284 info
->height
= get_unaligned_be32 (p
);
286 return CAIRO_STATUS_SUCCESS
;
289 static const unsigned char *
290 _jbig2_find_data_end (const unsigned char *p
,
291 const unsigned char *end
,
294 unsigned char end_seq
[2];
297 /* Segments of type "Immediate generic region" may have an
298 * unspecified data length. The JBIG2 specification specifies the
299 * method to find the end of the data for these segments. */
300 if (type
== 36 || type
== 38 || type
== 39) {
304 /* MMR encoding ends with 0x00, 0x00 */
308 /* Template encoding ends with 0xff, 0xac */
314 if (p
[0] == end_seq
[0] && p
[1] == end_seq
[1]) {
315 /* Skip the 2 terminating bytes and the 4 byte row count that follows. */
328 static const unsigned char *
329 _jbig2_get_next_segment (const unsigned char *p
,
330 const unsigned char *end
,
332 const unsigned char **data
,
333 unsigned long *data_len
)
335 unsigned long seg_num
;
336 cairo_bool_t big_page_size
;
344 seg_num
= get_unaligned_be32 (p
);
346 big_page_size
= (p
[4] & 0x40) != 0;
349 num_segs
= p
[0] >> 5;
351 num_segs
= get_unaligned_be32 (p
) & 0x1fffffff;
352 ref_seg_bytes
= 4 + ((num_segs
+ 1)/8);
360 else if (seg_num
<= 65536)
365 p
+= num_segs
* referred_size
;
366 p
+= big_page_size
? 4 : 1;
370 *data_len
= get_unaligned_be32 (p
);
374 if (*data_len
== 0xffffffff) {
375 /* if data length is -1 we have to scan through the data to find the end */
376 p
= _jbig2_find_data_end (*data
, end
, *type
);
380 *data_len
= p
- *data
;
392 _jbig2_extract_info (cairo_image_info_t
*info
, const unsigned char *p
)
394 info
->width
= get_unaligned_be32 (p
);
395 info
->height
= get_unaligned_be32 (p
+ 4);
396 info
->num_components
= 1;
397 info
->bits_per_component
= 1;
401 _cairo_image_info_get_jbig2_info (cairo_image_info_t
*info
,
402 const unsigned char *data
,
403 unsigned long length
)
405 const unsigned char *p
= data
;
406 const unsigned char *end
= data
+ length
;
408 const unsigned char *seg_data
;
409 unsigned long seg_data_len
;
411 while (p
&& p
< end
) {
412 p
= _jbig2_get_next_segment (p
, end
, &seg_type
, &seg_data
, &seg_data_len
);
413 if (p
&& seg_type
== 48 && seg_data_len
> 8) {
414 /* page information segment */
415 _jbig2_extract_info (info
, seg_data
);
416 return CAIRO_STATUS_SUCCESS
;
420 return CAIRO_INT_STATUS_UNSUPPORTED
;