Skip to content
Permalink
main
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% SSSSS V V GGGG %
% SS V V G %
% SSS V V G GG %
% SS V V G G %
% SSSSS V GGG %
% %
% %
% Read/Write Scalable Vector Graphics Format %
% %
% Software Design %
% Cristy %
% William Radcliffe %
% March 2000 %
% %
% %
% Copyright @ 2000 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 %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
/*
Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/annotate.h"
#include "MagickCore/artifact.h"
#include "MagickCore/attribute.h"
#include "MagickCore/blob.h"
#include "MagickCore/blob-private.h"
#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"
#include "MagickCore/gem.h"
#include "MagickCore/image.h"
#include "MagickCore/image-private.h"
#include "MagickCore/list.h"
#include "MagickCore/log.h"
#include "MagickCore/magick.h"
#include "MagickCore/memory_.h"
#include "MagickCore/memory-private.h"
#include "MagickCore/module.h"
#include "MagickCore/monitor.h"
#include "MagickCore/monitor-private.h"
#include "MagickCore/option.h"
#include "MagickCore/pixel-accessor.h"
#include "MagickCore/policy.h"
#include "MagickCore/property.h"
#include "MagickCore/quantum-private.h"
#include "MagickCore/resource_.h"
#include "MagickCore/static.h"
#include "MagickCore/string_.h"
#include "MagickCore/string-private.h"
#include "MagickCore/token.h"
#include "MagickCore/utility.h"
#include "coders/coders-private.h"
#if defined(MAGICKCORE_XML_DELEGATE)
# if defined(MAGICKCORE_WINDOWS_SUPPORT)
# if !defined(__MINGW32__)
# include <win32config.h>
# endif
# endif
# include <libxml/xmlmemory.h>
# include <libxml/parserInternals.h>
# include <libxml/xmlerror.h>
#endif
#if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
#include "autotrace/autotrace.h"
#endif
#if defined(MAGICKCORE_RSVG_DELEGATE)
#include "librsvg/rsvg.h"
#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"
#include "librsvg/librsvg-features.h"
#endif
#endif
/*
Define declarations.
*/
#define DefaultSVGDensity 96.0
/*
Typedef declarations.
*/
typedef struct _BoundingBox
{
double
x,
y,
width,
height;
} BoundingBox;
typedef struct _ElementInfo
{
double
cx,
cy,
major,
minor,
angle;
} ElementInfo;
typedef struct _SVGInfo
{
FILE
*file;
ExceptionInfo
*exception;
Image
*image;
const ImageInfo
*image_info;
AffineMatrix
affine;
size_t
width,
height;
char
*size,
*title,
*comment;
int
n;
double
*scale,
pointsize;
ElementInfo
element;
SegmentInfo
segment;
BoundingBox
bounds,
text_offset,
view_box;
PointInfo
radius;
char
*stop_color,
*offset,
*text,
*vertices,
*url;
#if defined(MAGICKCORE_XML_DELEGATE)
xmlParserCtxtPtr
parser;
xmlDocPtr
document;
#endif
ssize_t
svgDepth;
} SVGInfo;
/*
Static declarations.
*/
static char
SVGDensityGeometry[] = "96.0x96.0";
/*
Forward declarations.
*/
static MagickBooleanType
WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I s S V G %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% IsSVG()() returns MagickTrue if the image format type, identified by the
% magick string, is SVG.
%
% The format of the IsSVG method is:
%
% MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
%
% A description of each parameter follows:
%
% o magick: compare image format pattern against these bytes.
%
% o length: Specifies the length of the magick string.
%
*/
static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
{
if (length < 4)
return(MagickFalse);
if (LocaleNCompare((const char *) magick+1,"svg",3) == 0)
return(MagickTrue);
if (length < 5)
return(MagickFalse);
if (LocaleNCompare((const char *) magick+1,"?xml",4) == 0)
return(MagickTrue);
return(MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e a d S V G I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ReadSVGImage() reads a Scalable Vector Graphics file and returns it. It
% allocates the memory necessary for the new Image structure and returns a
% pointer to the new image.
%
% The format of the ReadSVGImage method is:
%
% Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the image info.
%
% o exception: return any errors or warnings in this structure.
%
*/
static Image *RenderSVGImage(const ImageInfo *image_info,Image *image,
ExceptionInfo *exception)
{
char
background[MagickPathExtent],
command[MagickPathExtent],
*density,
input_filename[MagickPathExtent],
opacity[MagickPathExtent],
output_filename[MagickPathExtent],
unique[MagickPathExtent];
const DelegateInfo
*delegate_info;
Image
*next;
int
status;
struct stat
attributes;
/*
Our best hope for compliance with the SVG standard.
*/
delegate_info=GetDelegateInfo("svg:decode",(char *) NULL,exception);
if (delegate_info == (const DelegateInfo *) NULL)
return((Image *) NULL);
status=AcquireUniqueSymbolicLink(image->filename,input_filename);
(void) AcquireUniqueFilename(unique);
(void) FormatLocaleString(output_filename,MagickPathExtent,"%s.png",unique);
(void) AcquireUniqueFilename(unique);
density=AcquireString("");
(void) FormatLocaleString(density,MagickPathExtent,"%.20g",
ceil(sqrt(image->resolution.x*image->resolution.y)-0.5));
(void) FormatLocaleString(background,MagickPathExtent,
"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,MagickPathExtent,"%.20g",QuantumScale*
image->background_color.alpha);
(void) FormatLocaleString(command,MagickPathExtent,
GetDelegateCommands(delegate_info),input_filename,output_filename,density,
background,opacity,unique);
density=DestroyString(density);
status=ExternalDelegateCommand(MagickFalse,image_info->verbose,command,
(char *) NULL,exception);
(void) RelinquishUniqueFileResource(unique);
(void) RelinquishUniqueFileResource(input_filename);
if ((status == 0) && (stat(output_filename,&attributes) == 0) &&
(attributes.st_size > 0))
{
Image
*svg_image;
ImageInfo
*read_info;
read_info=CloneImageInfo(image_info);
(void) CopyMagickString(read_info->filename,output_filename,
MagickPathExtent);
svg_image=ReadImage(read_info,exception);
read_info=DestroyImageInfo(read_info);
if (svg_image != (Image *) NULL)
{
(void) RelinquishUniqueFileResource(output_filename);
for (next=GetFirstImageInList(svg_image); next != (Image *) NULL; )
{
(void) CopyMagickString(next->filename,image->filename,
MagickPathExtent);
(void) CopyMagickString(next->magick,image->magick,
MagickPathExtent);
next=GetNextImageInList(next);
}
return(svg_image);
}
}
(void) RelinquishUniqueFileResource(output_filename);
return((Image *) NULL);
}
#if defined(MAGICKCORE_RSVG_DELEGATE)
static Image *RenderRSVGImage(const ImageInfo *image_info,Image *image,
ExceptionInfo *exception)
{
#if defined(MAGICKCORE_CAIRO_DELEGATE)
cairo_surface_t
*cairo_surface;
cairo_t
*cairo_image;
MagickBooleanType
apply_density;
MemoryInfo
*pixel_info;
unsigned char
*p;
RsvgDimensionData
dimension_info;
unsigned char
*pixels;
#else
GdkPixbuf
*pixel_buffer;
const guchar
*p;
#endif
const char
*option;
GError
*error;
Image
*next;
MagickBooleanType
status;
PixelInfo
fill_color;
Quantum
*q;
RsvgHandle
*svg_handle;
ssize_t
n,
x,
y;
unsigned char
*buffer;
buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
sizeof(*buffer));
if (buffer == (unsigned char *) NULL)
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
#if LIBRSVG_CHECK_VERSION(2,40,3)
option=GetImageOption(image_info,"svg:xml-parse-huge");
if ((option != (char *) NULL) && (IsStringTrue(option) != MagickFalse))
svg_handle=rsvg_handle_new_with_flags(RSVG_HANDLE_FLAG_UNLIMITED);
else
#endif
svg_handle=rsvg_handle_new();
if (svg_handle == (RsvgHandle *) NULL)
{
buffer=(unsigned char *) RelinquishMagickMemory(buffer);
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
}
rsvg_handle_set_base_uri(svg_handle,image_info->filename);
if ((fabs(image->resolution.x) > MagickEpsilon) &&
(fabs(image->resolution.y) > MagickEpsilon))
rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
image->resolution.y);
while ((n=ReadBlob(image,MagickMaxBufferExtent-1,buffer)) != 0)
{
buffer[n]='\0';
error=(GError *) NULL;
(void) rsvg_handle_write(svg_handle,buffer,n,&error);
if (error != (GError *) NULL)
g_error_free(error);
}
buffer=(unsigned char *) RelinquishMagickMemory(buffer);
error=(GError *) NULL;
rsvg_handle_close(svg_handle,&error);
if (error != (GError *) NULL)
g_error_free(error);
#if defined(MAGICKCORE_CAIRO_DELEGATE)
apply_density=MagickTrue;
rsvg_handle_get_dimensions(svg_handle,&dimension_info);
if ((image->resolution.x > 0.0) && (image->resolution.y > 0.0))
{
RsvgDimensionData
dpi_dimension_info;
/*
We should not apply the density when the internal 'factor' is 'i'.
This can be checked by using the trick below.
*/
rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x*256,
image->resolution.y*256);
rsvg_handle_get_dimensions(svg_handle,&dpi_dimension_info);
if ((fabs((double) dpi_dimension_info.width-dimension_info.width) >= MagickEpsilon) ||
(fabs((double) dpi_dimension_info.height-dimension_info.height) >= MagickEpsilon))
apply_density=MagickFalse;
rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
image->resolution.y);
}
if (image_info->size != (char *) NULL)
{
(void) GetGeometry(image_info->size,(ssize_t *) NULL,(ssize_t *) NULL,
&image->columns,&image->rows);
if ((image->columns != 0) || (image->rows != 0))
{
image->resolution.x=DefaultSVGDensity*image->columns/
dimension_info.width;
image->resolution.y=DefaultSVGDensity*image->rows/
dimension_info.height;
if (fabs(image->resolution.x) < MagickEpsilon)
image->resolution.x=image->resolution.y;
else
if (fabs(image->resolution.y) < MagickEpsilon)
image->resolution.y=image->resolution.x;
else
image->resolution.x=image->resolution.y=MagickMin(
image->resolution.x,image->resolution.y);
apply_density=MagickTrue;
}
}
if (apply_density != MagickFalse)
{
image->columns=image->resolution.x*dimension_info.width/
DefaultSVGDensity;
image->rows=image->resolution.y*dimension_info.height/
DefaultSVGDensity;
}
else
{
image->columns=dimension_info.width;
image->rows=dimension_info.height;
}
pixel_info=(MemoryInfo *) NULL;
#else
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->alpha_trait=BlendPixelTrait;
if (image_info->ping == MagickFalse)
{
#if defined(MAGICKCORE_CAIRO_DELEGATE)
size_t
stride;
#endif
status=SetImageExtent(image,image->columns,image->rows,exception);
if (status == MagickFalse)
{
#if !defined(MAGICKCORE_CAIRO_DELEGATE)
g_object_unref(G_OBJECT(pixel_buffer));
#endif
g_object_unref(svg_handle);
ThrowReaderException(MissingDelegateError,
"NoDecodeDelegateForThisImageFormat");
}
#if defined(MAGICKCORE_CAIRO_DELEGATE)
stride=4*image->columns;
#if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
(int) 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);
#if defined(MAGICKCORE_CAIRO_DELEGATE)
cairo_surface=cairo_image_surface_create_for_data(pixels,
CAIRO_FORMAT_ARGB32,(int) image->columns,(int) image->rows,(int)
stride);
if ((cairo_surface == (cairo_surface_t *) NULL) ||
(cairo_surface_status(cairo_surface) != CAIRO_STATUS_SUCCESS))
{
if (cairo_surface != (cairo_surface_t *) NULL)
cairo_surface_destroy(cairo_surface);
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);
if (apply_density != MagickFalse)
cairo_scale(cairo_image,image->resolution.x/DefaultSVGDensity,
image->resolution.y/DefaultSVGDensity);
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_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++)
{
#if defined(MAGICKCORE_CAIRO_DELEGATE)
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++);
#endif
fill_color.alpha=ScaleCharToQuantum(*p++);
#if defined(MAGICKCORE_CAIRO_DELEGATE)
{
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,(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)
else
g_object_unref(svg_handle);
if (pixel_info != (MemoryInfo *) NULL)
pixel_info=RelinquishVirtualMemory(pixel_info);
#else
g_object_unref(G_OBJECT(pixel_buffer));
#endif
(void) CloseBlob(image);
for (next=GetFirstImageInList(image); next != (Image *) NULL; )
{
(void) CopyMagickString(next->filename,image->filename,MagickPathExtent);
(void) CopyMagickString(next->magick,image->magick,MagickPathExtent);
next=GetNextImageInList(next);
}
return(GetFirstImageInList(image));
}
#endif
#if defined(MAGICKCORE_XML_DELEGATE)
static SVGInfo *AcquireSVGInfo(void)
{
SVGInfo
*svg_info;
svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
if (svg_info == (SVGInfo *) NULL)
return((SVGInfo *) NULL);
(void) memset(svg_info,0,sizeof(*svg_info));
svg_info->text=AcquireString("");
svg_info->scale=(double *) AcquireCriticalMemory(sizeof(*svg_info->scale));
GetAffineMatrix(&svg_info->affine);
svg_info->scale[0]=ExpandAffine(&svg_info->affine);
return(svg_info);
}
static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
{
if (svg_info->size != (char *) NULL)
svg_info->size=DestroyString(svg_info->size);
if (svg_info->text != (char *) NULL)
svg_info->text=DestroyString(svg_info->text);
if (svg_info->scale != (double *) NULL)
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)
svg_info->comment=DestroyString(svg_info->comment);
return((SVGInfo *) RelinquishMagickMemory(svg_info));
}
static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
const char *string)
{
char
*next_token,
token[MagickPathExtent];
const char
*p;
double
value;
if (IsEventLogging() != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
assert(string != (const char *) NULL);
p=(const char *) string;
(void) GetNextToken(p,&p,MagickPathExtent,token);
value=StringToDouble(token,&next_token);
if (strchr(token,'%') != (char *) NULL)
{
double
alpha,
beta;
if (type > 0)
{
if (svg_info->view_box.width < MagickEpsilon)
return(0.0);
return(svg_info->view_box.width*value/100.0);
}
if (type < 0)
{
if (svg_info->view_box.height < MagickEpsilon)
return(0.0);
return(svg_info->view_box.height*value/100.0);
}
alpha=value-svg_info->view_box.width;
beta=value-svg_info->view_box.height;
return(hypot(alpha,beta)/sqrt(2.0)/100.0);
}
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (LocaleNCompare(token,"cm",2) == 0)
return(DefaultSVGDensity*svg_info->scale[0]/2.54*value);
if (LocaleNCompare(token,"em",2) == 0)
return(svg_info->pointsize*value);
if (LocaleNCompare(token,"ex",2) == 0)
return(svg_info->pointsize*value/2.0);
if (LocaleNCompare(token,"in",2) == 0)
return(DefaultSVGDensity*svg_info->scale[0]*value);
if (LocaleNCompare(token,"mm",2) == 0)
return(DefaultSVGDensity*svg_info->scale[0]/25.4*value);
if (LocaleNCompare(token,"pc",2) == 0)
return(DefaultSVGDensity*svg_info->scale[0]/6.0*value);
if (LocaleNCompare(token,"pt",2) == 0)
return(svg_info->scale[0]*value);
if (LocaleNCompare(token,"px",2) == 0)
return(value);
return(value);
}
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static int SVGIsStandalone(void *context)
{
SVGInfo
*svg_info;
/*
Is this document tagged standalone?
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
svg_info=(SVGInfo *) context;
return(svg_info->document->standalone == 1);
}
static int SVGHasInternalSubset(void *context)
{
SVGInfo
*svg_info;
/*
Does this document has an internal subset?
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.SVGHasInternalSubset()");
svg_info=(SVGInfo *) context;
return(svg_info->document->intSubset != NULL);
}
static int SVGHasExternalSubset(void *context)
{
SVGInfo
*svg_info;
/*
Does this document has an external subset?
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.SVGHasExternalSubset()");
svg_info=(SVGInfo *) context;
return(svg_info->document->extSubset != NULL);
}
static void SVGInternalSubset(void *context,const xmlChar *name,
const xmlChar *external_id,const xmlChar *system_id)
{
SVGInfo
*svg_info;
/*
Does this document have an internal subset?
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.internalSubset(%s, %s, %s)",(const char *) name,
(external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
(system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
svg_info=(SVGInfo *) context;
(void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
}
static xmlParserInputPtr SVGResolveEntity(void *context,
const xmlChar *public_id,const xmlChar *system_id)
{
SVGInfo
*svg_info;
xmlParserInputPtr
stream;
/*
Special entity resolver, better left to the parser, it has more
context than the application layer. The default behaviour is to
not resolve the entities, in that case the ENTITY_REF nodes are
built in the structure (and the parameter values).
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.resolveEntity(%s, %s)",
(public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
(system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
svg_info=(SVGInfo *) context;
stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
public_id,svg_info->parser);
return(stream);
}
static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
{
SVGInfo
*svg_info;
/*
Get an entity by name.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
name);
svg_info=(SVGInfo *) context;
return(xmlGetDocEntity(svg_info->document,name));
}
static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
{
SVGInfo
*svg_info;
/*
Get a parameter entity by name.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.getParameterEntity(%s)",name);
svg_info=(SVGInfo *) context;
return(xmlGetParameterEntity(svg_info->document,name));
}
static void SVGError(void *,const char *,...)
magick_attribute((__format__ (__printf__,2,3)));
static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
{
SVGInfo
*svg_info;
xmlEntityPtr
entity;
/*
An entity definition has been parsed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
svg_info=(SVGInfo *) context;
if (svg_info->parser->inSubset == 1)
entity=xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
content);
else
if (svg_info->parser->inSubset == 2)
entity=xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
content);
else
return;
if (entity == (xmlEntityPtr) NULL)
SVGError(svg_info,"NULL entity");
}
static void SVGAttributeDeclaration(void *context,const xmlChar *element,
const xmlChar *name,int type,int value,const xmlChar *default_value,
xmlEnumerationPtr tree)
{
SVGInfo
*svg_info;
xmlChar
*fullname,
*prefix;
xmlParserCtxtPtr
parser;
/*
An attribute definition has been parsed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
default_value);
svg_info=(SVGInfo *) context;
fullname=(xmlChar *) NULL;
prefix=(xmlChar *) NULL;
parser=svg_info->parser;
fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
if (parser->inSubset == 1)
(void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
element,fullname,prefix,(xmlAttributeType) type,
(xmlAttributeDefault) value,default_value,tree);
else
if (parser->inSubset == 2)
(void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
element,fullname,prefix,(xmlAttributeType) type,
(xmlAttributeDefault) value,default_value,tree);
if (prefix != (xmlChar *) NULL)
xmlFree(prefix);
if (fullname != (xmlChar *) NULL)
xmlFree(fullname);
}
static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
xmlElementContentPtr content)
{
SVGInfo
*svg_info;
xmlParserCtxtPtr
parser;
/*
An element definition has been parsed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.elementDecl(%s, %d, ...)",name,type);
svg_info=(SVGInfo *) context;
parser=svg_info->parser;
if (parser->inSubset == 1)
(void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
name,(xmlElementTypeVal) type,content);
else
if (parser->inSubset == 2)
(void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
name,(xmlElementTypeVal) type,content);
}
static void SVGStripString(const MagickBooleanType trim,char *message)
{
char
*p,
*q;
size_t
length;
assert(message != (char *) NULL);
if (*message == '\0')
return;
/*
Remove comment.
*/
q=message;
for (p=message; *p != '\0'; p++)
{
if ((*p == '/') && (*(p+1) == '*'))
{
for ( ; *p != '\0'; p++)
if ((*p == '*') && (*(p+1) == '/'))
{
p+=2;
break;
}
if (*p == '\0')
break;
}
*q++=(*p);
}
*q='\0';
length=strlen(message);
if ((trim != MagickFalse) && (length != 0))
{
/*
Remove whitespace.
*/
p=message;
while (isspace((int) ((unsigned char) *p)) != 0)
p++;
if ((*p == '\'') || (*p == '"'))
p++;
q=message+length-1;
while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
q--;
if (q > p)
if ((*q == '\'') || (*q == '"'))
q--;
(void) memmove(message,p,(size_t) (q-p+1));
message[q-p+1]='\0';
}
/*
Convert newlines to a space.
*/
for (p=message; *p != '\0'; p++)
if (*p == '\n')
*p=' ';
}
static char **SVGKeyValuePairs(void *context,const int key_sentinel,
const int value_sentinel,const char *text,size_t *number_tokens)
{
char
**tokens;
const char
*p,
*q;
ssize_t
i;
size_t
extent;
SVGInfo
*svg_info;
svg_info=(SVGInfo *) context;
*number_tokens=0;
if (text == (const char *) NULL)
return((char **) NULL);
extent=8;
tokens=(char **) AcquireQuantumMemory(extent+2UL,sizeof(*tokens));
if (tokens == (char **) NULL)
{
(void) ThrowMagickException(svg_info->exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
return((char **) NULL);
}
/*
Convert string to an ASCII list.
*/
i=0;
p=text;
for (q=p; *q != '\0'; q++)
{
if ((*q != key_sentinel) && (*q != value_sentinel) && (*q != '\0'))
continue;
if (i == (ssize_t) extent)
{
extent<<=1;
tokens=(char **) ResizeQuantumMemory(tokens,extent+2,sizeof(*tokens));
if (tokens == (char **) NULL)
{
(void) ThrowMagickException(svg_info->exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
return((char **) NULL);
}
}
tokens[i]=(char *) AcquireMagickMemory((size_t) (q-p+2));
if (tokens[i] == (char *) NULL)
{
(void) ThrowMagickException(svg_info->exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
break;
}
(void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
SVGStripString(MagickTrue,tokens[i]);
i++;
p=q+1;
}
tokens[i]=(char *) AcquireMagickMemory((size_t) (q-p+2));
if (tokens[i] == (char *) NULL)
(void) ThrowMagickException(svg_info->exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
else
{
(void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
SVGStripString(MagickTrue,tokens[i++]);
}
tokens[i]=(char *) NULL;
*number_tokens=(size_t) i;
return(tokens);
}
static void SVGNotationDeclaration(void *context,const xmlChar *name,
const xmlChar *public_id,const xmlChar *system_id)
{
SVGInfo
*svg_info;
xmlParserCtxtPtr
parser;
/*
What to do when a notation declaration has been parsed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.notationDecl(%s, %s, %s)",name,
public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
svg_info=(SVGInfo *) context;
parser=svg_info->parser;
if (parser->inSubset == 1)
(void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
name,public_id,system_id);
else
if (parser->inSubset == 2)
(void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
name,public_id,system_id);
}
static void SVGProcessStyleElement(void *context,const xmlChar *name,
const char *style)
{
char
background[MagickPathExtent],
*color,
*keyword,
*units,
*value;
char
**tokens;
ssize_t
i;
size_t
number_tokens;
SVGInfo
*svg_info;
(void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
svg_info=(SVGInfo *) context;
tokens=SVGKeyValuePairs(context,':',';',style,&number_tokens);
if (tokens == (char **) NULL)
return;
for (i=0; i < (ssize_t) (number_tokens-1); i+=2)
{
keyword=(char *) tokens[i];
value=(char *) tokens[i+1];
if (LocaleCompare(keyword,"font-size") != 0)
continue;
svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
(void) FormatLocaleFile(svg_info->file,"font-size %g\n",
svg_info->pointsize);
}
color=AcquireString("none");
units=AcquireString("userSpaceOnUse");
for (i=0; i < (ssize_t) (number_tokens-1); i+=2)
{
keyword=(char *) tokens[i];
value=(char *) tokens[i+1];
(void) LogMagickEvent(CoderEvent,GetMagickModule()," %s: %s",keyword,
value);
switch (*keyword)
{
case 'B':
case 'b':
{
if (LocaleCompare((const char *) name,"background") == 0)
{
if (LocaleCompare((const char *) name,"svg") == 0)
(void) CopyMagickString(background,value,MagickPathExtent);
break;
}
break;
}
case 'C':
case 'c':
{
if (LocaleCompare(keyword,"clip-path") == 0)
{
(void) FormatLocaleFile(svg_info->file,"clip-path \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"clip-rule") == 0)
{
(void) FormatLocaleFile(svg_info->file,"clip-rule \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"clipPathUnits") == 0)
{
(void) CloneString(&units,value);
(void) FormatLocaleFile(svg_info->file,"clip-units \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"color") == 0)
{
(void) CloneString(&color,value);
(void) FormatLocaleFile(svg_info->file,"currentColor \"%s\"\n",
color);
break;
}
break;
}
case 'F':
case 'f':
{
if (LocaleCompare(keyword,"fill") == 0)
{
if (LocaleCompare(value,"currentColor") == 0)
{
(void) FormatLocaleFile(svg_info->file,"fill \"%s\"\n",color);
break;
}
if (LocaleCompare(value,"#000000ff") == 0)
(void) FormatLocaleFile(svg_info->file,"fill '#000000'\n");
else
(void) FormatLocaleFile(svg_info->file,"fill \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"fillcolor") == 0)
{
(void) FormatLocaleFile(svg_info->file,"fill \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"fill-rule") == 0)
{
(void) FormatLocaleFile(svg_info->file,"fill-rule \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"fill-opacity") == 0)
{
(void) FormatLocaleFile(svg_info->file,"fill-opacity \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"font") == 0)
{
char
font_family[MagickPathExtent],
font_size[MagickPathExtent],
font_style[MagickPathExtent];
if (sscanf(value,"%2048s %2048s %2048s",font_style,font_size,
font_family) != 3)
break;
if (GetUserSpaceCoordinateValue(svg_info,0,font_style) == 0)
(void) FormatLocaleFile(svg_info->file,"font-style \"%s\"\n",
style);
else
if (sscanf(value,"%2048s %2048s",font_size,font_family) != 2)
break;
(void) FormatLocaleFile(svg_info->file,"font-size \"%s\"\n",
font_size);
(void) FormatLocaleFile(svg_info->file,"font-family \"%s\"\n",
font_family);
break;
}
if (LocaleCompare(keyword,"font-family") == 0)
{
(void) FormatLocaleFile(svg_info->file,"font-family \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"font-stretch") == 0)
{
(void) FormatLocaleFile(svg_info->file,"font-stretch \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"font-style") == 0)
{
(void) FormatLocaleFile(svg_info->file,"font-style \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"font-size") == 0)
{
svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
(void) FormatLocaleFile(svg_info->file,"font-size %g\n",
svg_info->pointsize);
break;
}
if (LocaleCompare(keyword,"font-weight") == 0)
{
(void) FormatLocaleFile(svg_info->file,"font-weight \"%s\"\n",
value);
break;
}
break;
}
case 'K':
case 'k':
{
if (LocaleCompare(keyword,"kerning") == 0)
{
(void) FormatLocaleFile(svg_info->file,"kerning \"%s\"\n",value);
break;
}
break;
}
case 'L':
case 'l':
{
if (LocaleCompare(keyword,"letter-spacing") == 0)
{
(void) FormatLocaleFile(svg_info->file,"letter-spacing \"%s\"\n",
value);
break;
}
break;
}
case 'M':
case 'm':
{
if (LocaleCompare(keyword,"mask") == 0)
{
(void) FormatLocaleFile(svg_info->file,"mask \"%s\"\n",value);
break;
}
break;
}
case 'O':
case 'o':
{
if (LocaleCompare(keyword,"offset") == 0)
{
(void) FormatLocaleFile(svg_info->file,"offset %g\n",
GetUserSpaceCoordinateValue(svg_info,1,value));
break;
}
if (LocaleCompare(keyword,"opacity") == 0)
{
(void) FormatLocaleFile(svg_info->file,"opacity \"%s\"\n",value);
break;
}
break;
}
case 'S':
case 's':
{
if (LocaleCompare(keyword,"stop-color") == 0)
{
(void) CloneString(&svg_info->stop_color,value);
break;
}
if (LocaleCompare(keyword,"stroke") == 0)
{
if (LocaleCompare(value,"currentColor") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke \"%s\"\n",color);
break;
}
if (LocaleCompare(value,"#000000ff") == 0)
(void) FormatLocaleFile(svg_info->file,"fill '#000000'\n");
else
(void) FormatLocaleFile(svg_info->file,
"stroke \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
LocaleCompare(value,"true") == 0);
break;
}
if (LocaleCompare(keyword,"stroke-dasharray") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
value);
break;
}
if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %g\n",
GetUserSpaceCoordinateValue(svg_info,1,value));
break;
}
if (LocaleCompare(keyword,"stroke-linecap") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-linecap \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"stroke-linejoin") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-linejoin \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-miterlimit \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"stroke-opacity") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-opacity \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"stroke-width") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
GetUserSpaceCoordinateValue(svg_info,1,value));
break;
}
break;
}
case 't':
case 'T':
{
if (LocaleCompare(keyword,"text-align") == 0)
{
(void) FormatLocaleFile(svg_info->file,"text-align \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"text-anchor") == 0)
{
(void) FormatLocaleFile(svg_info->file,"text-anchor \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"text-decoration") == 0)
{
if (LocaleCompare(value,"underline") == 0)
(void) FormatLocaleFile(svg_info->file,"decorate underline\n");
if (LocaleCompare(value,"line-through") == 0)
(void) FormatLocaleFile(svg_info->file,"decorate line-through\n");
if (LocaleCompare(value,"overline") == 0)
(void) FormatLocaleFile(svg_info->file,"decorate overline\n");
break;
}
if (LocaleCompare(keyword,"text-antialiasing") == 0)
{
(void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
LocaleCompare(value,"true") == 0);
break;
}
break;
}
default:
break;
}
}
if (units != (char *) NULL)
units=DestroyString(units);
if (color != (char *) NULL)
color=DestroyString(color);
for (i=0; tokens[i] != (char *) NULL; i++)
tokens[i]=DestroyString(tokens[i]);
tokens=(char **) RelinquishMagickMemory(tokens);
}
static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
{
SVGInfo
*svg_info;
/*
What to do when an unparsed entity declaration is parsed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
svg_info=(SVGInfo *) context;
(void) xmlAddDocEntity(svg_info->document,name,
XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
}
static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
{
SVGInfo
*svg_info;
/*
Receive the document locator at startup, actually xmlDefaultSAXLocator.
*/
(void) location;
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.setDocumentLocator()");
svg_info=(SVGInfo *) context;
(void) svg_info;
}
static void SVGStartDocument(void *context)
{
SVGInfo
*svg_info;
xmlParserCtxtPtr
parser;
/*
Called when the document start being processed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
svg_info=(SVGInfo *) context;
parser=svg_info->parser;
svg_info->document=xmlNewDoc(parser->version);
if (svg_info->document == (xmlDocPtr) NULL)
return;
if (parser->encoding == NULL)
svg_info->document->encoding=(const xmlChar *) NULL;
else
svg_info->document->encoding=xmlStrdup(parser->encoding);
svg_info->document->standalone=parser->standalone;
}
static void SVGEndDocument(void *context)
{
SVGInfo
*svg_info;
/*
Called when the document end has been detected.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
svg_info=(SVGInfo *) context;
if (svg_info->offset != (char *) NULL)
svg_info->offset=DestroyString(svg_info->offset);
if (svg_info->stop_color != (char *) NULL)
svg_info->stop_color=DestroyString(svg_info->stop_color);
if (svg_info->scale != (double *) NULL)
svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
if (svg_info->text != (char *) NULL)
svg_info->text=DestroyString(svg_info->text);
if (svg_info->vertices != (char *) NULL)
svg_info->vertices=DestroyString(svg_info->vertices);
if (svg_info->url != (char *) NULL)
svg_info->url=DestroyString(svg_info->url);
#if defined(MAGICKCORE_XML_DELEGATE)
if (svg_info->document != (xmlDocPtr) NULL)
{
xmlFreeDoc(svg_info->document);
svg_info->document=(xmlDocPtr) NULL;
}
#endif
}
static void SVGStartElement(void *context,const xmlChar *name,
const xmlChar **attributes)
{
#define PushGraphicContext(id) \
{ \
if (*id == '\0') \
(void) FormatLocaleFile(svg_info->file,"push graphic-context\n"); \
else \
(void) FormatLocaleFile(svg_info->file,"push graphic-context \"%s\"\n", \
id); \
}
char
*color,
background[MagickPathExtent],
id[MagickPathExtent],
*next_token,
token[MagickPathExtent],
**tokens,
*units;
const char
*keyword,
*p,
*value;
ssize_t
i,
j;
size_t
number_tokens;
SVGInfo
*svg_info;
/*
Called when an opening tag has been processed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
name);
svg_info=(SVGInfo *) context;
svg_info->n++;
svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
svg_info->n+1UL,sizeof(*svg_info->scale));
if (svg_info->scale == (double *) NULL)
{
(void) ThrowMagickException(svg_info->exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
return;
}
svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
color=AcquireString("none");
units=AcquireString("userSpaceOnUse");
*id='\0';
*token='\0';
*background='\0';
value=(const char *) NULL;
if ((LocaleCompare((char *) name,"image") == 0) ||
(LocaleCompare((char *) name,"pattern") == 0) ||
(LocaleCompare((char *) name,"rect") == 0) ||
(LocaleCompare((char *) name,"text") == 0) ||
(LocaleCompare((char *) name,"use") == 0))
{
svg_info->bounds.x=0.0;
svg_info->bounds.y=0.0;
}
if (attributes != (const xmlChar **) NULL)
for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
{
keyword=(const char *) attributes[i];
value=(const char *) attributes[i+1];
switch (*keyword)
{
case 'C':
case 'c':
{
if (LocaleCompare(keyword,"cx") == 0)
{
svg_info->element.cx=
GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
if (LocaleCompare(keyword,"cy") == 0)
{
svg_info->element.cy=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
break;
}
case 'F':
case 'f':
{
if (LocaleCompare(keyword,"fx") == 0)
{
svg_info->element.major=
GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
if (LocaleCompare(keyword,"fy") == 0)
{
svg_info->element.minor=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
break;
}
case 'H':
case 'h':
{
if (LocaleCompare(keyword,"height") == 0)
{
svg_info->bounds.height=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
break;
}
case 'I':
case 'i':
{
if (LocaleCompare(keyword,"id") == 0)
{
(void) CopyMagickString(id,value,MagickPathExtent);
break;
}
break;
}
case 'R':
case 'r':
{
if (LocaleCompare(keyword,"r") == 0)
{
svg_info->element.angle=GetUserSpaceCoordinateValue(svg_info,0,
value);
break;
}
break;
}
case 'W':
case 'w':
{
if (LocaleCompare(keyword,"width") == 0)
{
svg_info->bounds.width=
GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
break;
}
case 'X':
case 'x':
{
if (LocaleCompare(keyword,"x") == 0)
{
svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
if (LocaleCompare(keyword,"x1") == 0)
{
svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
value);
break;
}
if (LocaleCompare(keyword,"x2") == 0)
{
svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
value);
break;
}
break;
}
case 'Y':
case 'y':
{
if (LocaleCompare(keyword,"y") == 0)
{
svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
if (LocaleCompare(keyword,"y1") == 0)
{
svg_info->segment.y1=GetUserSpaceCoordinateValue(svg_info,-1,
value);
break;
}
if (LocaleCompare(keyword,"y2") == 0)
{
svg_info->segment.y2=GetUserSpaceCoordinateValue(svg_info,-1,
value);
break;
}
break;
}
default:
break;
}
}
if (strchr((char *) name,':') != (char *) NULL)
{
/*
Skip over namespace.
*/
for ( ; *name != ':'; name++) ;
name++;
}
switch (*name)
{
case 'C':
case 'c':
{
if (LocaleCompare((const char *) name,"circle") == 0)
{
PushGraphicContext(id);
break;
}
if (LocaleCompare((const char *) name,"clipPath") == 0)
{
(void) FormatLocaleFile(svg_info->file,"push clip-path \"%s\"\n",id);
break;
}
break;
}
case 'D':
case 'd':
{
if (LocaleCompare((const char *) name,"defs") == 0)
{
(void) FormatLocaleFile(svg_info->file,"push defs\n");
break;
}
break;
}
case 'E':
case 'e':
{
if (LocaleCompare((const char *) name,"ellipse") == 0)
{
PushGraphicContext(id);
break;
}
break;
}
case 'F':
case 'f':
{
if (LocaleCompare((const char *) name,"foreignObject") == 0)
{
PushGraphicContext(id);
break;
}
break;
}
case 'G':
case 'g':
{
if (LocaleCompare((const char *) name,"g") == 0)
{
PushGraphicContext(id);
break;
}
break;
}
case 'I':
case 'i':
{
if (LocaleCompare((const char *) name,"image") == 0)
{
PushGraphicContext(id);
break;
}
break;
}
case 'L':
case 'l':
{
if (LocaleCompare((const char *) name,"line") == 0)
{
PushGraphicContext(id);
break;
}
if (LocaleCompare((const char *) name,"linearGradient") == 0)
{
(void) FormatLocaleFile(svg_info->file,
"push gradient \"%s\" linear %g,%g %g,%g\n",id,
svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
svg_info->segment.y2);
break;
}
break;
}
case 'M':
case 'm':
{
if (LocaleCompare((const char *) name,"mask") == 0)
{
(void) FormatLocaleFile(svg_info->file,"push mask \"%s\"\n",id);
break;
}
break;
}
case 'P':
case 'p':
{
if (LocaleCompare((const char *) name,"path") == 0)
{
PushGraphicContext(id);
break;
}
if (LocaleCompare((const char *) name,"pattern") == 0)
{
(void) FormatLocaleFile(svg_info->file,
"push pattern \"%s\" %g,%g %g,%g\n",id,
svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
svg_info->bounds.height);
break;
}
if (LocaleCompare((const char *) name,"polygon") == 0)
{
PushGraphicContext(id);
break;
}
if (LocaleCompare((const char *) name,"polyline") == 0)
{
PushGraphicContext(id);
break;
}
break;
}
case 'R':
case 'r':
{
if (LocaleCompare((const char *) name,"radialGradient") == 0)
{
(void) FormatLocaleFile(svg_info->file,
"push gradient \"%s\" radial %g,%g %g,%g %g\n",
id,svg_info->element.cx,svg_info->element.cy,
svg_info->element.major,svg_info->element.minor,
svg_info->element.angle);
break;
}
if (LocaleCompare((const char *) name,"rect") == 0)
{
PushGraphicContext(id);
break;
}
break;
}
case 'S':
case 's':
{
if (LocaleCompare((char *) name,"style") == 0)
break;
if (LocaleCompare((const char *) name,"svg") == 0)
{
svg_info->svgDepth++;
PushGraphicContext(id);
(void) FormatLocaleFile(svg_info->file,"compliance \"SVG\"\n");
(void) FormatLocaleFile(svg_info->file,"fill \"black\"\n");
(void) FormatLocaleFile(svg_info->file,"fill-opacity 1\n");
(void) FormatLocaleFile(svg_info->file,"stroke \"none\"\n");
(void) FormatLocaleFile(svg_info->file,"stroke-width 1\n");
(void) FormatLocaleFile(svg_info->file,"stroke-opacity 1\n");
(void) FormatLocaleFile(svg_info->file,"fill-rule nonzero\n");
break;
}
if (LocaleCompare((const char *) name,"symbol") == 0)
{
(void) FormatLocaleFile(svg_info->file,"push symbol\n");
break;
}
break;
}
case 'T':
case 't':
{
if (LocaleCompare((const char *) name,"text") == 0)
{
PushGraphicContext(id);
svg_info->text_offset.x=svg_info->bounds.x;
svg_info->text_offset.y=svg_info->bounds.y;
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)
{
if (*svg_info->text != '\0')
{
char
*text;
text=EscapeString(svg_info->text,'\"');
(void) FormatLocaleFile(svg_info->file,"text %g,%g \"%s\"\n",
svg_info->text_offset.x,svg_info->text_offset.y,text);
text=DestroyString(text);
*svg_info->text='\0';
}
PushGraphicContext(id);
break;
}
break;
}
case 'U':
case 'u':
{
if (LocaleCompare((char *) name,"use") == 0)
{
PushGraphicContext(id);
break;
}
break;
}
default:
break;
}
if (attributes != (const xmlChar **) NULL)
for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
{
keyword=(const char *) attributes[i];
value=(const char *) attributes[i+1];
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" %s = %s",keyword,value);
switch (*keyword)
{
case 'A':
case 'a':
{
if (LocaleCompare(keyword,"angle") == 0)
{
(void) FormatLocaleFile(svg_info->file,"angle %g\n",
GetUserSpaceCoordinateValue(svg_info,0,value));
break;
}
break;
}
case 'C':
case 'c':
{
if (LocaleCompare(keyword,"class") == 0)
{
p=value;
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token != '\0')
(void) FormatLocaleFile(svg_info->file,"class \"%s\"\n",value);
else
(void) FormatLocaleFile(svg_info->file,"class \"none\"\n");
break;
}
if (LocaleCompare(keyword,"clip-path") == 0)
{
(void) FormatLocaleFile(svg_info->file,"clip-path \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"clip-rule") == 0)
{
(void) FormatLocaleFile(svg_info->file,"clip-rule \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"clipPathUnits") == 0)
{
(void) CloneString(&units,value);
(void) FormatLocaleFile(svg_info->file,"clip-units \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"color") == 0)
{
(void) CloneString(&color,value);
break;
}
if (LocaleCompare(keyword,"cx") == 0)
{
svg_info->element.cx=
GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
if (LocaleCompare(keyword,"cy") == 0)
{
svg_info->element.cy=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
break;
}
case 'D':
case 'd':
{
if (LocaleCompare(keyword,"d") == 0)
{
(void) CloneString(&svg_info->vertices,value);
break;
}
if (LocaleCompare(keyword,"dx") == 0)
{
double
dx;
dx=GetUserSpaceCoordinateValue(svg_info,1,value);
svg_info->bounds.x+=dx;
svg_info->text_offset.x+=dx;
if (LocaleCompare((char *) name,"text") == 0)
(void) FormatLocaleFile(svg_info->file,"translate %g,0.0\n",dx);
break;
}
if (LocaleCompare(keyword,"dy") == 0)
{
double
dy;
dy=GetUserSpaceCoordinateValue(svg_info,-1,value);
svg_info->bounds.y+=dy;
svg_info->text_offset.y+=dy;
if (LocaleCompare((char *) name,"text") == 0)
(void) FormatLocaleFile(svg_info->file,"translate 0.0,%g\n",dy);
break;
}
break;
}
case 'F':
case 'f':
{
if (LocaleCompare(keyword,"fill") == 0)
{
if (LocaleCompare(value,"currentColor") == 0)
{
(void) FormatLocaleFile(svg_info->file,"fill \"%s\"\n",color);
break;
}
(void) FormatLocaleFile(svg_info->file,"fill \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"fillcolor") == 0)
{
(void) FormatLocaleFile(svg_info->file,"fill \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"fill-rule") == 0)
{
(void) FormatLocaleFile(svg_info->file,"fill-rule \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"fill-opacity") == 0)
{
(void) FormatLocaleFile(svg_info->file,"fill-opacity \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"font-family") == 0)
{
(void) FormatLocaleFile(svg_info->file,"font-family \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"font-stretch") == 0)
{
(void) FormatLocaleFile(svg_info->file,"font-stretch \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"font-style") == 0)
{
(void) FormatLocaleFile(svg_info->file,"font-style \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"font-size") == 0)
{
if (LocaleCompare(value,"xx-small") == 0)
svg_info->pointsize=6.144;
else if (LocaleCompare(value,"x-small") == 0)
svg_info->pointsize=7.68;
else if (LocaleCompare(value,"small") == 0)
svg_info->pointsize=9.6;
else if (LocaleCompare(value,"medium") == 0)
svg_info->pointsize=12.0;
else if (LocaleCompare(value,"large") == 0)
svg_info->pointsize=14.4;
else if (LocaleCompare(value,"x-large") == 0)
svg_info->pointsize=17.28;
else if (LocaleCompare(value,"xx-large") == 0)
svg_info->pointsize=20.736;
else
svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,
value);
(void) FormatLocaleFile(svg_info->file,"font-size %g\n",
svg_info->pointsize);
break;
}
if (LocaleCompare(keyword,"font-weight") == 0)
{
(void) FormatLocaleFile(svg_info->file,"font-weight \"%s\"\n",
value);
break;
}
break;
}
case 'G':
case 'g':
{
if (LocaleCompare(keyword,"gradientTransform") == 0)
{
AffineMatrix
affine,
current,
transform;
GetAffineMatrix(&transform);
(void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
tokens=SVGKeyValuePairs(context,'(',')',value,&number_tokens);
if (tokens == (char **) NULL)
break;
for (j=0; j < (ssize_t) (number_tokens-1); j+=2)
{
keyword=(char *) tokens[j];
if (keyword == (char *) NULL)
continue;
value=(char *) tokens[j+1];
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" %s: %s",keyword,value);
current=transform;
GetAffineMatrix(&affine);
switch (*keyword)
{
case 'M':
case 'm':
{
if (LocaleCompare(keyword,"matrix") == 0)
{
p=value;
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.sx=StringToDouble(value,(char **) NULL);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.rx=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.ry=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.sy=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.tx=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.ty=StringToDouble(token,&next_token);
break;
}
break;
}
case 'R':
case 'r':
{
if (LocaleCompare(keyword,"rotate") == 0)
{
double
angle;
angle=GetUserSpaceCoordinateValue(svg_info,0,value);
affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
break;
}
break;
}
case 'S':
case 's':
{
if (LocaleCompare(keyword,"scale") == 0)
{
for (p=value; *p != '\0'; p++)
if ((isspace((int) ((unsigned char) *p)) != 0) ||
(*p == ','))
break;
affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
affine.sy=affine.sx;
if (*p != '\0')
affine.sy=
GetUserSpaceCoordinateValue(svg_info,-1,p+1);
svg_info->scale[svg_info->n]=ExpandAffine(&affine);
break;
}
if (LocaleCompare(keyword,"skewX") == 0)
{
affine.sx=svg_info->affine.sx;
affine.ry=tan(DegreesToRadians(fmod(
GetUserSpaceCoordinateValue(svg_info,1,value),
360.0)));
affine.sy=svg_info->affine.sy;
break;
}
if (LocaleCompare(keyword,"skewY") == 0)
{
affine.sx=svg_info->affine.sx;
affine.rx=tan(DegreesToRadians(fmod(
GetUserSpaceCoordinateValue(svg_info,-1,value),
360.0)));
affine.sy=svg_info->affine.sy;
break;
}
break;
}
case 'T':
case 't':
{
if (LocaleCompare(keyword,"translate") == 0)
{
for (p=value; *p != '\0'; p++)
if ((isspace((int) ((unsigned char) *p)) != 0) ||
(*p == ','))
break;
affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
affine.ty=affine.tx;
if (*p != '\0')
affine.ty=
GetUserSpaceCoordinateValue(svg_info,-1,p+1);
break;
}
break;
}
default:
break;
}
transform.sx=affine.sx*current.sx+affine.ry*current.rx;
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.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,transform.ry,transform.sy,transform.tx,
transform.ty);
for (j=0; tokens[j] != (char *) NULL; j++)
tokens[j]=DestroyString(tokens[j]);
tokens=(char **) RelinquishMagickMemory(tokens);
break;
}
if (LocaleCompare(keyword,"gradientUnits") == 0)
{
(void) CloneString(&units,value);
(void) FormatLocaleFile(svg_info->file,"gradient-units \"%s\"\n",
value);
break;
}
break;
}
case 'H':
case 'h':
{
if (LocaleCompare(keyword,"height") == 0)
{
svg_info->bounds.height=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
if (LocaleCompare(keyword,"href") == 0)
{
(void) CloneString(&svg_info->url,value);
break;
}
break;
}
case 'K':
case 'k':
{
if (LocaleCompare(keyword,"kerning") == 0)
{
(void) FormatLocaleFile(svg_info->file,"kerning \"%s\"\n",
value);
break;
}
break;
}
case 'L':
case 'l':
{
if (LocaleCompare(keyword,"letter-spacing") == 0)
{
(void) FormatLocaleFile(svg_info->file,"letter-spacing \"%s\"\n",
value);
break;
}
break;
}
case 'M':
case 'm':
{
if (LocaleCompare(keyword,"major") == 0)
{
svg_info->element.major=
GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
if (LocaleCompare(keyword,"mask") == 0)
{
(void) FormatLocaleFile(svg_info->file,"mask \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"minor") == 0)
{
svg_info->element.minor=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
break;
}
case 'O':
case 'o':
{
if (LocaleCompare(keyword,"offset") == 0)
{
(void) CloneString(&svg_info->offset,value);
break;
}
if (LocaleCompare(keyword,"opacity") == 0)
{
(void) FormatLocaleFile(svg_info->file,"opacity \"%s\"\n",value);
break;
}
break;
}
case 'P':
case 'p':
{
if (LocaleCompare(keyword,"path") == 0)
{
(void) CloneString(&svg_info->url,value);
break;
}
if (LocaleCompare(keyword,"points") == 0)
{
(void) CloneString(&svg_info->vertices,value);
break;
}
break;
}
case 'R':
case 'r':
{
if (LocaleCompare(keyword,"r") == 0)
{
svg_info->element.major=
GetUserSpaceCoordinateValue(svg_info,1,value);
svg_info->element.minor=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
if (LocaleCompare(keyword,"rotate") == 0)
{
double
angle;
angle=GetUserSpaceCoordinateValue(svg_info,0,value);
(void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
svg_info->bounds.x,svg_info->bounds.y);
svg_info->bounds.x=0;
svg_info->bounds.y=0;
(void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
break;
}
if (LocaleCompare(keyword,"rx") == 0)
{
if (LocaleCompare((const char *) name,"ellipse") == 0)
svg_info->element.major=
GetUserSpaceCoordinateValue(svg_info,1,value);
else
svg_info->radius.x=
GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
if (LocaleCompare(keyword,"ry") == 0)
{
if (LocaleCompare((const char *) name,"ellipse") == 0)
svg_info->element.minor=
GetUserSpaceCoordinateValue(svg_info,-1,value);
else
svg_info->radius.y=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
break;
}
case 'S':
case 's':
{
if (LocaleCompare(keyword,"stop-color") == 0)
{
(void) CloneString(&svg_info->stop_color,value);
break;
}
if (LocaleCompare(keyword,"stroke") == 0)
{
if (LocaleCompare(value,"currentColor") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke \"%s\"\n",
color);
break;
}
(void) FormatLocaleFile(svg_info->file,"stroke \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
LocaleCompare(value,"true") == 0);
break;
}
if (LocaleCompare(keyword,"stroke-dasharray") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
value);
break;
}
if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %g\n",
GetUserSpaceCoordinateValue(svg_info,1,value));
break;
}
if (LocaleCompare(keyword,"stroke-linecap") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-linecap \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"stroke-linejoin") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-linejoin \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
{
(void) FormatLocaleFile(svg_info->file,
"stroke-miterlimit \"%s\"\n",value);
break;
}
if (LocaleCompare(keyword,"stroke-opacity") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-opacity \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"stroke-width") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
GetUserSpaceCoordinateValue(svg_info,1,value));
break;
}
if (LocaleCompare(keyword,"style") == 0)
{
SVGProcessStyleElement(context,name,value);
break;
}
break;
}
case 'T':
case 't':
{
if (LocaleCompare(keyword,"text-align") == 0)
{
(void) FormatLocaleFile(svg_info->file,"text-align \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"text-anchor") == 0)
{
(void) FormatLocaleFile(svg_info->file,"text-anchor \"%s\"\n",
value);
break;
}
if (LocaleCompare(keyword,"text-decoration") == 0)
{
if (LocaleCompare(value,"underline") == 0)
(void) FormatLocaleFile(svg_info->file,"decorate underline\n");
if (LocaleCompare(value,"line-through") == 0)
(void) FormatLocaleFile(svg_info->file,
"decorate line-through\n");
if (LocaleCompare(value,"overline") == 0)
(void) FormatLocaleFile(svg_info->file,"decorate overline\n");
break;
}
if (LocaleCompare(keyword,"text-antialiasing") == 0)
{
(void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
LocaleCompare(value,"true") == 0);
break;
}
if (LocaleCompare(keyword,"transform") == 0)
{
AffineMatrix
affine,
current,
transform;
GetAffineMatrix(&transform);
(void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
tokens=SVGKeyValuePairs(context,'(',')',value,&number_tokens);
if (tokens == (char **) NULL)
break;
for (j=0; j < (ssize_t) (number_tokens-1); j+=2)
{
keyword=(char *) tokens[j];
value=(char *) tokens[j+1];
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" %s: %s",keyword,value);
current=transform;
GetAffineMatrix(&affine);
switch (*keyword)
{
case 'M':
case 'm':
{
if (LocaleCompare(keyword,"matrix") == 0)
{
p=value;
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.sx=StringToDouble(value,(char **) NULL);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.rx=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.ry=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.sy=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.tx=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
affine.ty=StringToDouble(token,&next_token);
break;
}
break;
}
case 'R':
case 'r':
{
if (LocaleCompare(keyword,"rotate") == 0)
{
double
angle,
x,
y;
p=value;
(void) GetNextToken(p,&p,MagickPathExtent,token);
angle=StringToDouble(value,(char **) NULL);
affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
x=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
y=StringToDouble(token,&next_token);
y=StringToDouble(token,&next_token);
affine.tx=(-1.0*(svg_info->bounds.x+x*
cos(DegreesToRadians(fmod(angle,360.0)))-y*
sin(DegreesToRadians(fmod(angle,360.0)))))+x;
affine.ty=(-1.0*(svg_info->bounds.y+x*
sin(DegreesToRadians(fmod(angle,360.0)))+y*
cos(DegreesToRadians(fmod(angle,360.0)))))+y;
break;
}
break;
}
case 'S':
case 's':
{
if (LocaleCompare(keyword,"scale") == 0)
{
for (p=value; *p != '\0'; p++)
if ((isspace((int) ((unsigned char) *p)) != 0) ||
(*p == ','))
break;
affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
affine.sy=affine.sx;
if (*p != '\0')
affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
p+1);
svg_info->scale[svg_info->n]=ExpandAffine(&affine);
break;
}
if (LocaleCompare(keyword,"skewX") == 0)
{
affine.sx=svg_info->affine.sx;
affine.ry=tan(DegreesToRadians(fmod(
GetUserSpaceCoordinateValue(svg_info,1,value),
360.0)));
affine.sy=svg_info->affine.sy;
break;
}
if (LocaleCompare(keyword,"skewY") == 0)
{
affine.sx=svg_info->affine.sx;
affine.rx=tan(DegreesToRadians(fmod(
GetUserSpaceCoordinateValue(svg_info,-1,value),
360.0)));
affine.sy=svg_info->affine.sy;
break;
}
break;
}
case 'T':
case 't':
{
if (LocaleCompare(keyword,"translate") == 0)
{
for (p=value; *p != '\0'; p++)
if ((isspace((int) ((unsigned char) *p)) != 0) ||
(*p == ','))
break;
affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
affine.ty=0;
if (*p != '\0')
affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
p+1);
break;
}
break;
}
default:
break;
}
transform.sx=affine.sx*current.sx+affine.ry*current.rx;
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.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,
transform.ry,transform.sy,transform.tx,transform.ty);
for (j=0; tokens[j] != (char *) NULL; j++)
tokens[j]=DestroyString(tokens[j]);
tokens=(char **) RelinquishMagickMemory(tokens);
break;
}
break;
}
case 'V':
case 'v':
{
if (LocaleCompare(keyword,"verts") == 0)
{
(void) CloneString(&svg_info->vertices,value);
break;
}
if (LocaleCompare(keyword,"viewBox") == 0)
{
p=value;
(void) GetNextToken(p,&p,MagickPathExtent,token);
svg_info->view_box.x=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
svg_info->view_box.y=StringToDouble(token,&next_token);
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
svg_info->view_box.width=StringToDouble(token,
(char **) NULL);
if (svg_info->bounds.width < MagickEpsilon)
svg_info->bounds.width=svg_info->view_box.width;
(void) GetNextToken(p,&p,MagickPathExtent,token);
if (*token == ',')
(void) GetNextToken(p,&p,MagickPathExtent,token);
svg_info->view_box.height=StringToDouble(token,
(char **) NULL);
if (svg_info->bounds.height == 0)
svg_info->bounds.height=svg_info->view_box.height;
break;
}
break;
}
case 'W':
case 'w':
{
if (LocaleCompare(keyword,"width") == 0)
{
svg_info->bounds.width=
GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
break;
}
case 'X':
case 'x':
{
if (LocaleCompare(keyword,"x") == 0)
{
svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
if (LocaleCompare(keyword,"xlink:href") == 0)
{
(void) CloneString(&svg_info->url,value);
break;
}
if (LocaleCompare(keyword,"x1") == 0)
{
svg_info->segment.x1=
GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
if (LocaleCompare(keyword,"x2") == 0)
{
svg_info->segment.x2=
GetUserSpaceCoordinateValue(svg_info,1,value);
break;
}
break;
}
case 'Y':
case 'y':
{
if (LocaleCompare(keyword,"y") == 0)
{
svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
if (LocaleCompare(keyword,"y1") == 0)
{
svg_info->segment.y1=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
if (LocaleCompare(keyword,"y2") == 0)
{
svg_info->segment.y2=
GetUserSpaceCoordinateValue(svg_info,-1,value);
break;
}
break;
}
default:
break;
}
}
if (LocaleCompare((const char *) name,"svg") == 0)
{
if (svg_info->document->encoding != (const xmlChar *) NULL)
(void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
(const char *) svg_info->document->encoding);
if (attributes != (const xmlChar **) NULL)
{
double
sx,
sy,
tx,
ty;
if ((svg_info->view_box.width < MagickEpsilon) ||
(svg_info->view_box.height < MagickEpsilon))
svg_info->view_box=svg_info->bounds;
svg_info->width=0;
if (svg_info->bounds.width >= MagickEpsilon)
svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
svg_info->height=0;
if (svg_info->bounds.height >= MagickEpsilon)
svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
(void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
(double) svg_info->width,(double) svg_info->height);
sx=PerceptibleReciprocal(svg_info->view_box.width)*svg_info->width;
sy=PerceptibleReciprocal(svg_info->view_box.height)*svg_info->height;
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);
if ((svg_info->svgDepth == 1) && (*background != '\0'))
{
PushGraphicContext(id);
(void) FormatLocaleFile(svg_info->file,"fill %s\n",background);
(void) FormatLocaleFile(svg_info->file,
"rectangle 0,0 %g,%g\n",svg_info->view_box.width,
svg_info->view_box.height);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
}
}
}
(void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
if (units != (char *) NULL)
units=DestroyString(units);
if (color != (char *) NULL)
color=DestroyString(color);
}
static void SVGEndElement(void *context,const xmlChar *name)
{
SVGInfo
*svg_info;
/*
Called when the end of an element has been detected.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.endElement(%s)",name);
svg_info=(SVGInfo *) context;
if (strchr((char *) name,':') != (char *) NULL)
{
/*
Skip over namespace.
*/
for ( ; *name != ':'; name++) ;
name++;
}
switch (*name)
{
case 'C':
case 'c':
{
if (LocaleCompare((const char *) name,"circle") == 0)
{
(void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
svg_info->element.cy+svg_info->element.minor);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
if (LocaleCompare((const char *) name,"clipPath") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
break;
}
break;
}
case 'D':
case 'd':
{
if (LocaleCompare((const char *) name,"defs") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop defs\n");
break;
}
if (LocaleCompare((const char *) name,"desc") == 0)
{
char
*p;
if (*svg_info->text == '\0')
break;
(void) fputc('#',svg_info->file);
for (p=svg_info->text; *p != '\0'; p++)
{
(void) fputc(*p,svg_info->file);
if (*p == '\n')
(void) fputc('#',svg_info->file);
}
(void) fputc('\n',svg_info->file);
*svg_info->text='\0';
break;
}
break;
}
case 'E':
case 'e':
{
if (LocaleCompare((const char *) name,"ellipse") == 0)
{
double
angle;
angle=svg_info->element.angle;
(void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
svg_info->element.cx,svg_info->element.cy,
angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
break;
}
case 'F':
case 'f':
{
if (LocaleCompare((const char *) name,"foreignObject") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
break;
}
case 'G':
case 'g':
{
if (LocaleCompare((const char *) name,"g") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
break;
}
case 'I':
case 'i':
{
if (LocaleCompare((const char *) name,"image") == 0)
{
(void) FormatLocaleFile(svg_info->file,
"image Over %g,%g %g,%g \"%s\"\n",svg_info->bounds.x,
svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
svg_info->url);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
break;
}
case 'L':
case 'l':
{
if (LocaleCompare((const char *) name,"line") == 0)
{
(void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
svg_info->segment.y2);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
if (LocaleCompare((const char *) name,"linearGradient") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop gradient\n");
break;
}
break;
}
case 'M':
case 'm':
{
if (LocaleCompare((const char *) name,"mask") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop mask\n");
break;
}
break;
}
case 'P':
case 'p':
{
if (LocaleCompare((const char *) name,"pattern") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop pattern\n");
break;
}
if (LocaleCompare((const char *) name,"path") == 0)
{
(void) FormatLocaleFile(svg_info->file,"path \"%s\"\n",
svg_info->vertices);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
if (LocaleCompare((const char *) name,"polygon") == 0)
{
(void) FormatLocaleFile(svg_info->file,"polygon %s\n",
svg_info->vertices);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
if (LocaleCompare((const char *) name,"polyline") == 0)
{
(void) FormatLocaleFile(svg_info->file,"polyline %s\n",
svg_info->vertices);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
break;
}
case 'R':
case 'r':
{
if (LocaleCompare((const char *) name,"radialGradient") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop gradient\n");
break;
}
if (LocaleCompare((const char *) name,"rect") == 0)
{
if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
{
if ((fabs(svg_info->bounds.width-1.0) < MagickEpsilon) &&
(fabs(svg_info->bounds.height-1.0) < MagickEpsilon))
(void) FormatLocaleFile(svg_info->file,"point %g,%g\n",
svg_info->bounds.x,svg_info->bounds.y);
else
(void) FormatLocaleFile(svg_info->file,
"rectangle %g,%g %g,%g\n",svg_info->bounds.x,
svg_info->bounds.y,svg_info->bounds.x+svg_info->bounds.width,
svg_info->bounds.y+svg_info->bounds.height);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
if (svg_info->radius.x == 0.0)
svg_info->radius.x=svg_info->radius.y;
if (svg_info->radius.y == 0.0)
svg_info->radius.y=svg_info->radius.x;
(void) FormatLocaleFile(svg_info->file,
"roundRectangle %g,%g %g,%g %g,%g\n",
svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
svg_info->radius.x,svg_info->radius.y);
svg_info->radius.x=0.0;
svg_info->radius.y=0.0;
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
break;
}
case 'S':
case 's':
{
if (LocaleCompare((const char *) name,"stop") == 0)
{
(void) FormatLocaleFile(svg_info->file,"stop-color \"%s\" %s\n",
svg_info->stop_color,svg_info->offset == (char *) NULL ? "100%" :
svg_info->offset);
break;
}
if (LocaleCompare((char *) name,"style") == 0)
{
char
*keyword,
**tokens,
*value;
ssize_t
j;
size_t
number_tokens;
/*
Find style definitions in svg_info->text.
*/
tokens=SVGKeyValuePairs(context,'{','}',svg_info->text,
&number_tokens);
if (tokens == (char **) NULL)
break;
for (j=0; j < (ssize_t) (number_tokens-1); j+=2)
{
keyword=(char *) tokens[j];
value=(char *) tokens[j+1];
(void) FormatLocaleFile(svg_info->file,"push class \"%s\"\n",
*keyword == '.' ? keyword+1 : keyword);
SVGProcessStyleElement(context,name,value);
(void) FormatLocaleFile(svg_info->file,"pop class\n");
}
for (j=0; tokens[j] != (char *) NULL; j++)
tokens[j]=DestroyString(tokens[j]);
tokens=(char **) RelinquishMagickMemory(tokens);
break;
}
if (LocaleCompare((const char *) name,"svg") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
svg_info->svgDepth--;
break;
}
if (LocaleCompare((const char *) name,"symbol") == 0)
{
(void) FormatLocaleFile(svg_info->file,"pop symbol\n");
break;
}
break;
}
case 'T':
case 't':
{
if (LocaleCompare((const char *) name,"text") == 0)
{
if (*svg_info->text != '\0')
{
char
*text;
SVGStripString(MagickTrue,svg_info->text);
text=EscapeString(svg_info->text,'\"');
(void) FormatLocaleFile(svg_info->file,"text %g,%g \"%s\"\n",
svg_info->text_offset.x,svg_info->text_offset.y,text);
text=DestroyString(text);
*svg_info->text='\0';
}
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
if (LocaleCompare((const char *) name,"tspan") == 0)
{
if (*svg_info->text != '\0')
{
char
*text;
text=EscapeString(svg_info->text,'\"');
(void) FormatLocaleFile(svg_info->file,"text %g,%g \"%s\"\n",
svg_info->bounds.x,svg_info->bounds.y,text);
text=DestroyString(text);
*svg_info->text='\0';
}
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
if (LocaleCompare((const char *) name,"title") == 0)
{
if (*svg_info->text == '\0')
break;
(void) CloneString(&svg_info->title,svg_info->text);
*svg_info->text='\0';
break;
}
break;
}
case 'U':
case 'u':
{
if (LocaleCompare((char *) name,"use") == 0)
{
if ((svg_info->bounds.x != 0.0) || (svg_info->bounds.y != 0.0))
(void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
svg_info->bounds.x,svg_info->bounds.y);
(void) FormatLocaleFile(svg_info->file,"use \"url(%s)\"\n",
svg_info->url);
(void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
break;
}
break;
}
default:
break;
}
*svg_info->text='\0';
(void) memset(&svg_info->element,0,sizeof(svg_info->element));
(void) memset(&svg_info->segment,0,sizeof(svg_info->segment));
svg_info->n--;
}
static void SVGCharacters(void *context,const xmlChar *c,int length)
{
char
*text;
char
*p;
ssize_t
i;
SVGInfo
*svg_info;
/*
Receiving some characters from the parser.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.characters(%s,%.20g)",c,(double) length);
svg_info=(SVGInfo *) context;
text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
if (text == (char *) NULL)
return;
p=text;
for (i=0; i < (ssize_t) length; i++)
*p++=c[i];
*p='\0';
SVGStripString(MagickFalse,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)
{
SVGInfo
*svg_info;
xmlParserCtxtPtr
parser;
/*
Called when an entity reference is detected.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
name);
svg_info=(SVGInfo *) context;
parser=svg_info->parser;
if (parser == (xmlParserCtxtPtr) NULL)
return;
if (parser->node == (xmlNodePtr) NULL)
return;
if (*name == '#')
(void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
else
(void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
}
static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
{
SVGInfo
*svg_info;
/*
Receiving some ignorable whitespaces from the parser.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.ignorableWhitespace(%.30s, %d)",c,length);
svg_info=(SVGInfo *) context;
(void) svg_info;
}
static void SVGProcessingInstructions(void *context,const xmlChar *target,
const xmlChar *data)
{
SVGInfo
*svg_info;
/*
A processing instruction has been parsed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.processingInstruction(%s, %s)",target,data);
svg_info=(SVGInfo *) context;
(void) svg_info;
}
static void SVGComment(void *context,const xmlChar *value)
{
SVGInfo
*svg_info;
/*
A comment has been parsed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
value);
svg_info=(SVGInfo *) context;
if (svg_info->comment != (char *) NULL)
(void) ConcatenateString(&svg_info->comment,"\n");
(void) ConcatenateString(&svg_info->comment,(const char *) value);
}
static void SVGWarning(void *,const char *,...)
magick_attribute((__format__ (__printf__,2,3)));
static void SVGWarning(void *context,const char *format,...)
{
char
*message,
reason[MagickPathExtent];
SVGInfo
*svg_info;
va_list
operands;
/**
Display and format a warning messages, gives file, line, position and
extra parameters.
*/
va_start(operands,format);
svg_info=(SVGInfo *) context;
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
(void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
#if !defined(MAGICKCORE_HAVE_VSNPRINTF)
(void) vsprintf(reason,format,operands);
#else
(void) vsnprintf(reason,MagickPathExtent,format,operands);
#endif
message=GetExceptionMessage(errno);
(void) ThrowMagickException(svg_info->exception,GetMagickModule(),
DelegateWarning,reason,"`%s`",message);
message=DestroyString(message);
va_end(operands);
}
static void SVGError(void *context,const char *format,...)
{
char
*message,
reason[MagickPathExtent];
SVGInfo
*svg_info;
va_list
operands;
/*
Display and format a error formats, gives file, line, position and
extra parameters.
*/
va_start(operands,format);
svg_info=(SVGInfo *) context;
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
(void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
#if !defined(MAGICKCORE_HAVE_VSNPRINTF)
(void) vsprintf(reason,format,operands);
#else
(void) vsnprintf(reason,MagickPathExtent,format,operands);
#endif
message=GetExceptionMessage(errno);
(void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
reason,"`%s`",message);
message=DestroyString(message);
va_end(operands);
xmlStopParser(svg_info->parser);
}
static void SVGCDataBlock(void *context,const xmlChar *value,int length)
{
SVGInfo
*svg_info;
xmlNodePtr
child;
xmlParserCtxtPtr
parser;
/*
Called when a pcdata block has been parsed.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
value,length);
svg_info=(SVGInfo *) context;
parser=svg_info->parser;
child=xmlGetLastChild(parser->node);
if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
{
xmlTextConcat(child,value,length);
return;
}
child=xmlNewCDataBlock(parser->myDoc,value,length);
if (xmlAddChild(parser->node,child) == (xmlNodePtr) NULL)
xmlFreeNode(child);
}
static void SVGExternalSubset(void *context,const xmlChar *name,
const xmlChar *external_id,const xmlChar *system_id)
{
SVGInfo
*svg_info;
xmlParserCtxt
parser_context;
xmlParserCtxtPtr
parser;
xmlParserInputPtr
input;
/*
Does this document has an external subset?
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" SAX.externalSubset(%s, %s, %s)",name,
(external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
(system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
svg_info=(SVGInfo *) context;
parser=svg_info->parser;
if (((external_id == NULL) && (system_id == NULL)) ||
((parser->validate == 0) || (parser->wellFormed == 0) ||
(svg_info->document == 0)))
return;
input=SVGResolveEntity(context,external_id,system_id);
if (input == NULL)
return;
(void) xmlNewDtd(svg_info->document,name,external_id,system_id);
parser_context=(*parser);
parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
if (parser->inputTab == (xmlParserInputPtr *) NULL)
{
parser->errNo=XML_ERR_NO_MEMORY;
parser->input=parser_context.input;
parser->inputNr=parser_context.inputNr;
parser->inputMax=parser_context.inputMax;
parser->inputTab=parser_context.inputTab;
return;
}
parser->inputNr=0;
parser->inputMax=5;
parser->input=NULL;
xmlPushInput(parser,input);
(void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
if (input->filename == (char *) NULL)
input->filename=(char *) xmlStrdup(system_id);
input->line=1;
input->col=1;
input->base=parser->input->cur;
input->cur=parser->input->cur;
input->free=NULL;
xmlParseExternalSubset(parser,external_id,system_id);
while (parser->inputNr > 1)
(void) xmlPopInput(parser);
xmlFreeInputStream(parser->input);
xmlFree(parser->inputTab);
parser->input=parser_context.input;
parser->inputNr=parser_context.inputNr;
parser->inputMax=parser_context.inputMax;
parser->inputTab=parser_context.inputTab;
}
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
static Image *RenderMSVGImage(const ImageInfo *image_info,Image *image,