Line data Source code
1 : /* cairo - a vector graphics library with display and print output
2 : *
3 : * Copyright © 2008 Adrian Johnson
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it either under the terms of the GNU Lesser General Public
7 : * License version 2.1 as published by the Free Software Foundation
8 : * (the "LGPL") or, at your option, under the terms of the Mozilla
9 : * Public License Version 1.1 (the "MPL"). If you do not alter this
10 : * notice, a recipient may use your version of this file under either
11 : * the MPL or the LGPL.
12 : *
13 : * You should have received a copy of the LGPL along with this library
14 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 : * You should have received a copy of the MPL along with this library
17 : * in the file COPYING-MPL-1.1
18 : *
19 : * The contents of this file are subject to the Mozilla Public License
20 : * Version 1.1 (the "License"); you may not use this file except in
21 : * compliance with the License. You may obtain a copy of the License at
22 : * http://www.mozilla.org/MPL/
23 : *
24 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 : * the specific language governing rights and limitations.
27 : *
28 : * The Original Code is the cairo graphics library.
29 : *
30 : * The Initial Developer of the Original Code is Adrian Johnson.
31 : *
32 : * Contributor(s):
33 : * Adrian Johnson <ajohnson@redneon.com>
34 : */
35 :
36 : #include "cairoint.h"
37 : #include "cairo-image-info-private.h"
38 :
39 : static uint32_t
40 0 : _get_be32 (const unsigned char *p)
41 : {
42 0 : return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
43 : }
44 :
45 : /* JPEG (image/jpeg)
46 : *
47 : * http://www.w3.org/Graphics/JPEG/itu-t81.pdf
48 : */
49 :
50 : /* Markers with no parameters. All other markers are followed by a two
51 : * byte length of the parameters. */
52 : #define TEM 0x01
53 : #define RST_begin 0xd0
54 : #define RST_end 0xd7
55 : #define SOI 0xd8
56 : #define EOI 0xd9
57 :
58 : /* Start of frame markers. */
59 : #define SOF0 0xc0
60 : #define SOF1 0xc1
61 : #define SOF2 0xc2
62 : #define SOF3 0xc3
63 : #define SOF5 0xc5
64 : #define SOF6 0xc6
65 : #define SOF7 0xc7
66 : #define SOF9 0xc9
67 : #define SOF10 0xca
68 : #define SOF11 0xcb
69 : #define SOF13 0xcd
70 : #define SOF14 0xce
71 : #define SOF15 0xcf
72 :
73 : static const unsigned char *
74 0 : _jpeg_skip_segment (const unsigned char *p)
75 : {
76 : int len;
77 :
78 0 : p++;
79 0 : len = (p[0] << 8) | p[1];
80 :
81 0 : return p + len;
82 : }
83 :
84 : static void
85 0 : _jpeg_extract_info (cairo_image_info_t *info, const unsigned char *p)
86 : {
87 0 : info->width = (p[6] << 8) + p[7];
88 0 : info->height = (p[4] << 8) + p[5];
89 0 : info->num_components = p[8];
90 0 : info->bits_per_component = p[3];
91 0 : }
92 :
93 : cairo_int_status_t
94 0 : _cairo_image_info_get_jpeg_info (cairo_image_info_t *info,
95 : const unsigned char *data,
96 : long length)
97 : {
98 0 : const unsigned char *p = data;
99 :
100 0 : while (p + 1 < data + length) {
101 0 : if (*p != 0xff)
102 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
103 0 : p++;
104 :
105 0 : switch (*p) {
106 : /* skip fill bytes */
107 : case 0xff:
108 0 : p++;
109 0 : break;
110 :
111 : case TEM:
112 : case SOI:
113 : case EOI:
114 0 : p++;
115 0 : break;
116 :
117 : case SOF0:
118 : case SOF1:
119 : case SOF2:
120 : case SOF3:
121 : case SOF5:
122 : case SOF6:
123 : case SOF7:
124 : case SOF9:
125 : case SOF10:
126 : case SOF11:
127 : case SOF13:
128 : case SOF14:
129 : case SOF15:
130 : /* Start of frame found. Extract the image parameters. */
131 0 : if (p + 8 > data + length)
132 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
133 :
134 0 : _jpeg_extract_info (info, p);
135 0 : return CAIRO_STATUS_SUCCESS;
136 :
137 : default:
138 0 : if (*p >= RST_begin && *p <= RST_end) {
139 0 : p++;
140 0 : break;
141 : }
142 :
143 0 : if (p + 2 > data + length)
144 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
145 :
146 0 : p = _jpeg_skip_segment (p);
147 0 : break;
148 : }
149 : }
150 :
151 0 : return CAIRO_STATUS_SUCCESS;
152 : }
153 :
154 : /* JPEG 2000 (image/jp2)
155 : *
156 : * http://www.jpeg.org/public/15444-1annexi.pdf
157 : */
158 :
159 : #define JPX_FILETYPE 0x66747970
160 : #define JPX_JP2_HEADER 0x6A703268
161 : #define JPX_IMAGE_HEADER 0x69686472
162 :
163 : static const unsigned char _jpx_signature[] = {
164 : 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a
165 : };
166 :
167 : static const unsigned char *
168 0 : _jpx_next_box (const unsigned char *p)
169 : {
170 0 : return p + _get_be32 (p);
171 : }
172 :
173 : static const unsigned char *
174 0 : _jpx_get_box_contents (const unsigned char *p)
175 : {
176 0 : return p + 8;
177 : }
178 :
179 : static cairo_bool_t
180 0 : _jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type)
181 : {
182 : uint32_t length;
183 :
184 0 : if (p + 8 < end) {
185 0 : length = _get_be32 (p);
186 0 : if (_get_be32 (p + 4) == type && p + length < end)
187 0 : return TRUE;
188 : }
189 :
190 0 : return FALSE;
191 : }
192 :
193 : static const unsigned char *
194 0 : _jpx_find_box (const unsigned char *p, const unsigned char *end, uint32_t type)
195 : {
196 0 : while (p < end) {
197 0 : if (_jpx_match_box (p, end, type))
198 0 : return p;
199 0 : p = _jpx_next_box (p);
200 : }
201 :
202 0 : return NULL;
203 : }
204 :
205 : static void
206 0 : _jpx_extract_info (const unsigned char *p, cairo_image_info_t *info)
207 : {
208 0 : info->height = _get_be32 (p);
209 0 : info->width = _get_be32 (p + 4);
210 0 : info->num_components = (p[8] << 8) + p[9];
211 0 : info->bits_per_component = p[10];
212 0 : }
213 :
214 : cairo_int_status_t
215 0 : _cairo_image_info_get_jpx_info (cairo_image_info_t *info,
216 : const unsigned char *data,
217 : unsigned long length)
218 : {
219 0 : const unsigned char *p = data;
220 0 : const unsigned char *end = data + length;
221 :
222 : /* First 12 bytes must be the JPEG 2000 signature box. */
223 0 : if (length < ARRAY_LENGTH(_jpx_signature) ||
224 0 : memcmp(p, _jpx_signature, ARRAY_LENGTH(_jpx_signature)) != 0)
225 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
226 :
227 0 : p += ARRAY_LENGTH(_jpx_signature);
228 :
229 : /* Next box must be a File Type Box */
230 0 : if (! _jpx_match_box (p, end, JPX_FILETYPE))
231 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
232 :
233 0 : p = _jpx_next_box (p);
234 :
235 : /* Locate the JP2 header box. */
236 0 : p = _jpx_find_box (p, end, JPX_JP2_HEADER);
237 0 : if (!p)
238 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
239 :
240 : /* Step into the JP2 header box. First box must be the Image
241 : * Header */
242 0 : p = _jpx_get_box_contents (p);
243 0 : if (! _jpx_match_box (p, end, JPX_IMAGE_HEADER))
244 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
245 :
246 : /* Get the image info */
247 0 : p = _jpx_get_box_contents (p);
248 0 : _jpx_extract_info (p, info);
249 :
250 0 : return CAIRO_STATUS_SUCCESS;
251 : }
252 :
253 : /* PNG (image/png)
254 : *
255 : * http://www.w3.org/TR/2003/REC-PNG-20031110/
256 : */
257 :
258 : #define PNG_IHDR 0x49484452
259 :
260 : static const unsigned char _png_magic[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
261 :
262 : cairo_int_status_t
263 0 : _cairo_image_info_get_png_info (cairo_image_info_t *info,
264 : const unsigned char *data,
265 : unsigned long length)
266 : {
267 0 : const unsigned char *p = data;
268 0 : const unsigned char *end = data + length;
269 :
270 0 : if (length < 8 || memcmp (data, _png_magic, 8) != 0)
271 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
272 :
273 0 : p += 8;
274 :
275 : /* The first chunk must be IDHR. IDHR has 13 bytes of data plus
276 : * the 12 bytes of overhead for the chunk. */
277 0 : if (p + 13 + 12 > end)
278 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
279 :
280 0 : p += 4;
281 0 : if (_get_be32 (p) != PNG_IHDR)
282 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
283 :
284 0 : p += 4;
285 0 : info->width = _get_be32 (p);
286 0 : p += 4;
287 0 : info->height = _get_be32 (p);
288 :
289 0 : return CAIRO_STATUS_SUCCESS;
290 : }
|