/src/imagemagick/coders/mvg.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % M M V V GGGG % |
7 | | % MM MM V V G % |
8 | | % M M M V V G GG % |
9 | | % M M V V G G % |
10 | | % M M V GGG % |
11 | | % % |
12 | | % % |
13 | | % Read/Write Magick Vector Graphics Metafiles. % |
14 | | % % |
15 | | % Software Design % |
16 | | % Cristy % |
17 | | % April 2000 % |
18 | | % % |
19 | | % % |
20 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
21 | | % dedicated to making software imaging solutions freely available. % |
22 | | % % |
23 | | % You may not use this file except in compliance with the License. You may % |
24 | | % obtain a copy of the License at % |
25 | | % % |
26 | | % https://imagemagick.org/license/ % |
27 | | % % |
28 | | % Unless required by applicable law or agreed to in writing, software % |
29 | | % distributed under the License is distributed on an "AS IS" BASIS, % |
30 | | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
31 | | % See the License for the specific language governing permissions and % |
32 | | % limitations under the License. % |
33 | | % % |
34 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
35 | | % |
36 | | % |
37 | | */ |
38 | | |
39 | | /* |
40 | | Include declarations. |
41 | | */ |
42 | | #include "MagickCore/studio.h" |
43 | | #include "MagickCore/artifact.h" |
44 | | #include "MagickCore/blob.h" |
45 | | #include "MagickCore/blob-private.h" |
46 | | #include "MagickCore/draw.h" |
47 | | #include "MagickCore/exception.h" |
48 | | #include "MagickCore/exception-private.h" |
49 | | #include "MagickCore/image.h" |
50 | | #include "MagickCore/image-private.h" |
51 | | #include "MagickCore/list.h" |
52 | | #include "MagickCore/magick.h" |
53 | | #include "MagickCore/memory_.h" |
54 | | #include "MagickCore/module.h" |
55 | | #include "MagickCore/property.h" |
56 | | #include "MagickCore/quantum-private.h" |
57 | | #include "MagickCore/static.h" |
58 | | #include "MagickCore/string_.h" |
59 | | #include "MagickCore/string-private.h" |
60 | | |
61 | | /* |
62 | | Forward declarations. |
63 | | */ |
64 | | static MagickBooleanType |
65 | | WriteMVGImage(const ImageInfo *,Image *,ExceptionInfo *); |
66 | | |
67 | | /* |
68 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
69 | | % % |
70 | | % % |
71 | | % % |
72 | | % I s M V G % |
73 | | % % |
74 | | % % |
75 | | % % |
76 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
77 | | % |
78 | | % IsMVG() returns MagickTrue if the image format type, identified by the |
79 | | % magick string, is MVG. |
80 | | % |
81 | | % The format of the IsMVG method is: |
82 | | % |
83 | | % MagickBooleanType IsMVG(const unsigned char *magick,const size_t length) |
84 | | % |
85 | | % A description of each parameter follows: |
86 | | % |
87 | | % o magick: compare image format pattern against these bytes. |
88 | | % |
89 | | % o length: Specifies the length of the magick string. |
90 | | % |
91 | | */ |
92 | | static MagickBooleanType IsMVG(const unsigned char *magick,const size_t length) |
93 | 0 | { |
94 | 0 | if (length < 20) |
95 | 0 | return(MagickFalse); |
96 | 0 | if (LocaleNCompare((const char *) magick,"push graphic-context",20) == 0) |
97 | 0 | return(MagickTrue); |
98 | 0 | return(MagickFalse); |
99 | 0 | } |
100 | | |
101 | | /* |
102 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
103 | | % % |
104 | | % % |
105 | | % % |
106 | | % R e a d M V G I m a g e % |
107 | | % % |
108 | | % % |
109 | | % % |
110 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
111 | | % |
112 | | % ReadMVGImage creates a gradient image and initializes it to |
113 | | % the X server color range as specified by the filename. It allocates the |
114 | | % memory necessary for the new Image structure and returns a pointer to the |
115 | | % new image. |
116 | | % |
117 | | % The format of the ReadMVGImage method is: |
118 | | % |
119 | | % Image *ReadMVGImage(const ImageInfo *image_info,ExceptionInfo *exception) |
120 | | % |
121 | | % A description of each parameter follows: |
122 | | % |
123 | | % o image_info: the image info. |
124 | | % |
125 | | % o exception: return any errors or warnings in this structure. |
126 | | % |
127 | | */ |
128 | | static Image *ReadMVGImage(const ImageInfo *image_info,ExceptionInfo *exception) |
129 | 2.92k | { |
130 | 2.92k | DrawInfo |
131 | 2.92k | *draw_info; |
132 | | |
133 | 2.92k | Image |
134 | 2.92k | *image; |
135 | | |
136 | 2.92k | MagickBooleanType |
137 | 2.92k | status; |
138 | | |
139 | | /* |
140 | | Open image. |
141 | | */ |
142 | 2.92k | assert(image_info != (const ImageInfo *) NULL); |
143 | 2.92k | assert(image_info->signature == MagickCoreSignature); |
144 | 2.92k | assert(exception != (ExceptionInfo *) NULL); |
145 | 2.92k | assert(exception->signature == MagickCoreSignature); |
146 | 2.92k | if (IsEventLogging() != MagickFalse) |
147 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
148 | 0 | image_info->filename); |
149 | 2.92k | image=AcquireImage(image_info,exception); |
150 | 2.92k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
151 | 2.92k | if (status == MagickFalse) |
152 | 0 | { |
153 | 0 | image=DestroyImageList(image); |
154 | 0 | return((Image *) NULL); |
155 | 0 | } |
156 | 2.92k | if ((image->columns == 0) || (image->rows == 0)) |
157 | 2.92k | { |
158 | 2.92k | char |
159 | 2.92k | primitive[MagickPathExtent]; |
160 | | |
161 | 2.92k | char |
162 | 2.92k | *p; |
163 | | |
164 | 2.92k | SegmentInfo |
165 | 2.92k | bounds; |
166 | | |
167 | | /* |
168 | | Determine size of image canvas. |
169 | | */ |
170 | 2.92k | (void) memset(&bounds,0,sizeof(bounds)); |
171 | 13.9k | while (ReadBlobString(image,primitive) != (char *) NULL) |
172 | 13.9k | { |
173 | 13.9k | int |
174 | 13.9k | count; |
175 | | |
176 | 20.3k | for (p=primitive; (*p == ' ') || (*p == '\t'); p++) ; |
177 | 13.9k | count=MagickSscanf(p,"viewbox %lf %lf %lf %lf",&bounds.x1,&bounds.y1, |
178 | 13.9k | &bounds.x2,&bounds.y2); |
179 | 13.9k | if (count != 4) |
180 | 11.0k | continue; |
181 | 2.90k | image->columns=CastDoubleToSizeT(floor((bounds.x2-bounds.x1)+0.5)); |
182 | 2.90k | image->rows=CastDoubleToSizeT(floor((bounds.y2-bounds.y1)+0.5)); |
183 | 2.90k | break; |
184 | 13.9k | } |
185 | 2.92k | } |
186 | 2.92k | if ((image->columns == 0) || (image->rows == 0)) |
187 | 2.90k | ThrowReaderException(OptionError,"MustSpecifyImageSize"); |
188 | 2.90k | draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); |
189 | 2.90k | if (draw_info->density != (char *) NULL) |
190 | 0 | draw_info->density=DestroyString(draw_info->density); |
191 | 2.90k | draw_info->affine.sx=image->resolution.x == 0.0 ? 1.0 : image->resolution.x/ |
192 | 0 | 96.0; |
193 | 2.90k | draw_info->affine.sy=image->resolution.y == 0.0 ? 1.0 : image->resolution.y/ |
194 | 0 | 96.0; |
195 | 2.90k | image->columns=CastDoubleToSizeT(draw_info->affine.sx*image->columns); |
196 | 2.90k | image->rows=CastDoubleToSizeT(draw_info->affine.sy*image->rows); |
197 | 2.90k | status=SetImageExtent(image,image->columns,image->rows,exception); |
198 | 2.90k | if (status == MagickFalse) |
199 | 1 | { |
200 | 1 | draw_info=DestroyDrawInfo(draw_info); |
201 | 1 | return(DestroyImageList(image)); |
202 | 1 | } |
203 | 2.90k | if (SetImageBackgroundColor(image,exception) == MagickFalse) |
204 | 0 | { |
205 | 0 | draw_info=DestroyDrawInfo(draw_info); |
206 | 0 | return(DestroyImageList(image)); |
207 | 0 | } |
208 | | /* |
209 | | Render drawing. |
210 | | */ |
211 | 2.90k | if (GetBlobStreamData(image) == (unsigned char *) NULL) |
212 | 0 | draw_info->primitive=FileToString(image->filename,~0UL,exception); |
213 | 2.90k | else |
214 | 2.90k | { |
215 | 2.90k | MagickSizeType |
216 | 2.90k | length; |
217 | | |
218 | 2.90k | length=GetBlobSize(image); |
219 | 2.90k | if (length == (MagickSizeType) ((size_t) length)) |
220 | 2.90k | { |
221 | 2.90k | draw_info->primitive=(char *) AcquireQuantumMemory(1,(size_t) length+1); |
222 | 2.90k | if (draw_info->primitive != (char *) NULL) |
223 | 2.90k | { |
224 | 2.90k | memcpy(draw_info->primitive,GetBlobStreamData(image),(size_t) |
225 | 2.90k | length); |
226 | 2.90k | draw_info->primitive[length]='\0'; |
227 | 2.90k | } |
228 | 2.90k | } |
229 | 2.90k | } |
230 | 2.90k | if (draw_info->primitive == (char *) NULL) |
231 | 0 | { |
232 | 0 | draw_info=DestroyDrawInfo(draw_info); |
233 | 0 | return(DestroyImageList(image)); |
234 | 0 | } |
235 | 2.90k | if (*draw_info->primitive == '@') |
236 | 0 | { |
237 | 0 | draw_info=DestroyDrawInfo(draw_info); |
238 | 0 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
239 | 0 | } |
240 | 2.90k | (void) DrawImage(image,draw_info,exception); |
241 | 2.90k | (void) SetImageArtifact(image,"mvg:vector-graphics",draw_info->primitive); |
242 | 2.90k | draw_info=DestroyDrawInfo(draw_info); |
243 | 2.90k | if (CloseBlob(image) == MagickFalse) |
244 | 0 | status=MagickFalse; |
245 | 2.90k | if (status == MagickFalse) |
246 | 0 | return(DestroyImageList(image)); |
247 | 2.90k | return(GetFirstImageInList(image)); |
248 | 2.90k | } |
249 | | |
250 | | /* |
251 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
252 | | % % |
253 | | % % |
254 | | % % |
255 | | % R e g i s t e r M V G I m a g e % |
256 | | % % |
257 | | % % |
258 | | % % |
259 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
260 | | % |
261 | | % RegisterMVGImage() adds properties for the MVG image format |
262 | | % to the list of supported formats. The properties include the image format |
263 | | % tag, a method to read and/or write the format, whether the format |
264 | | % supports the saving of more than one frame to the same file or blob, |
265 | | % whether the format supports native in-memory I/O, and a brief |
266 | | % description of the format. |
267 | | % |
268 | | % The format of the RegisterMVGImage method is: |
269 | | % |
270 | | % size_t RegisterMVGImage(void) |
271 | | % |
272 | | */ |
273 | | ModuleExport size_t RegisterMVGImage(void) |
274 | 8 | { |
275 | 8 | MagickInfo |
276 | 8 | *entry; |
277 | | |
278 | 8 | entry=AcquireMagickInfo("MVG","MVG","Magick Vector Graphics"); |
279 | 8 | entry->decoder=(DecodeImageHandler *) ReadMVGImage; |
280 | 8 | entry->encoder=(EncodeImageHandler *) WriteMVGImage; |
281 | 8 | entry->magick=(IsImageFormatHandler *) IsMVG; |
282 | 8 | entry->format_type=ImplicitFormatType; |
283 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
284 | 8 | entry->flags^=CoderAdjoinFlag; |
285 | 8 | (void) RegisterMagickInfo(entry); |
286 | 8 | return(MagickImageCoderSignature); |
287 | 8 | } |
288 | | |
289 | | /* |
290 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
291 | | % % |
292 | | % % |
293 | | % % |
294 | | % U n r e g i s t e r M V G I m a g e % |
295 | | % % |
296 | | % % |
297 | | % % |
298 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
299 | | % |
300 | | % UnregisterMVGImage() removes format registrations made by the |
301 | | % MVG module from the list of supported formats. |
302 | | % |
303 | | % The format of the UnregisterMVGImage method is: |
304 | | % |
305 | | % UnregisterMVGImage(void) |
306 | | % |
307 | | */ |
308 | | ModuleExport void UnregisterMVGImage(void) |
309 | 0 | { |
310 | 0 | (void) UnregisterMagickInfo("MVG"); |
311 | 0 | } |
312 | | |
313 | | /* |
314 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
315 | | % % |
316 | | % % |
317 | | % % |
318 | | % W r i t e M V G I m a g e % |
319 | | % % |
320 | | % % |
321 | | % % |
322 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
323 | | % |
324 | | % WriteMVGImage() writes an image to a file in MVG image format. |
325 | | % |
326 | | % The format of the WriteMVGImage method is: |
327 | | % |
328 | | % MagickBooleanType WriteMVGImage(const ImageInfo *image_info, |
329 | | % Image *image,ExceptionInfo *exception) |
330 | | % |
331 | | % A description of each parameter follows. |
332 | | % |
333 | | % o image_info: the image info. |
334 | | % |
335 | | % o image: The image. |
336 | | % |
337 | | % o exception: return any errors or warnings in this structure. |
338 | | % |
339 | | */ |
340 | | static MagickBooleanType WriteMVGImage(const ImageInfo *image_info,Image *image, |
341 | | ExceptionInfo *exception) |
342 | 60 | { |
343 | 60 | const char |
344 | 60 | *value; |
345 | | |
346 | 60 | MagickBooleanType |
347 | 60 | status; |
348 | | |
349 | | /* |
350 | | Open output image file. |
351 | | */ |
352 | 60 | assert(image_info != (const ImageInfo *) NULL); |
353 | 60 | assert(image_info->signature == MagickCoreSignature); |
354 | 60 | assert(image != (Image *) NULL); |
355 | 60 | assert(image->signature == MagickCoreSignature); |
356 | 60 | if (IsEventLogging() != MagickFalse) |
357 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
358 | 60 | value=GetImageArtifact(image,"mvg:vector-graphics"); |
359 | 60 | if (value == (const char *) NULL) |
360 | 60 | ThrowWriterException(OptionError,"NoImageVectorGraphics"); |
361 | 60 | status=OpenBlob(image_info,image,WriteBlobMode,exception); |
362 | 60 | if (status == MagickFalse) |
363 | 0 | return(status); |
364 | 60 | (void) WriteBlob(image,strlen(value),(const unsigned char *) value); |
365 | 60 | if (CloseBlob(image) == MagickFalse) |
366 | 0 | status=MagickFalse; |
367 | 60 | return(status); |
368 | 60 | } |