/src/imagemagick/coders/html.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % H H TTTTT M M L % |
7 | | % H H T MM MM L % |
8 | | % HHHHH T M M M L % |
9 | | % H H T M M L % |
10 | | % H H T M M LLLLL % |
11 | | % % |
12 | | % % |
13 | | % Write A Client-Side Image Map Using % |
14 | | % Image Montage & Directory Information. % |
15 | | % % |
16 | | % Software Design % |
17 | | % Cristy % |
18 | | % July 1992 % |
19 | | % % |
20 | | % % |
21 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
22 | | % dedicated to making software imaging solutions freely available. % |
23 | | % % |
24 | | % You may not use this file except in compliance with the License. You may % |
25 | | % obtain a copy of the License at % |
26 | | % % |
27 | | % https://imagemagick.org/license/ % |
28 | | % % |
29 | | % Unless required by applicable law or agreed to in writing, software % |
30 | | % distributed under the License is distributed on an "AS IS" BASIS, % |
31 | | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
32 | | % See the License for the specific language governing permissions and % |
33 | | % limitations under the License. % |
34 | | % % |
35 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
36 | | % |
37 | | % |
38 | | */ |
39 | | |
40 | | /* |
41 | | Include declarations. |
42 | | */ |
43 | | #include "MagickCore/studio.h" |
44 | | #include "MagickCore/blob.h" |
45 | | #include "MagickCore/blob-private.h" |
46 | | #include "MagickCore/color-private.h" |
47 | | #include "MagickCore/colorspace.h" |
48 | | #include "MagickCore/colorspace-private.h" |
49 | | #include "MagickCore/constitute.h" |
50 | | #include "MagickCore/exception.h" |
51 | | #include "MagickCore/exception-private.h" |
52 | | #include "MagickCore/geometry.h" |
53 | | #include "MagickCore/list.h" |
54 | | #include "MagickCore/magick.h" |
55 | | #include "MagickCore/memory_.h" |
56 | | #include "MagickCore/paint.h" |
57 | | #include "MagickCore/property.h" |
58 | | #include "MagickCore/quantum-private.h" |
59 | | #include "MagickCore/static.h" |
60 | | #include "MagickCore/string_.h" |
61 | | #include "MagickCore/module.h" |
62 | | #include "MagickCore/utility.h" |
63 | | |
64 | | /* |
65 | | Forward declarations. |
66 | | */ |
67 | | static MagickBooleanType |
68 | | WriteHTMLImage(const ImageInfo *,Image *,ExceptionInfo *); |
69 | | |
70 | | /* |
71 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
72 | | % % |
73 | | % % |
74 | | % % |
75 | | % I s H T M L % |
76 | | % % |
77 | | % % |
78 | | % % |
79 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
80 | | % |
81 | | % IsHTML() returns MagickTrue if the image format type, identified by the |
82 | | % magick string, is HTML. |
83 | | % |
84 | | % The format of the IsHTML method is: |
85 | | % |
86 | | % MagickBooleanType IsHTML(const unsigned char *magick,const size_t length) |
87 | | % |
88 | | % A description of each parameter follows: |
89 | | % |
90 | | % o magick: compare image format pattern against these bytes. |
91 | | % |
92 | | % o length: Specifies the length of the magick string. |
93 | | % |
94 | | */ |
95 | | static MagickBooleanType IsHTML(const unsigned char *magick,const size_t length) |
96 | 0 | { |
97 | 0 | if (length < 6) |
98 | 0 | return(MagickFalse); |
99 | 0 | if (LocaleNCompare((char *) magick+1,"html",5) == 0) |
100 | 0 | return(MagickTrue); |
101 | 0 | return(MagickFalse); |
102 | 0 | } |
103 | | |
104 | | /* |
105 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
106 | | % % |
107 | | % % |
108 | | % % |
109 | | % R e g i s t e r H T M L I m a g e % |
110 | | % % |
111 | | % % |
112 | | % % |
113 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
114 | | % |
115 | | % RegisterHTMLImage() adds properties for the HTML image format to |
116 | | % the list of supported formats. The properties include the image format |
117 | | % tag, a method to read and/or write the format, whether the format |
118 | | % supports the saving of more than one frame to the same file or blob, |
119 | | % whether the format supports native in-memory I/O, and a brief |
120 | | % description of the format. |
121 | | % |
122 | | % The format of the RegisterHTMLImage method is: |
123 | | % |
124 | | % size_t RegisterHTMLImage(void) |
125 | | % |
126 | | */ |
127 | | ModuleExport size_t RegisterHTMLImage(void) |
128 | 7 | { |
129 | 7 | MagickInfo |
130 | 7 | *entry; |
131 | | |
132 | 7 | entry=AcquireMagickInfo("HTML","HTM", |
133 | 7 | "Hypertext Markup Language and a client-side image map"); |
134 | 7 | entry->encoder=(EncodeImageHandler *) WriteHTMLImage; |
135 | 7 | entry->magick=(IsImageFormatHandler *) IsHTML; |
136 | 7 | entry->flags^=CoderAdjoinFlag; |
137 | 7 | (void) RegisterMagickInfo(entry); |
138 | 7 | entry=AcquireMagickInfo("HTML","HTML", |
139 | 7 | "Hypertext Markup Language and a client-side image map"); |
140 | 7 | entry->encoder=(EncodeImageHandler *) WriteHTMLImage; |
141 | 7 | entry->magick=(IsImageFormatHandler *) IsHTML; |
142 | 7 | entry->flags^=CoderAdjoinFlag; |
143 | 7 | (void) RegisterMagickInfo(entry); |
144 | 7 | entry=AcquireMagickInfo("HTML","SHTML", |
145 | 7 | "Hypertext Markup Language and a client-side image map"); |
146 | 7 | entry->encoder=(EncodeImageHandler *) WriteHTMLImage; |
147 | 7 | entry->magick=(IsImageFormatHandler *) IsHTML; |
148 | 7 | entry->flags^=CoderAdjoinFlag; |
149 | 7 | (void) RegisterMagickInfo(entry); |
150 | 7 | return(MagickImageCoderSignature); |
151 | 7 | } |
152 | | |
153 | | /* |
154 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
155 | | % % |
156 | | % % |
157 | | % % |
158 | | % U n r e g i s t e r H T M L I m a g e % |
159 | | % % |
160 | | % % |
161 | | % % |
162 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
163 | | % |
164 | | % UnregisterHTMLImage() removes format registrations made by the |
165 | | % HTML module from the list of supported formats. |
166 | | % |
167 | | % The format of the UnregisterHTMLImage method is: |
168 | | % |
169 | | % UnregisterHTMLImage(void) |
170 | | % |
171 | | */ |
172 | | ModuleExport void UnregisterHTMLImage(void) |
173 | 0 | { |
174 | 0 | (void) UnregisterMagickInfo("HTM"); |
175 | 0 | (void) UnregisterMagickInfo("HTML"); |
176 | 0 | (void) UnregisterMagickInfo("SHTML"); |
177 | 0 | } |
178 | | |
179 | | /* |
180 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
181 | | % % |
182 | | % % |
183 | | % % |
184 | | % W r i t e H T M L I m a g e % |
185 | | % % |
186 | | % % |
187 | | % % |
188 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
189 | | % |
190 | | % WriteHTMLImage() writes an image in the HTML encoded image format. |
191 | | % |
192 | | % The format of the WriteHTMLImage method is: |
193 | | % |
194 | | % MagickBooleanType WriteHTMLImage(const ImageInfo *image_info, |
195 | | % Image *image,ExceptionInfo *exception) |
196 | | % |
197 | | % A description of each parameter follows. |
198 | | % |
199 | | % o image_info: the image info. |
200 | | % |
201 | | % o image: The image. |
202 | | % |
203 | | % o exception: return any errors or warnings in this structure. |
204 | | % |
205 | | */ |
206 | | |
207 | | static ssize_t WriteURLComponent(Image *image,const int c) |
208 | 0 | { |
209 | 0 | char |
210 | 0 | encoding[MagickPathExtent], |
211 | 0 | html5; |
212 | | |
213 | 0 | html5=isalnum(c) != 0 || (c == '-') || (c == '_') || (c == '.') || |
214 | 0 | (c == '!') || (c == '~') || (c == '*') || (c == '\'') || (c == '(') || |
215 | 0 | (c == ')') ? (char) c : 0; |
216 | 0 | if (html5 != 0) |
217 | 0 | (void) FormatLocaleString(encoding,MagickPathExtent,"%c",html5); |
218 | 0 | else |
219 | 0 | (void) FormatLocaleString(encoding,MagickPathExtent,"%%%02X",c); |
220 | 0 | return(WriteBlobString(image,encoding)); |
221 | 0 | } |
222 | | |
223 | | static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info, |
224 | | Image *image,ExceptionInfo *exception) |
225 | 0 | { |
226 | 0 | char |
227 | 0 | basename[MagickPathExtent], |
228 | 0 | buffer[MagickPathExtent], |
229 | 0 | filename[MagickPathExtent], |
230 | 0 | mapname[MagickPathExtent], |
231 | 0 | url[MagickPathExtent]; |
232 | |
|
233 | 0 | Image |
234 | 0 | *next; |
235 | |
|
236 | 0 | ImageInfo |
237 | 0 | *write_info; |
238 | |
|
239 | 0 | MagickBooleanType |
240 | 0 | status; |
241 | |
|
242 | 0 | RectangleInfo |
243 | 0 | geometry; |
244 | |
|
245 | 0 | char |
246 | 0 | *p; |
247 | | |
248 | | /* |
249 | | Open image. |
250 | | */ |
251 | 0 | assert(image_info != (const ImageInfo *) NULL); |
252 | 0 | assert(image_info->signature == MagickCoreSignature); |
253 | 0 | assert(image != (Image *) NULL); |
254 | 0 | assert(image->signature == MagickCoreSignature); |
255 | 0 | assert(exception != (ExceptionInfo *) NULL); |
256 | 0 | assert(exception->signature == MagickCoreSignature); |
257 | 0 | if (IsEventLogging() != MagickFalse) |
258 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
259 | 0 | image_info->filename); |
260 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
261 | 0 | if (status == MagickFalse) |
262 | 0 | return(status); |
263 | 0 | (void) CloseBlob(image); |
264 | 0 | if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) |
265 | 0 | (void) TransformImageColorspace(image,sRGBColorspace,exception); |
266 | 0 | *url='\0'; |
267 | 0 | if ((LocaleCompare(image_info->magick,"FTP") == 0) || |
268 | 0 | (LocaleCompare(image_info->magick,"HTTP") == 0)) |
269 | 0 | { |
270 | | /* |
271 | | Extract URL base from filename. |
272 | | */ |
273 | 0 | p=strrchr(image->filename,'/'); |
274 | 0 | if (p != (char *) NULL) |
275 | 0 | { |
276 | 0 | p++; |
277 | 0 | (void) CopyMagickString(url,image_info->magick,MagickPathExtent); |
278 | 0 | (void) ConcatenateMagickString(url,":",MagickPathExtent); |
279 | 0 | url[strlen(url)+p-image->filename]='\0'; |
280 | 0 | (void) ConcatenateMagickString(url,image->filename,(size_t) |
281 | 0 | (p-image->filename+2)); |
282 | 0 | (void) CopyMagickString(image->filename,p,MagickPathExtent); |
283 | 0 | } |
284 | 0 | } |
285 | | /* |
286 | | Refer to image map file. |
287 | | */ |
288 | 0 | (void) CopyMagickString(filename,image->filename,MagickPathExtent); |
289 | 0 | AppendImageFormat("map",filename); |
290 | 0 | GetPathComponent(filename,BasePath,basename); |
291 | 0 | (void) CopyMagickString(mapname,basename,MagickPathExtent); |
292 | 0 | (void) CopyMagickString(image->filename,image_info->filename, |
293 | 0 | MagickPathExtent); |
294 | 0 | (void) CopyMagickString(filename,image->filename,MagickPathExtent); |
295 | 0 | write_info=CloneImageInfo(image_info); |
296 | 0 | *write_info->magick='\0'; |
297 | 0 | write_info->adjoin=MagickTrue; |
298 | 0 | status=MagickTrue; |
299 | 0 | if (LocaleCompare(image_info->magick,"SHTML") != 0) |
300 | 0 | { |
301 | 0 | const char |
302 | 0 | *value; |
303 | | |
304 | | /* |
305 | | Open output image file. |
306 | | */ |
307 | 0 | assert(exception != (ExceptionInfo *) NULL); |
308 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
309 | 0 | if (status == MagickFalse) |
310 | 0 | return(status); |
311 | | /* |
312 | | Write the HTML image file. |
313 | | */ |
314 | 0 | (void) WriteBlobString(image,"<?xml version=\"1.0\" " |
315 | 0 | "encoding=\"UTF-8\"?>\n"); |
316 | 0 | (void) WriteBlobString(image,"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML " |
317 | 0 | "1.0 Strict//EN\" " |
318 | 0 | "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"); |
319 | 0 | (void) WriteBlobString(image,"<html>\n"); |
320 | 0 | (void) WriteBlobString(image,"<head>\n"); |
321 | 0 | value=GetImageProperty(image,"label",exception); |
322 | 0 | if (value != (const char *) NULL) |
323 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent,"<title>%s</title>\n", |
324 | 0 | value); |
325 | 0 | else |
326 | 0 | { |
327 | 0 | GetPathComponent(filename,BasePath,basename); |
328 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent, |
329 | 0 | "<title>%s</title>\n",basename); |
330 | 0 | } |
331 | 0 | (void) WriteBlobString(image,buffer); |
332 | 0 | (void) WriteBlobString(image,"</head>\n"); |
333 | 0 | (void) WriteBlobString(image,"<body style=\"text-align: center;\">\n"); |
334 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent,"<h1>%s</h1>\n", |
335 | 0 | image->filename); |
336 | 0 | (void) WriteBlobString(image,buffer); |
337 | 0 | (void) WriteBlobString(image,"<div>\n"); |
338 | 0 | (void) CopyMagickString(filename,image->filename,MagickPathExtent); |
339 | 0 | AppendImageFormat("png",filename); |
340 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent,"<img usemap=\"#%s\" " |
341 | 0 | "src=\"%s\" style=\"border: 0;\" alt=\"Image map\" />\n",mapname, |
342 | 0 | filename); |
343 | 0 | (void) WriteBlobString(image,buffer); |
344 | | /* |
345 | | Determine the size and location of each image tile. |
346 | | */ |
347 | 0 | SetGeometry(image,&geometry); |
348 | 0 | if (image->montage != (char *) NULL) |
349 | 0 | (void) ParseAbsoluteGeometry(image->montage,&geometry); |
350 | | /* |
351 | | Write an image map. |
352 | | */ |
353 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent, |
354 | 0 | "<map id=\"%s\" name=\"%s\">\n",mapname,mapname); |
355 | 0 | (void) WriteBlobString(image,buffer); |
356 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent," <area href=\"%s", |
357 | 0 | url); |
358 | 0 | (void) WriteBlobString(image,buffer); |
359 | 0 | if (image->directory == (char *) NULL) |
360 | 0 | { |
361 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent, |
362 | 0 | "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n", |
363 | 0 | image->filename,(double) geometry.width-1,(double) geometry.height- |
364 | 0 | 1); |
365 | 0 | (void) WriteBlobString(image,buffer); |
366 | 0 | } |
367 | 0 | else |
368 | 0 | for (p=image->directory; *p != '\0'; p++) |
369 | 0 | if (*p != '\xff') |
370 | 0 | (void) WriteURLComponent(image,(unsigned char) *p); |
371 | 0 | else |
372 | 0 | { |
373 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent,"\" shape=" |
374 | 0 | "\"rect\" coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n", |
375 | 0 | (double) geometry.x,(double) geometry.y,(double) (geometry.x+ |
376 | 0 | (ssize_t) geometry.width-1),(double) (geometry.y+(ssize_t) |
377 | 0 | geometry.height-1)); |
378 | 0 | (void) WriteBlobString(image,buffer); |
379 | 0 | if (*(p+1) != '\0') |
380 | 0 | { |
381 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent, |
382 | 0 | " <area href=%s\"",url); |
383 | 0 | (void) WriteBlobString(image,buffer); |
384 | 0 | } |
385 | 0 | geometry.x+=(ssize_t) geometry.width; |
386 | 0 | if ((geometry.x+4) >= (ssize_t) image->columns) |
387 | 0 | { |
388 | 0 | geometry.x=0; |
389 | 0 | geometry.y+=(ssize_t) geometry.height; |
390 | 0 | } |
391 | 0 | } |
392 | 0 | (void) WriteBlobString(image,"</map>\n"); |
393 | 0 | (void) CopyMagickString(filename,image->filename,MagickPathExtent); |
394 | 0 | (void) WriteBlobString(image,"</div>\n"); |
395 | 0 | (void) WriteBlobString(image,"</body>\n"); |
396 | 0 | (void) WriteBlobString(image,"</html>\n"); |
397 | 0 | (void) CloseBlob(image); |
398 | | /* |
399 | | Write the image as PNG. |
400 | | */ |
401 | 0 | (void) CopyMagickString(image->filename,filename,MagickPathExtent); |
402 | 0 | AppendImageFormat("png",image->filename); |
403 | 0 | next=GetNextImageInList(image); |
404 | 0 | image->next=NewImageList(); |
405 | 0 | (void) CopyMagickString(image->magick,"PNG",MagickPathExtent); |
406 | 0 | (void) WriteImage(write_info,image,exception); |
407 | 0 | image->next=next; |
408 | | /* |
409 | | Determine image map filename. |
410 | | */ |
411 | 0 | GetPathComponent(image->filename,BasePath,filename); |
412 | 0 | (void) ConcatenateMagickString(filename,"_map.shtml",MagickPathExtent); |
413 | 0 | (void) CopyMagickString(image->filename,filename,MagickPathExtent); |
414 | 0 | } |
415 | | /* |
416 | | Open image map. |
417 | | */ |
418 | 0 | status=OpenBlob(write_info,image,WriteBinaryBlobMode,exception); |
419 | 0 | if (status == MagickFalse) |
420 | 0 | return(status); |
421 | 0 | write_info=DestroyImageInfo(write_info); |
422 | | /* |
423 | | Determine the size and location of each image tile. |
424 | | */ |
425 | 0 | SetGeometry(image,&geometry); |
426 | 0 | if (image->montage != (char *) NULL) |
427 | 0 | (void) ParseAbsoluteGeometry(image->montage,&geometry); |
428 | | /* |
429 | | Write an image map. |
430 | | */ |
431 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent, |
432 | 0 | "<map id=\"%s\" name=\"%s\">\n",mapname,mapname); |
433 | 0 | (void) WriteBlobString(image,buffer); |
434 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent," <area href=\"%s",url); |
435 | 0 | (void) WriteBlobString(image,buffer); |
436 | 0 | if (image->directory == (char *) NULL) |
437 | 0 | { |
438 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent, |
439 | 0 | "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n", |
440 | 0 | image->filename,(double) geometry.width-1,(double) geometry.height-1); |
441 | 0 | (void) WriteBlobString(image,buffer); |
442 | 0 | } |
443 | 0 | else |
444 | 0 | for (p=image->directory; *p != '\0'; p++) |
445 | 0 | if (*p != '\xff') |
446 | 0 | (void) WriteURLComponent(image,(unsigned char) *p); |
447 | 0 | else |
448 | 0 | { |
449 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent,"\" shape=\"rect\"" |
450 | 0 | " coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n", |
451 | 0 | (double) geometry.x,(double) geometry.y,geometry.x+(double) |
452 | 0 | geometry.width-1,geometry.y+(double) geometry.height-1); |
453 | 0 | (void) WriteBlobString(image,buffer); |
454 | 0 | if (*(p+1) != '\0') |
455 | 0 | { |
456 | 0 | (void) FormatLocaleString(buffer,MagickPathExtent, |
457 | 0 | " <area href=%s\"",url); |
458 | 0 | (void) WriteBlobString(image,buffer); |
459 | 0 | } |
460 | 0 | geometry.x+=(ssize_t) geometry.width; |
461 | 0 | if ((geometry.x+4) >= (ssize_t) image->columns) |
462 | 0 | { |
463 | 0 | geometry.x=0; |
464 | 0 | geometry.y+=(ssize_t) geometry.height; |
465 | 0 | } |
466 | 0 | } |
467 | 0 | (void) WriteBlobString(image,"</map>\n"); |
468 | 0 | (void) CloseBlob(image); |
469 | 0 | (void) CopyMagickString(image->filename,filename,MagickPathExtent); |
470 | 0 | return(status); |
471 | 0 | } |