]> granicus.if.org Git - imagemagick/blobdiff - coders/svg.c
Added support for writing RLE compressed TGA files.
[imagemagick] / coders / svg.c
index 89d01813273d56584c44590ed94ed81f411c73c5..e94646142b429ed9e6b36062aa4fbe82416e97cf 100644 (file)
 %                  Read/Write Scalable Vector Graphics Format                 %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                             William Radcliffe                               %
 %                                March 2000                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -49,6 +49,8 @@
 #include "MagickCore/cache.h"
 #include "MagickCore/constitute.h"
 #include "MagickCore/composite-private.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/delegate-private.h"
 #include "MagickCore/draw.h"
 #include "MagickCore/exception.h"
 #include "MagickCore/exception-private.h"
@@ -73,7 +75,7 @@
 #include "MagickCore/utility.h"
 #if defined(MAGICKCORE_XML_DELEGATE)
 #  if defined(MAGICKCORE_WINDOWS_SUPPORT)
-#    if defined(__MINGW32__)
+#    if defined(__MINGW32__) || defined(__MINGW64__)
 #      define _MSC_VER
 #    else
 #      include <win32config.h>
 
 #if defined(MAGICKCORE_RSVG_DELEGATE)
 #include "librsvg/rsvg.h"
-#if defined(MAGICKCORE_CAIRO_DELEGATE)
+#if !defined(LIBRSVG_CHECK_VERSION)
+#include "librsvg/rsvg-cairo.h"
+#include "librsvg/librsvg-features.h"
+#elif !LIBRSVG_CHECK_VERSION(2,36,2)
 #include "librsvg/rsvg-cairo.h"
-#endif
 #include "librsvg/librsvg-features.h"
 #endif
+#endif
 \f
 /*
   Typedef declarations.
@@ -273,7 +278,7 @@ static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
   if (svg_info->text != (char *) NULL)
     svg_info->text=DestroyString(svg_info->text);
   if (svg_info->scale != (double *) NULL)
-    svg_info->scale=(double *) (svg_info->scale);
+    svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
   if (svg_info->title != (char *) NULL)
     svg_info->title=DestroyString(svg_info->title);
   if (svg_info->comment != (char *) NULL)
@@ -307,13 +312,13 @@ static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
       if (type > 0)
         {
           if (svg_info->view_box.width == 0.0)
-            return(1000.0);
+            return(0.0);
           return(svg_info->view_box.width*value/100.0);
         }
       if (type < 0)
         {
           if (svg_info->view_box.height == 0.0)
-            return(1000.0);
+            return(0.0);
           return(svg_info->view_box.height*value/100.0);
         }
       alpha=value-svg_info->view_box.width;
@@ -334,7 +339,7 @@ static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
   if (LocaleNCompare(token,"pc",2) == 0)
     return(DefaultResolution*svg_info->scale[0]/6.0*value);
   if (LocaleNCompare(token,"pt",2) == 0)
-    return(svg_info->scale[0]*value);
+    return(1.25*svg_info->scale[0]*value);
   if (LocaleNCompare(token,"px",2) == 0)
     return(value);
   return(value);
@@ -1092,6 +1097,10 @@ static void SVGStartElement(void *context,const xmlChar *name,
       if (LocaleCompare((const char *) name,"text") == 0)
         {
           (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+          svg_info->bounds.x=0.0;
+          svg_info->bounds.y=0.0;
+          svg_info->bounds.width=0.0;
+          svg_info->bounds.height=0.0;
           break;
         }
       if (LocaleCompare((const char *) name,"tspan") == 0)
@@ -1232,9 +1241,9 @@ static void SVGStartElement(void *context,const xmlChar *name,
               (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
               break;
             }
-          if (LocaleCompare(keyword,"fill-opacity") == 0)
+          if (LocaleCompare(keyword,"fill-alpha") == 0)
             {
-              (void) FormatLocaleFile(svg_info->file,"fill-opacity '%s'\n",
+              (void) FormatLocaleFile(svg_info->file,"fill-alpha '%s'\n",
                 value);
               break;
             }
@@ -1406,10 +1415,10 @@ static void SVGStartElement(void *context,const xmlChar *name,
                 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
                 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
                 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
-                transform.tx=affine.sx*current.tx+affine.ry*current.ty+
-                  affine.tx;
-                transform.ty=affine.rx*current.tx+affine.sy*current.ty+
-                  affine.ty;
+                transform.tx=affine.tx*current.sx+affine.ty*current.ry+
+                  current.tx;
+                transform.ty=affine.tx*current.rx+affine.ty*current.sy+
+                  current.ty;
               }
               (void) FormatLocaleFile(svg_info->file,
                 "affine %g %g %g %g %g %g\n",transform.sx,
@@ -1656,12 +1665,12 @@ static void SVGStartElement(void *context,const xmlChar *name,
                           "fill '%s'\n",color);
                              break;
                            }
-                        if (LocaleCompare(value,"#00000000") == 0)
+                        if (LocaleCompare(value,"#000000ff") == 0)
                           (void) FormatLocaleFile(svg_info->file,
-                          "fill '#000000'\n");
+                            "fill '#000000'\n");
                         else
                           (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
-                          value);
+                            value);
                         break;
                       }
                     if (LocaleCompare(keyword,"fillcolor") == 0)
@@ -1676,10 +1685,10 @@ static void SVGStartElement(void *context,const xmlChar *name,
                           "fill-rule '%s'\n",value);
                         break;
                       }
-                    if (LocaleCompare(keyword,"fill-opacity") == 0)
+                    if (LocaleCompare(keyword,"fill-alpha") == 0)
                       {
                         (void) FormatLocaleFile(svg_info->file,
-                          "fill-opacity '%s'\n",value);
+                          "fill-alpha '%s'\n",value);
                         break;
                       }
                     if (LocaleCompare(keyword,"font-family") == 0)
@@ -1749,12 +1758,12 @@ static void SVGStartElement(void *context,const xmlChar *name,
                           "stroke '%s'\n",color);
                              break;
                            }
-                        if (LocaleCompare(value,"#00000000") == 0)
+                        if (LocaleCompare(value,"#000000ff") == 0)
                           (void) FormatLocaleFile(svg_info->file,
-                          "fill '#000000'\n");
+                            "fill '#000000'\n");
                         else
                           (void) FormatLocaleFile(svg_info->file,
-                          "stroke '%s'\n",value);
+                            "stroke '%s'\n",value);
                         break;
                       }
                     if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
@@ -2039,10 +2048,10 @@ static void SVGStartElement(void *context,const xmlChar *name,
                 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
                 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
                 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
-                transform.tx=affine.sx*current.tx+affine.ry*current.ty+
-                  affine.tx;
-                transform.ty=affine.rx*current.tx+affine.sy*current.ty+
-                  affine.ty;
+                transform.tx=affine.tx*current.sx+affine.ty*current.ry+
+                  current.tx;
+                transform.ty=affine.tx*current.rx+affine.ty*current.sy+
+                  current.ty;
               }
               (void) FormatLocaleFile(svg_info->file,
                 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
@@ -2162,7 +2171,9 @@ static void SVGStartElement(void *context,const xmlChar *name,
         {
           double
             sx,
-            sy;
+            sy,
+            tx,
+            ty;
 
           if ((svg_info->view_box.width == 0.0) ||
               (svg_info->view_box.height == 0.0))
@@ -2173,8 +2184,12 @@ static void SVGStartElement(void *context,const xmlChar *name,
             (double) svg_info->width,(double) svg_info->height);
           sx=(double) svg_info->width/svg_info->view_box.width;
           sy=(double) svg_info->height/svg_info->view_box.height;
-          (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g 0.0 0.0\n",
-            sx,sy);
+          tx=svg_info->view_box.x != 0.0 ? (double) -sx*svg_info->view_box.x :
+            0.0;
+          ty=svg_info->view_box.y != 0.0 ? (double) -sy*svg_info->view_box.y :
+            0.0;
+          (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g %g %g\n",
+            sx,sy,tx,ty);
         }
     }
   (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  )");
@@ -2462,6 +2477,9 @@ static void SVGEndElement(void *context,const xmlChar *name)
 
 static void SVGCharacters(void *context,const xmlChar *c,int length)
 {
+  char
+    *text;
+
   register char
     *p;
 
@@ -2477,22 +2495,21 @@ static void SVGCharacters(void *context,const xmlChar *c,int length)
   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
     "  SAX.characters(%s,%.20g)",c,(double) length);
   svg_info=(SVGInfo *) context;
-  if (svg_info->text != (char *) NULL)
-    svg_info->text=(char *) ResizeQuantumMemory(svg_info->text,
-      strlen(svg_info->text)+length+MaxTextExtent,sizeof(*svg_info->text));
-  else
-    {
-      svg_info->text=(char *) AcquireQuantumMemory(length+MaxTextExtent,
-        sizeof(*svg_info->text));
-      if (svg_info->text != (char *) NULL)
-        *svg_info->text='\0';
-    }
-  if (svg_info->text == (char *) NULL)
+  text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
+  if (text == (char *) NULL)
     return;
-  p=svg_info->text+strlen(svg_info->text);
+  p=text;
   for (i=0; i < (ssize_t) length; i++)
     *p++=c[i];
   *p='\0';
+  StripString(text);
+  if (svg_info->text == (char *) NULL)
+    svg_info->text=text;
+  else
+    {
+      (void) ConcatenateString(&svg_info->text,text);
+      text=DestroyString(text);
+    }
 }
 
 static void SVGReference(void *context,const xmlChar *name)
@@ -2722,22 +2739,17 @@ static void SVGExternalSubset(void *context,const xmlChar *name,
   parser->inputTab=parser_context.inputTab;
 }
 
-#if defined(MAGICKCORE_RSVG_DELEGATE)
-static void SVGSetImageSize(int *width,int *height,gpointer context)
-{
-  Image
-    *image;
-
-  image=(Image *) context;
-  *width=(int) (*width*image->resolution.x/72.0);
-  *height=(int) (*height*image->resolution.y/72.0);
-}
-#endif
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
 
+/*
+  Static declarations.
+*/
+static char
+  SVGDensityGeometry[] = "90.0x90.0";
+\f
+
 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
 {
   char
@@ -2785,185 +2797,264 @@ static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
       image=DestroyImageList(image);
       return((Image *) NULL);
     }
+  if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
+    {
+      GeometryInfo
+        geometry_info;
+
+      int
+        flags;
+
+      flags=ParseGeometry(SVGDensityGeometry,&geometry_info);
+      image->resolution.x=geometry_info.rho;
+      image->resolution.y=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        image->resolution.y=image->resolution.x;
+    }
   if (LocaleCompare(image_info->magick,"MSVG") != 0)
     {
+      const DelegateInfo
+        *delegate_info;
+
+      delegate_info=GetDelegateInfo("svg:decode",(char *) NULL,exception);
+      if (delegate_info != (const DelegateInfo *) NULL)
+        {
+          char
+            background[MaxTextExtent],
+            command[MaxTextExtent],
+            density[MaxTextExtent],
+            filename[MaxTextExtent],
+            opacity[MaxTextExtent],
+            unique[MaxTextExtent];
+
+          int
+            status;
+
+          /*
+            Our best hope for compliance to the SVG standard.
+          */
+          (void) AcquireUniqueFilename(filename);
+          (void) AcquireUniqueFilename(unique);
+          (void) FormatLocaleString(density,MaxTextExtent,"%.20g,%.20g",
+            image->resolution.x,image->resolution.y);
+          (void) FormatLocaleString(background,MaxTextExtent,
+            "rgb(%.20g%%,%.20g%%,%.20g%%)",
+            100.0*QuantumScale*image->background_color.red,
+            100.0*QuantumScale*image->background_color.green,
+            100.0*QuantumScale*image->background_color.blue);
+          (void) FormatLocaleString(opacity,MaxTextExtent,"%.20g",
+            QuantumScale*image->background_color.alpha);
+          (void) FormatLocaleString(command,MaxTextExtent,
+            GetDelegateCommands(delegate_info),image->filename,filename,density,
+            background,opacity,unique);
+          status=SystemCommand(MagickFalse,image_info->verbose,command,
+            exception);
+          (void) RelinquishUniqueFileResource(unique);
+          if (status == 0)
+            {
+              ImageInfo
+                *read_info;
+
+              read_info=CloneImageInfo(image_info);
+              (void) CopyMagickString(read_info->filename,filename,
+                MaxTextExtent);
+              image=ReadImage(read_info,exception);
+              read_info=DestroyImageInfo(read_info);
+              (void) RelinquishUniqueFileResource(filename);
+              if (image != (Image *) NULL)
+                return(image);
+            }
+          (void) RelinquishUniqueFileResource(filename);
+        }
+      {
 #if defined(MAGICKCORE_RSVG_DELEGATE)
 #if defined(MAGICKCORE_CAIRO_DELEGATE)
-      cairo_surface_t
-        *cairo_surface;
+        cairo_surface_t
+          *cairo_surface;
+
+        cairo_t
+          *cairo_image;
 
-      cairo_t
-        *cairo_info;
+        MemoryInfo
+          *pixel_info;
 
-      register unsigned char
-        *p;
+        register unsigned char
+          *p;
 
-      RsvgDimensionData
-        dimension_info;
+        RsvgDimensionData
+          dimension_info;
 
-      unsigned char
-        *pixels;
+        unsigned char
+          *pixels;
 
 #else
-      GdkPixbuf
-        *pixel_info;
+        GdkPixbuf
+          *pixel_buffer;
 
-      register const guchar
-        *p;
+        register const guchar
+          *p;
 
 #endif
 
-      GError
-        *error;
+        GError
+          *error;
 
-      ssize_t
-        y;
+        ssize_t
+          y;
 
-      PixelInfo
-        fill_color;
+        PixelInfo
+          fill_color;
 
-      register ssize_t
-        x;
+        register ssize_t
+          x;
 
-      register Quantum
-        *q;
+        register Quantum
+          *q;
 
-      RsvgHandle
-        *svg_handle;
+        RsvgHandle
+          *svg_handle;
 
-      svg_handle=rsvg_handle_new();
-      if (svg_handle == (RsvgHandle *) NULL)
-        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
-      rsvg_handle_set_base_uri(svg_handle,image_info->filename);
-      rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
-      if ((image->resolution.x != 72.0) && (image->resolution.y != 72.0))
-        rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
-          image->resolution.y);
-      while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
-      {
+        svg_handle=rsvg_handle_new();
+        if (svg_handle == (RsvgHandle *) NULL)
+          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+        rsvg_handle_set_base_uri(svg_handle,image_info->filename);
+        if ((image->resolution.x != 90.0) && (image->resolution.y != 90.0))
+          rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
+            image->resolution.y);
+        while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
+        {
+          error=(GError *) NULL;
+          (void) rsvg_handle_write(svg_handle,message,n,&error);
+          if (error != (GError *) NULL)
+            g_error_free(error);
+        }
         error=(GError *) NULL;
-        (void) rsvg_handle_write(svg_handle,message,n,&error);
+        rsvg_handle_close(svg_handle,&error);
         if (error != (GError *) NULL)
           g_error_free(error);
-      }
-      error=(GError *) NULL;
-      rsvg_handle_close(svg_handle,&error);
-      if (error != (GError *) NULL)
-        g_error_free(error);
 #if defined(MAGICKCORE_CAIRO_DELEGATE)
-      rsvg_handle_get_dimensions(svg_handle,&dimension_info);
-      image->columns=dimension_info.width;
-      image->rows=dimension_info.height;
-      pixels=(unsigned char *) NULL;
+        rsvg_handle_get_dimensions(svg_handle,&dimension_info);
+        image->columns=image->resolution.x*dimension_info.width/90.0;
+        image->rows=image->resolution.y*dimension_info.height/90.0;
+        pixel_info=(MemoryInfo *) NULL;
 #else
-      pixel_info=rsvg_handle_get_pixbuf(svg_handle);
-      rsvg_handle_free(svg_handle);
-      image->columns=gdk_pixbuf_get_width(pixel_info);
-      image->rows=gdk_pixbuf_get_height(pixel_info);
+        pixel_buffer=rsvg_handle_get_pixbuf(svg_handle);
+        rsvg_handle_free(svg_handle);
+        image->columns=gdk_pixbuf_get_width(pixel_buffer);
+        image->rows=gdk_pixbuf_get_height(pixel_buffer);
 #endif
-      image->matte=MagickTrue;
-      SetImageProperty(image,"svg:base-uri",
-        rsvg_handle_get_base_uri(svg_handle),exception);
-      SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle),
-        exception);
-      SetImageProperty(image,"svg:description",
-        rsvg_handle_get_desc(svg_handle),exception);
-      if ((image->columns == 0) || (image->rows == 0))
-        {
+        image->alpha_trait=BlendPixelTrait;
+        SetImageProperty(image,"svg:base-uri",
+          rsvg_handle_get_base_uri(svg_handle),exception);
+        if ((image->columns == 0) || (image->rows == 0))
+          {
 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
-          g_object_unref(G_OBJECT(pixel_info));
+            g_object_unref(G_OBJECT(pixel_buffer));
 #endif
-          g_object_unref(svg_handle);
-          ThrowReaderException(MissingDelegateError,
-            "NoDecodeDelegateForThisImageFormat");
-        }
-      if (image_info->ping == MagickFalse)
-        {
+            g_object_unref(svg_handle);
+            ThrowReaderException(MissingDelegateError,
+              "NoDecodeDelegateForThisImageFormat");
+          }
+        if (image_info->ping == MagickFalse)
+          {
+            size_t
+              stride;
+
 #if defined(MAGICKCORE_CAIRO_DELEGATE)
-          pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
-            image->rows*sizeof(*pixels));
-          if (pixels == (unsigned char *) NULL)
-            {
-              g_object_unref(svg_handle);
-              ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
-            }
+            stride=4*image->columns;
+#if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
+            stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
+              image->columns);
+#endif
+            pixel_info=AcquireVirtualMemory(stride,image->rows*sizeof(*pixels));
+            if (pixel_info == (MemoryInfo *) NULL)
+              {
+                g_object_unref(svg_handle);
+                ThrowReaderException(ResourceLimitError,
+                  "MemoryAllocationFailed");
+              }
+            pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
 #endif
-          (void) SetImageBackgroundColor(image,exception);
+            (void) SetImageBackgroundColor(image,exception);
 #if defined(MAGICKCORE_CAIRO_DELEGATE)
-          cairo_surface=cairo_image_surface_create_for_data(pixels,
-            CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
-          if (cairo_surface == (cairo_surface_t *) NULL)
-            {
-              pixels=(unsigned char *) RelinquishMagickMemory(pixels);
-              g_object_unref(svg_handle);
-              ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
-            }
-          cairo_info=cairo_create(cairo_surface);
-          cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
-          cairo_paint(cairo_info);
-          cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
-          rsvg_handle_render_cairo(svg_handle,cairo_info);
-          cairo_destroy(cairo_info);
-          cairo_surface_destroy(cairo_surface);
-          g_object_unref(svg_handle);
-          p=pixels;
+            cairo_surface=cairo_image_surface_create_for_data(pixels,
+              CAIRO_FORMAT_ARGB32,image->columns,image->rows,stride);
+            if (cairo_surface == (cairo_surface_t *) NULL)
+              {
+                pixel_info=RelinquishVirtualMemory(pixel_info);
+                g_object_unref(svg_handle);
+                ThrowReaderException(ResourceLimitError,
+                  "MemoryAllocationFailed");
+              }
+            cairo_image=cairo_create(cairo_surface);
+            cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
+            cairo_paint(cairo_image);
+            cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
+            cairo_scale(cairo_image,image->resolution.x/90.0,
+              image->resolution.y/90.0);
+            rsvg_handle_render_cairo(svg_handle,cairo_image);
+            cairo_destroy(cairo_image);
+            cairo_surface_destroy(cairo_surface);
+            g_object_unref(svg_handle);
+            p=pixels;
 #else
-          p=gdk_pixbuf_get_pixels(pixel_info);
+            p=gdk_pixbuf_get_pixels(pixel_buffer);
 #endif
-          GetPixelInfo(image,&fill_color);
-          for (y=0; y < (ssize_t) image->rows; y++)
-          {
-            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
-            if (q == (Quantum *) NULL)
-              break;
-            for (x=0; x < (ssize_t) image->columns; x++)
+            GetPixelInfo(image,&fill_color);
+            for (y=0; y < (ssize_t) image->rows; y++)
             {
+              q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+              if (q == (Quantum *) NULL)
+                break;
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
 #if defined(MAGICKCORE_CAIRO_DELEGATE)
-              fill_color.blue=ScaleCharToQuantum(*p++);
-              fill_color.green=ScaleCharToQuantum(*p++);
-              fill_color.red=ScaleCharToQuantum(*p++);
+                fill_color.blue=ScaleCharToQuantum(*p++);
+                fill_color.green=ScaleCharToQuantum(*p++);
+                fill_color.red=ScaleCharToQuantum(*p++);
 #else
-              fill_color.red=ScaleCharToQuantum(*p++);
-              fill_color.green=ScaleCharToQuantum(*p++);
-              fill_color.blue=ScaleCharToQuantum(*p++);
+                fill_color.red=ScaleCharToQuantum(*p++);
+                fill_color.green=ScaleCharToQuantum(*p++);
+                fill_color.blue=ScaleCharToQuantum(*p++);
 #endif
-              fill_color.alpha=ScaleCharToQuantum(*p++);
+                fill_color.alpha=ScaleCharToQuantum(*p++);
 #if defined(MAGICKCORE_CAIRO_DELEGATE)
-              {
-                double
-                  gamma;
-    
-                gamma=1.0-QuantumScale*fill_color.alpha;
-                gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-                fill_color.blue*=gamma;
-                fill_color.green*=gamma;
-                fill_color.red*=gamma;
-              }
+                {
+                  double
+                    gamma;
+
+                  gamma=QuantumScale*fill_color.alpha;
+                  gamma=PerceptibleReciprocal(gamma);
+                  fill_color.blue*=gamma;
+                  fill_color.green*=gamma;
+                  fill_color.red*=gamma;
+                }
 #endif
-              CompositePixelOver(image,&fill_color,fill_color.alpha,q,
-                (MagickRealType) GetPixelAlpha(image,q),q);
-              q+=GetPixelChannels(image);
-            }
-            if (SyncAuthenticPixels(image,exception) == MagickFalse)
-              break;
-            if (image->previous == (Image *) NULL)
-              {
-                status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
-                image->rows);
-                if (status == MagickFalse)
-                  break;
+                CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
+                  GetPixelAlpha(image,q),q);
+                q+=GetPixelChannels(image);
               }
+              if (SyncAuthenticPixels(image,exception) == MagickFalse)
+                break;
+              if (image->previous == (Image *) NULL)
+                {
+                  status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
+                    y,image->rows);
+                  if (status == MagickFalse)
+                    break;
+                }
+            }
           }
-        }
 #if defined(MAGICKCORE_CAIRO_DELEGATE)
-      if (pixels != (unsigned char *) NULL)
-        pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+        if (pixel_info != (MemoryInfo *) NULL)
+          pixel_info=RelinquishVirtualMemory(pixel_info);
 #else
-      g_object_unref(G_OBJECT(pixel_info));
+        g_object_unref(G_OBJECT(pixel_buffer));
 #endif
-      (void) CloseBlob(image);
-      return(GetFirstImageInList(image));
+        (void) CloseBlob(image);
+        return(GetFirstImageInList(image));
 #endif
+      }
     }
   /*
     Open draw file.
@@ -2983,9 +3074,14 @@ static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   /*
     Parse SVG file.
   */
+  if (image == (Image *) NULL)
+    return((Image *) NULL);
   svg_info=AcquireSVGInfo();
   if (svg_info == (SVGInfo *) NULL)
-    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+    {
+      (void) fclose(file);
+      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+    }
   svg_info->file=file;
   svg_info->exception=exception;
   svg_info->image=image;
@@ -2996,7 +3092,6 @@ static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
     (void) CloneString(&svg_info->size,image_info->size);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
-  xmlInitParser();
   (void) xmlSubstituteEntitiesDefault(1);
   (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
   sax_modules.internalSubset=SVGInternalSubset;
@@ -3043,7 +3138,6 @@ static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
   xmlFreeParserCtxt(svg_info->parser);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
-  xmlCleanupParser();
   (void) fclose(file);
   (void) CloseBlob(image);
   image->columns=svg_info->width;
@@ -3128,7 +3222,12 @@ ModuleExport size_t RegisterSVGImage(void)
   (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
 #endif
 #if defined(MAGICKCORE_RSVG_DELEGATE)
-  rsvg_init();
+#if !GLIB_CHECK_VERSION(2,35,0)
+  g_type_init();
+#endif
+#if defined(MAGICKCORE_XML_DELEGATE)
+  xmlInitParser();
+#endif
   (void) FormatLocaleString(version,MaxTextExtent,"RSVG %d.%d.%d",
     LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
 #endif
@@ -3140,6 +3239,7 @@ ModuleExport size_t RegisterSVGImage(void)
   entry->blob_support=MagickFalse;
   entry->seekable_stream=MagickFalse;
   entry->description=ConstantString("Scalable Vector Graphics");
+  entry->mime_type=ConstantString("image/svg+xml");
   if (*version != '\0')
     entry->version=ConstantString(version);
   entry->magick=(IsImageFormatHandler *) IsSVG;
@@ -3153,6 +3253,7 @@ ModuleExport size_t RegisterSVGImage(void)
   entry->blob_support=MagickFalse;
   entry->seekable_stream=MagickFalse;
   entry->description=ConstantString("Compressed Scalable Vector Graphics");
+  entry->mime_type=ConstantString("image/svg+xml");
   if (*version != '\0')
     entry->version=ConstantString(version);
   entry->magick=(IsImageFormatHandler *) IsSVG;
@@ -3196,8 +3297,8 @@ ModuleExport void UnregisterSVGImage(void)
   (void) UnregisterMagickInfo("SVGZ");
   (void) UnregisterMagickInfo("SVG");
   (void) UnregisterMagickInfo("MSVG");
-#if defined(MAGICKCORE_RSVG_DELEGATE)
-  rsvg_term();
+#if defined(MAGICKCORE_XML_DELEGATE)
+  xmlCleanupParser();
 #endif
 }
 \f
@@ -3401,7 +3502,7 @@ static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
         break;
       for (x=0; x < (ssize_t) image->columns; x++)
       {
-        SetPixelInfo(image,p,&pixel);
+        GetPixelInfoPixel(image,p,&pixel);
         (void) QueryColorname(image,&pixel,SVGCompliance,tuple,exception);
         (void) FormatLocaleString(message,MaxTextExtent,
           "  <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
@@ -3694,11 +3795,11 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
             (void) WriteBlobString(image,message);
             break;
           }
-        if (LocaleCompare("fill-opacity",keyword) == 0)
+        if (LocaleCompare("fill-alpha",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
             (void) FormatLocaleString(message,MaxTextExtent,
-              "fill-opacity:%s;",token);
+              "fill-alpha:%s;",token);
             (void) WriteBlobString(image,message);
             break;
           }