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-2021 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/script/license.php %
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 */
IsHTML(const unsigned char * magick,const size_t length)95 static MagickBooleanType IsHTML(const unsigned char *magick,const size_t length)
96 {
97 if (length < 6)
98 return(MagickFalse);
99 if (LocaleNCompare((char *) magick+1,"html",5) == 0)
100 return(MagickTrue);
101 return(MagickFalse);
102 }
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 */
RegisterHTMLImage(void)127 ModuleExport size_t RegisterHTMLImage(void)
128 {
129 MagickInfo
130 *entry;
131
132 entry=AcquireMagickInfo("HTML","HTM",
133 "Hypertext Markup Language and a client-side image map");
134 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
135 entry->magick=(IsImageFormatHandler *) IsHTML;
136 entry->flags^=CoderAdjoinFlag;
137 (void) RegisterMagickInfo(entry);
138 entry=AcquireMagickInfo("HTML","HTML",
139 "Hypertext Markup Language and a client-side image map");
140 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
141 entry->magick=(IsImageFormatHandler *) IsHTML;
142 entry->flags^=CoderAdjoinFlag;
143 (void) RegisterMagickInfo(entry);
144 entry=AcquireMagickInfo("HTML","SHTML",
145 "Hypertext Markup Language and a client-side image map");
146 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
147 entry->magick=(IsImageFormatHandler *) IsHTML;
148 entry->flags^=CoderAdjoinFlag;
149 (void) RegisterMagickInfo(entry);
150 return(MagickImageCoderSignature);
151 }
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 */
UnregisterHTMLImage(void)172 ModuleExport void UnregisterHTMLImage(void)
173 {
174 (void) UnregisterMagickInfo("HTM");
175 (void) UnregisterMagickInfo("HTML");
176 (void) UnregisterMagickInfo("SHTML");
177 }
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 */
WriteHTMLImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)206 static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
207 Image *image,ExceptionInfo *exception)
208 {
209 char
210 basename[MagickPathExtent],
211 buffer[MagickPathExtent],
212 filename[MagickPathExtent],
213 mapname[MagickPathExtent],
214 url[MagickPathExtent];
215
216 Image
217 *next;
218
219 ImageInfo
220 *write_info;
221
222 MagickBooleanType
223 status;
224
225 RectangleInfo
226 geometry;
227
228 char
229 *p;
230
231 /*
232 Open image.
233 */
234 assert(image_info != (const ImageInfo *) NULL);
235 assert(image_info->signature == MagickCoreSignature);
236 assert(image != (Image *) NULL);
237 assert(image->signature == MagickCoreSignature);
238 if (image->debug != MagickFalse)
239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
240 image_info->filename);
241 assert(exception != (ExceptionInfo *) NULL);
242 assert(exception->signature == MagickCoreSignature);
243 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
244 if (status == MagickFalse)
245 return(status);
246 (void) CloseBlob(image);
247 (void) TransformImageColorspace(image,sRGBColorspace,exception);
248 *url='\0';
249 if ((LocaleCompare(image_info->magick,"FTP") == 0) ||
250 (LocaleCompare(image_info->magick,"HTTP") == 0))
251 {
252 /*
253 Extract URL base from filename.
254 */
255 p=strrchr(image->filename,'/');
256 if (p != (char *) NULL)
257 {
258 p++;
259 (void) CopyMagickString(url,image_info->magick,MagickPathExtent);
260 (void) ConcatenateMagickString(url,":",MagickPathExtent);
261 url[strlen(url)+p-image->filename]='\0';
262 (void) ConcatenateMagickString(url,image->filename,
263 p-image->filename+2);
264 (void) CopyMagickString(image->filename,p,MagickPathExtent);
265 }
266 }
267 /*
268 Refer to image map file.
269 */
270 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
271 AppendImageFormat("map",filename);
272 GetPathComponent(filename,BasePath,basename);
273 (void) CopyMagickString(mapname,basename,MagickPathExtent);
274 (void) CopyMagickString(image->filename,image_info->filename,
275 MagickPathExtent);
276 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
277 write_info=CloneImageInfo(image_info);
278 *write_info->magick='\0';
279 write_info->adjoin=MagickTrue;
280 status=MagickTrue;
281 if (LocaleCompare(image_info->magick,"SHTML") != 0)
282 {
283 const char
284 *value;
285
286 /*
287 Open output image file.
288 */
289 assert(exception != (ExceptionInfo *) NULL);
290 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
291 if (status == MagickFalse)
292 return(status);
293 /*
294 Write the HTML image file.
295 */
296 (void) WriteBlobString(image,"<?xml version=\"1.0\" "
297 "encoding=\"US-ASCII\"?>\n");
298 (void) WriteBlobString(image,"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML "
299 "1.0 Strict//EN\" "
300 "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
301 (void) WriteBlobString(image,"<html>\n");
302 (void) WriteBlobString(image,"<head>\n");
303 value=GetImageProperty(image,"label",exception);
304 if (value != (const char *) NULL)
305 (void) FormatLocaleString(buffer,MagickPathExtent,"<title>%s</title>\n",
306 value);
307 else
308 {
309 GetPathComponent(filename,BasePath,basename);
310 (void) FormatLocaleString(buffer,MagickPathExtent,
311 "<title>%s</title>\n",basename);
312 }
313 (void) WriteBlobString(image,buffer);
314 (void) WriteBlobString(image,"</head>\n");
315 (void) WriteBlobString(image,"<body style=\"text-align: center;\">\n");
316 (void) FormatLocaleString(buffer,MagickPathExtent,"<h1>%s</h1>\n",
317 image->filename);
318 (void) WriteBlobString(image,buffer);
319 (void) WriteBlobString(image,"<div>\n");
320 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
321 AppendImageFormat("png",filename);
322 (void) FormatLocaleString(buffer,MagickPathExtent,"<img usemap=\"#%s\" "
323 "src=\"%s\" style=\"border: 0;\" alt=\"Image map\" />\n",mapname,
324 filename);
325 (void) WriteBlobString(image,buffer);
326 /*
327 Determine the size and location of each image tile.
328 */
329 SetGeometry(image,&geometry);
330 if (image->montage != (char *) NULL)
331 (void) ParseAbsoluteGeometry(image->montage,&geometry);
332 /*
333 Write an image map.
334 */
335 (void) FormatLocaleString(buffer,MagickPathExtent,
336 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
337 (void) WriteBlobString(image,buffer);
338 (void) FormatLocaleString(buffer,MagickPathExtent," <area href=\"%s",
339 url);
340 (void) WriteBlobString(image,buffer);
341 if (image->directory == (char *) NULL)
342 {
343 (void) FormatLocaleString(buffer,MagickPathExtent,
344 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
345 image->filename,(double) geometry.width-1,(double) geometry.height-
346 1);
347 (void) WriteBlobString(image,buffer);
348 }
349 else
350 for (p=image->directory; *p != '\0'; p++)
351 if (*p != '\xff')
352 (void) WriteBlobByte(image,(unsigned char) *p);
353 else
354 {
355 (void) FormatLocaleString(buffer,MagickPathExtent,"\" shape="
356 "\"rect\" coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n",
357 (double) geometry.x,(double) geometry.y,(double) (geometry.x+
358 geometry.width-1),(double) (geometry.y+geometry.height-1));
359 (void) WriteBlobString(image,buffer);
360 if (*(p+1) != '\0')
361 {
362 (void) FormatLocaleString(buffer,MagickPathExtent,
363 " <area href=%s\"",url);
364 (void) WriteBlobString(image,buffer);
365 }
366 geometry.x+=(ssize_t) geometry.width;
367 if ((geometry.x+4) >= (ssize_t) image->columns)
368 {
369 geometry.x=0;
370 geometry.y+=(ssize_t) geometry.height;
371 }
372 }
373 (void) WriteBlobString(image,"</map>\n");
374 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
375 (void) WriteBlobString(image,"</div>\n");
376 (void) WriteBlobString(image,"</body>\n");
377 (void) WriteBlobString(image,"</html>\n");
378 (void) CloseBlob(image);
379 /*
380 Write the image as PNG.
381 */
382 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
383 AppendImageFormat("png",image->filename);
384 next=GetNextImageInList(image);
385 image->next=NewImageList();
386 (void) CopyMagickString(image->magick,"PNG",MagickPathExtent);
387 (void) WriteImage(write_info,image,exception);
388 image->next=next;
389 /*
390 Determine image map filename.
391 */
392 GetPathComponent(image->filename,BasePath,filename);
393 (void) ConcatenateMagickString(filename,"_map.shtml",MagickPathExtent);
394 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
395 }
396 /*
397 Open image map.
398 */
399 status=OpenBlob(write_info,image,WriteBinaryBlobMode,exception);
400 if (status == MagickFalse)
401 return(status);
402 write_info=DestroyImageInfo(write_info);
403 /*
404 Determine the size and location of each image tile.
405 */
406 SetGeometry(image,&geometry);
407 if (image->montage != (char *) NULL)
408 (void) ParseAbsoluteGeometry(image->montage,&geometry);
409 /*
410 Write an image map.
411 */
412 (void) FormatLocaleString(buffer,MagickPathExtent,
413 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
414 (void) WriteBlobString(image,buffer);
415 (void) FormatLocaleString(buffer,MagickPathExtent," <area href=\"%s",url);
416 (void) WriteBlobString(image,buffer);
417 if (image->directory == (char *) NULL)
418 {
419 (void) FormatLocaleString(buffer,MagickPathExtent,
420 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
421 image->filename,(double) geometry.width-1,(double) geometry.height-1);
422 (void) WriteBlobString(image,buffer);
423 }
424 else
425 for (p=image->directory; *p != '\0'; p++)
426 if (*p != '\xff')
427 (void) WriteBlobByte(image,(unsigned char) *p);
428 else
429 {
430 (void) FormatLocaleString(buffer,MagickPathExtent,"\" shape=\"rect\""
431 " coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n",
432 (double) geometry.x,(double) geometry.y,geometry.x+(double)
433 geometry.width-1,geometry.y+(double) geometry.height-1);
434 (void) WriteBlobString(image,buffer);
435 if (*(p+1) != '\0')
436 {
437 (void) FormatLocaleString(buffer,MagickPathExtent,
438 " <area href=%s\"",url);
439 (void) WriteBlobString(image,buffer);
440 }
441 geometry.x+=(ssize_t) geometry.width;
442 if ((geometry.x+4) >= (ssize_t) image->columns)
443 {
444 geometry.x=0;
445 geometry.y+=(ssize_t) geometry.height;
446 }
447 }
448 (void) WriteBlobString(image,"</map>\n");
449 (void) CloseBlob(image);
450 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
451 return(status);
452 }
453