source: trunk/third/librsvg/rsvg-file-util.c @ 18805

Revision 18805, 14.8 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18804, which included commits to RCS files with non-trunk default branches.
Line 
1/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3   rsvg-file-util.c: SAX-based renderer for SVG files into a GdkPixbuf.
4
5   Copyright (C) 2000 Eazel, Inc.
6   Copyright (C) 2002 Dom Lachowicz <cinamod@hotmail.com>
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU Library General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   Library General Public License for more details.
17
18   You should have received a copy of the GNU Library General Public
19   License along with this program; if not, write to the
20   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21   Boston, MA 02111-1307, USA.
22
23   Author: Raph Levien <raph@artofcode.com>
24*/
25
26#include "config.h"
27#include "rsvg.h"
28
29#if HAVE_SVGZ
30#include "rsvg-gz.h"
31#endif
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <math.h>
36
37#define SVG_BUFFER_SIZE (1024 * 8)
38
39typedef enum {
40        RSVG_SIZE_ZOOM,
41        RSVG_SIZE_WH,
42        RSVG_SIZE_WH_MAX,
43        RSVG_SIZE_ZOOM_MAX
44} RsvgSizeType;
45
46struct RsvgSizeCallbackData
47{
48        RsvgSizeType type;
49        double x_zoom;
50        double y_zoom;
51        gint width;
52        gint height;
53};
54
55static void
56rsvg_size_callback (int *width,
57                                        int *height,
58                                        gpointer  data)
59{
60        struct RsvgSizeCallbackData *real_data = (struct RsvgSizeCallbackData *) data;
61        double zoomx, zoomy, zoom;
62       
63        switch (real_data->type) {
64        case RSVG_SIZE_ZOOM:
65                if (*width < 0 || *height < 0)
66                        return;
67               
68                *width = floor (real_data->x_zoom * *width + 0.5);
69                *height = floor (real_data->y_zoom * *height + 0.5);
70                return;
71               
72        case RSVG_SIZE_ZOOM_MAX:
73                if (*width < 0 || *height < 0)
74                        return;
75               
76                *width = floor (real_data->x_zoom * *width + 0.5);
77                *height = floor (real_data->y_zoom * *height + 0.5);
78               
79                if (*width > real_data->width || *height > real_data->height)
80                        {
81                                zoomx = (double) real_data->width / *width;
82                                zoomy = (double) real_data->height / *height;
83                                zoom = MIN (zoomx, zoomy);
84                               
85                                *width = floor (zoom * *width + 0.5);
86                                *height = floor (zoom * *height + 0.5);
87                        }
88                return;
89               
90        case RSVG_SIZE_WH_MAX:
91                if (*width < 0 || *height < 0)
92                        return;
93               
94                zoomx = (double) real_data->width / *width;
95                zoomy = (double) real_data->height / *height;
96                zoom = MIN (zoomx, zoomy);
97               
98                *width = floor (zoom * *width + 0.5);
99                *height = floor (zoom * *height + 0.5);
100                return;
101               
102        case RSVG_SIZE_WH:
103               
104                if (real_data->width != -1)
105                        *width = real_data->width;
106                if (real_data->height != -1)
107                        *height = real_data->height;
108                return;
109        }
110       
111        g_assert_not_reached ();
112}
113
114static GdkPixbuf *
115rsvg_pixbuf_from_file_with_size_data_ex (RsvgHandle * handle,
116                                                                                 const gchar * file_name,
117                                                                                 struct RsvgSizeCallbackData * data,
118                                                                                 GError ** error)
119{
120        guchar chars[SVG_BUFFER_SIZE];
121        GdkPixbuf *retval;
122        gint result;
123        FILE *f = fopen (file_name, "rb");
124
125        if (!f)
126                {
127                        /* FIXME: Set up error. */
128                        return NULL;
129                }
130       
131        rsvg_handle_set_size_callback (handle, rsvg_size_callback, data, NULL);
132
133        while ((result = fread (chars, 1, SVG_BUFFER_SIZE, f)) > 0)
134                rsvg_handle_write (handle, chars, result, error);
135       
136        rsvg_handle_close (handle, error);
137        retval = rsvg_handle_get_pixbuf (handle);
138       
139        fclose (f);     
140        return retval;
141}
142
143static GdkPixbuf *
144rsvg_pixbuf_from_file_with_size_data (const gchar * file_name,
145                                                                          struct RsvgSizeCallbackData * data,
146                                                                          GError ** error)
147{
148#if HAVE_SVGZ
149        RsvgHandle * handle;
150        guchar chars[SVG_BUFFER_SIZE];
151        GdkPixbuf *retval;
152        gint result;
153        FILE *f = fopen (file_name, "rb");
154
155        if (!f)
156                {
157                        /* FIXME: Set up error. */
158                        return NULL;
159                }
160       
161        result = fread (chars, 1, SVG_BUFFER_SIZE, f);
162
163        if (result == 0) {
164                fclose (f);
165                return NULL;
166        }
167
168        /* test for GZ marker */
169        if ((result >= 2) && (chars[0] == (guchar)0x1f) && (chars[1] == (guchar)0x8b))
170                handle = rsvg_handle_new_gz ();
171        else
172                handle = rsvg_handle_new ();
173
174        rsvg_handle_set_size_callback (handle, rsvg_size_callback, data, NULL);
175        rsvg_handle_write (handle, chars, result, error);
176
177        while ((result = fread (chars, 1, SVG_BUFFER_SIZE, f)) > 0)
178                rsvg_handle_write (handle, chars, result, error);
179       
180        rsvg_handle_close (handle, error);
181        retval = rsvg_handle_get_pixbuf (handle);
182       
183        fclose (f);     
184        rsvg_handle_free (handle);
185        return retval;
186#else
187        RsvgHandle * handle = rsvg_handle_new ();
188        GdkPixbuf * retval = rsvg_pixbuf_from_file_with_size_data_ex (handle, file_name, data, error);
189        rsvg_handle_free (handle);
190        return retval;
191#endif
192}
193
194
195/**
196 * rsvg_pixbuf_from_file_at_size_ex:
197 * @handle: The RSVG handle you wish to render with (either normal or gzipped)
198 * @file_name: A file name
199 * @width: The new width, or -1
200 * @height: The new height, or -1
201 * @error: return location for errors
202 *
203 * Loads a new #GdkPixbuf from @file_name and returns it.  This pixbuf is scaled
204 * from the size indicated to the new size indicated by @width and @height.  If
205 * either of these are -1, then the default size of the image being loaded is
206 * used.  The caller must assume the reference to the returned pixbuf. If an
207 * error occurred, @error is set and %NULL is returned. Returned handle is closed
208 * by this call and must be freed by the caller.
209 *
210 * Return value: A newly allocated #GdkPixbuf, or %NULL
211 **/
212GdkPixbuf  *
213rsvg_pixbuf_from_file_at_size_ex (RsvgHandle * handle,
214                                                                  const gchar  *file_name,
215                                                                  gint          width,
216                                                                  gint          height,
217                                                                  GError      **error)
218{
219        struct RsvgSizeCallbackData data;
220       
221        data.type = RSVG_SIZE_WH;
222        data.width = width;
223        data.height = height;
224       
225        return rsvg_pixbuf_from_file_with_size_data_ex (handle, file_name, &data, error);
226}
227
228/**
229 * rsvg_pixbuf_from_file_ex:
230 * @handle: The RSVG handle you wish to render with (either normal or gzipped)
231 * @file_name: A file name
232 * @error: return location for errors
233 *
234 * Loads a new #GdkPixbuf from @file_name and returns it.  The caller must
235 * assume the reference to the reurned pixbuf. If an error occurred, @error is
236 * set and %NULL is returned. Returned handle is closed by this call and must be
237 * freed by the caller.
238 *
239 * Return value: A newly allocated #GdkPixbuf, or %NULL
240 **/
241GdkPixbuf  *
242rsvg_pixbuf_from_file_ex (RsvgHandle * handle,
243                                                  const gchar  *file_name,
244                                                  GError      **error)
245{
246        return rsvg_pixbuf_from_file_at_size_ex (handle, file_name, -1, -1, error);
247}
248
249/**
250 * rsvg_pixbuf_from_file_at_zoom_ex:
251 * @handle: The RSVG handle you wish to render with (either normal or gzipped)
252 * @file_name: A file name
253 * @x_zoom: The horizontal zoom factor
254 * @y_zoom: The vertical zoom factor
255 * @error: return location for errors
256 *
257 * Loads a new #GdkPixbuf from @file_name and returns it.  This pixbuf is scaled
258 * from the size indicated by the file by a factor of @x_zoom and @y_zoom.  The
259 * caller must assume the reference to the returned pixbuf. If an error
260 * occurred, @error is set and %NULL is returned. Returned handle is closed by this
261 * call and must be freed by the caller.
262 *
263 * Return value: A newly allocated #GdkPixbuf, or %NULL
264 **/
265GdkPixbuf  *
266rsvg_pixbuf_from_file_at_zoom_ex (RsvgHandle * handle,
267                                                                  const gchar  *file_name,
268                                                                  double        x_zoom,
269                                                                  double        y_zoom,
270                                                                  GError      **error)
271{
272        struct RsvgSizeCallbackData data;
273       
274        g_return_val_if_fail (file_name != NULL, NULL);
275        g_return_val_if_fail (x_zoom > 0.0 && y_zoom > 0.0, NULL);
276       
277        data.type = RSVG_SIZE_ZOOM;
278        data.x_zoom = x_zoom;
279        data.y_zoom = y_zoom;
280       
281        return rsvg_pixbuf_from_file_with_size_data_ex (handle, file_name, &data, error);
282}
283
284/**
285 * rsvg_pixbuf_from_file_at_max_size_ex:
286 * @handle: The RSVG handle you wish to render with (either normal or gzipped)
287 * @file_name: A file name
288 * @max_width: The requested max width
289 * @max_height: The requested max heigh
290 * @error: return location for errors
291 *
292 * Loads a new #GdkPixbuf from @file_name and returns it.  This pixbuf is uniformly
293 * scaled so that the it fits into a rectangle of size max_width * max_height. The
294 * caller must assume the reference to the returned pixbuf. If an error occurred,
295 * @error is set and %NULL is returned. Returned handle is closed by this call and
296 * must be freed by the caller.
297 *
298 * Return value: A newly allocated #GdkPixbuf, or %NULL
299 **/
300GdkPixbuf  *
301rsvg_pixbuf_from_file_at_max_size_ex (RsvgHandle * handle,
302                                                                          const gchar  *file_name,
303                                                                          gint          max_width,
304                                                                          gint          max_height,
305                                                                          GError      **error)
306{
307        struct RsvgSizeCallbackData data;
308       
309        data.type = RSVG_SIZE_WH_MAX;
310        data.width = max_width;
311        data.height = max_height;
312       
313        return rsvg_pixbuf_from_file_with_size_data_ex (handle, file_name, &data, error);
314}
315
316/**
317 * rsvg_pixbuf_from_file_at_zoom_with_max_ex:
318 * @handle: The RSVG handle you wish to render with (either normal or gzipped)
319 * @file_name: A file name
320 * @x_zoom: The horizontal zoom factor
321 * @y_zoom: The vertical zoom factor
322 * @max_width: The requested max width
323 * @max_height: The requested max heigh
324 * @error: return location for errors
325 *
326 * Loads a new #GdkPixbuf from @file_name and returns it.  This pixbuf is scaled
327 * from the size indicated by the file by a factor of @x_zoom and @y_zoom. If the
328 * resulting pixbuf would be larger than max_width/max_heigh it is uniformly scaled
329 * down to fit in that rectangle. The caller must assume the reference to the
330 * returned pixbuf. If an error occurred, @error is set and %NULL is returned.
331 * Returned handle is closed by this call and must be freed by the caller.
332 *
333 * Return value: A newly allocated #GdkPixbuf, or %NULL
334 **/
335GdkPixbuf  *
336rsvg_pixbuf_from_file_at_zoom_with_max_ex (RsvgHandle * handle,
337                                                                                   const gchar  *file_name,
338                                                                                   double        x_zoom,
339                                                                                   double        y_zoom,
340                                                                                   gint          max_width,
341                                                                                   gint          max_height,
342                                                                                   GError      **error)
343{
344        struct RsvgSizeCallbackData data;
345       
346        g_return_val_if_fail (file_name != NULL, NULL);
347        g_return_val_if_fail (x_zoom > 0.0 && y_zoom > 0.0, NULL);
348       
349        data.type = RSVG_SIZE_ZOOM_MAX;
350        data.x_zoom = x_zoom;
351        data.y_zoom = y_zoom;
352        data.width = max_width;
353        data.height = max_height;
354       
355        return rsvg_pixbuf_from_file_with_size_data_ex (handle, file_name, &data, error);
356}
357
358/**
359 * rsvg_pixbuf_from_file:
360 * @file_name: A file name
361 * @error: return location for errors
362 *
363 * Loads a new #GdkPixbuf from @file_name and returns it.  The caller must
364 * assume the reference to the reurned pixbuf. If an error occurred, @error is
365 * set and %NULL is returned.
366 *
367 * Return value: A newly allocated #GdkPixbuf, or %NULL
368 **/
369GdkPixbuf *
370rsvg_pixbuf_from_file (const gchar *file_name,
371                                           GError     **error)
372{
373        return rsvg_pixbuf_from_file_at_size (file_name, -1, -1, error);
374}
375
376/**
377 * rsvg_pixbuf_from_file_at_zoom:
378 * @file_name: A file name
379 * @x_zoom: The horizontal zoom factor
380 * @y_zoom: The vertical zoom factor
381 * @error: return location for errors
382 *
383 * Loads a new #GdkPixbuf from @file_name and returns it.  This pixbuf is scaled
384 * from the size indicated by the file by a factor of @x_zoom and @y_zoom.  The
385 * caller must assume the reference to the returned pixbuf. If an error
386 * occurred, @error is set and %NULL is returned.
387 *
388 * Return value: A newly allocated #GdkPixbuf, or %NULL
389 **/
390GdkPixbuf *
391rsvg_pixbuf_from_file_at_zoom (const gchar *file_name,
392                                                           double       x_zoom,
393                                                           double       y_zoom,
394                                                           GError     **error)
395{
396        struct RsvgSizeCallbackData data;
397       
398        g_return_val_if_fail (file_name != NULL, NULL);
399        g_return_val_if_fail (x_zoom > 0.0 && y_zoom > 0.0, NULL);
400       
401        data.type = RSVG_SIZE_ZOOM;
402        data.x_zoom = x_zoom;
403        data.y_zoom = y_zoom;
404       
405        return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
406}
407
408/**
409 * rsvg_pixbuf_from_file_at_zoom_with_max:
410 * @file_name: A file name
411 * @x_zoom: The horizontal zoom factor
412 * @y_zoom: The vertical zoom factor
413 * @max_width: The requested max width
414 * @max_height: The requested max heigh
415 * @error: return location for errors
416 *
417 * Loads a new #GdkPixbuf from @file_name and returns it.  This pixbuf is scaled
418 * from the size indicated by the file by a factor of @x_zoom and @y_zoom. If the
419 * resulting pixbuf would be larger than max_width/max_heigh it is uniformly scaled
420 * down to fit in that rectangle. The caller must assume the reference to the
421 * returned pixbuf. If an error occurred, @error is set and %NULL is returned.
422 *
423 * Return value: A newly allocated #GdkPixbuf, or %NULL
424 **/
425GdkPixbuf  *
426rsvg_pixbuf_from_file_at_zoom_with_max (const gchar  *file_name,
427                                                                                double        x_zoom,
428                                                                                double        y_zoom,
429                                                                                gint          max_width,
430                                                                                gint          max_height,
431                                                                                GError      **error)
432{
433        struct RsvgSizeCallbackData data;
434       
435        g_return_val_if_fail (file_name != NULL, NULL);
436        g_return_val_if_fail (x_zoom > 0.0 && y_zoom > 0.0, NULL);
437       
438        data.type = RSVG_SIZE_ZOOM_MAX;
439        data.x_zoom = x_zoom;
440        data.y_zoom = y_zoom;
441        data.width = max_width;
442        data.height = max_height;
443       
444        return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
445}
446
447/**
448 * rsvg_pixbuf_from_file_at_size:
449 * @file_name: A file name
450 * @width: The new width, or -1
451 * @height: The new height, or -1
452 * @error: return location for errors
453 *
454 * Loads a new #GdkPixbuf from @file_name and returns it.  This pixbuf is scaled
455 * from the size indicated to the new size indicated by @width and @height.  If
456 * either of these are -1, then the default size of the image being loaded is
457 * used.  The caller must assume the reference to the returned pixbuf. If an
458 * error occurred, @error is set and %NULL is returned.
459 *
460 * Return value: A newly allocated #GdkPixbuf, or %NULL
461 **/
462GdkPixbuf *
463rsvg_pixbuf_from_file_at_size (const gchar *file_name,
464                                                           gint         width,
465                                                           gint         height,
466                                                           GError     **error)
467{
468        struct RsvgSizeCallbackData data;
469       
470        data.type = RSVG_SIZE_WH;
471        data.width = width;
472        data.height = height;
473       
474        return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
475}
476
477/**
478 * rsvg_pixbuf_from_file_at_max_size:
479 * @file_name: A file name
480 * @max_width: The requested max width
481 * @max_height: The requested max heigh
482 * @error: return location for errors
483 *
484 * Loads a new #GdkPixbuf from @file_name and returns it.  This pixbuf is uniformly
485 * scaled so that the it fits into a rectangle of size max_width * max_height. The
486 * caller must assume the reference to the returned pixbuf. If an error occurred,
487 * @error is set and %NULL is returned.
488 *
489 * Return value: A newly allocated #GdkPixbuf, or %NULL
490 **/
491GdkPixbuf  *
492rsvg_pixbuf_from_file_at_max_size (const gchar     *file_name,
493                                                                   gint             max_width,
494                                                                   gint             max_height,
495                                                                   GError         **error)
496{
497        struct RsvgSizeCallbackData data;
498       
499        data.type = RSVG_SIZE_WH_MAX;
500        data.width = max_width;
501        data.height = max_height;
502       
503        return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
504}
Note: See TracBrowser for help on using the repository browser.