blob: c44506e6589d8f803b2a7abb9958ed92af8e557d [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000017% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000018% July 1992 %
19% %
20% %
Cristy7ce65e72015-12-12 18:03:16 -050021% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000022% 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% http://www.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*/
cristy4c08aed2011-07-01 19:47:50 +000043#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"
cristy510d06a2011-07-06 23:43:54 +000048#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000049#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"
cristy3ed852e2009-09-05 21:47:34 +000063
64/*
65 Forward declarations.
66*/
67static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000068 WriteHTMLImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000069
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*/
95static MagickBooleanType IsHTML(const unsigned char *magick,const size_t length)
96{
97 if (length < 5)
98 return(MagickFalse);
99 if (LocaleNCompare((char *) magick,"<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%
cristybb503372010-05-27 20:51:26 +0000124% size_t RegisterHTMLImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000125%
126*/
cristybb503372010-05-27 20:51:26 +0000127ModuleExport size_t RegisterHTMLImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000128{
129 MagickInfo
130 *entry;
131
dirk06b627a2015-04-06 18:59:17 +0000132 entry=AcquireMagickInfo("HTML","HTM",
133 "Hypertext Markup Language and a client-side image map");
cristy3ed852e2009-09-05 21:47:34 +0000134 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
135 entry->magick=(IsImageFormatHandler *) IsHTML;
dirk08e9a112015-02-22 01:51:41 +0000136 entry->flags^=CoderAdjoinFlag;
cristy3ed852e2009-09-05 21:47:34 +0000137 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000138 entry=AcquireMagickInfo("HTML","HTML",
139 "Hypertext Markup Language and a client-side image map");
cristy3ed852e2009-09-05 21:47:34 +0000140 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
141 entry->magick=(IsImageFormatHandler *) IsHTML;
dirk08e9a112015-02-22 01:51:41 +0000142 entry->flags^=CoderAdjoinFlag;
cristy3ed852e2009-09-05 21:47:34 +0000143 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000144 entry=AcquireMagickInfo("HTML","SHTML",
145 "Hypertext Markup Language and a client-side image map");
cristy3ed852e2009-09-05 21:47:34 +0000146 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
147 entry->magick=(IsImageFormatHandler *) IsHTML;
dirk08e9a112015-02-22 01:51:41 +0000148 entry->flags^=CoderAdjoinFlag;
cristy3ed852e2009-09-05 21:47:34 +0000149 (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*/
172ModuleExport 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%
cristy1e178e72011-08-28 19:44:34 +0000194% MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
195% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000196%
197% A description of each parameter follows.
198%
199% o image_info: the image info.
200%
201% o image: The image.
202%
cristy1e178e72011-08-28 19:44:34 +0000203% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +0000204%
205*/
206static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000207 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000208{
209 char
cristy151b66d2015-04-15 10:50:31 +0000210 basename[MagickPathExtent],
211 buffer[MagickPathExtent],
212 filename[MagickPathExtent],
213 mapname[MagickPathExtent],
214 url[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000215
216 Image
217 *next;
218
219 ImageInfo
220 *write_info;
221
222 MagickBooleanType
223 status;
224
225 RectangleInfo
226 geometry;
227
228 register char
229 *p;
230
231 /*
232 Open image.
233 */
234 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000235 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000236 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000237 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000238 if (image->debug != MagickFalse)
239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
240 image_info->filename);
cristy3a37efd2011-08-28 20:31:03 +0000241 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000242 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +0000243 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000244 if (status == MagickFalse)
245 return(status);
246 (void) CloseBlob(image);
cristyaf8d3912014-02-21 14:50:33 +0000247 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000248 *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,'/');
cristyfc7f59b2011-09-16 00:41:11 +0000256 if (p != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000257 {
258 p++;
cristy151b66d2015-04-15 10:50:31 +0000259 (void) CopyMagickString(url,image_info->magick,MagickPathExtent);
260 (void) ConcatenateMagickString(url,":",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000261 url[strlen(url)+p-image->filename]='\0';
262 (void) ConcatenateMagickString(url,image->filename,
263 p-image->filename+2);
cristy151b66d2015-04-15 10:50:31 +0000264 (void) CopyMagickString(image->filename,p,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000265 }
266 }
267 /*
268 Refer to image map file.
269 */
cristy151b66d2015-04-15 10:50:31 +0000270 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000271 AppendImageFormat("map",filename);
272 GetPathComponent(filename,BasePath,basename);
cristy151b66d2015-04-15 10:50:31 +0000273 (void) CopyMagickString(mapname,basename,MagickPathExtent);
274 (void) CopyMagickString(image->filename,image_info->filename,MagickPathExtent);
275 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000276 write_info=CloneImageInfo(image_info);
cristy386d8ba2015-02-25 02:45:59 +0000277 *write_info->magick='\0';
cristy3ed852e2009-09-05 21:47:34 +0000278 write_info->adjoin=MagickTrue;
279 status=MagickTrue;
280 if (LocaleCompare(image_info->magick,"SHTML") != 0)
281 {
282 const char
283 *value;
284
285 /*
286 Open output image file.
287 */
cristy3a37efd2011-08-28 20:31:03 +0000288 assert(exception != (ExceptionInfo *) NULL);
cristyb06ced82012-01-21 16:19:35 +0000289 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000290 if (status == MagickFalse)
291 return(status);
292 /*
293 Write the HTML image file.
294 */
295 (void) WriteBlobString(image,"<?xml version=\"1.0\" "
296 "encoding=\"US-ASCII\"?>\n");
297 (void) WriteBlobString(image,"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML "
298 "1.0 Strict//EN\" "
299 "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
300 (void) WriteBlobString(image,"<html>\n");
301 (void) WriteBlobString(image,"<head>\n");
cristyd15e6592011-10-15 00:13:06 +0000302 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000303 if (value != (const char *) NULL)
cristy151b66d2015-04-15 10:50:31 +0000304 (void) FormatLocaleString(buffer,MagickPathExtent,"<title>%s</title>\n",
cristy3ed852e2009-09-05 21:47:34 +0000305 value);
306 else
307 {
308 GetPathComponent(filename,BasePath,basename);
cristy151b66d2015-04-15 10:50:31 +0000309 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000310 "<title>%s</title>\n",basename);
311 }
312 (void) WriteBlobString(image,buffer);
313 (void) WriteBlobString(image,"</head>\n");
314 (void) WriteBlobString(image,"<body style=\"text-align: center;\">\n");
cristy151b66d2015-04-15 10:50:31 +0000315 (void) FormatLocaleString(buffer,MagickPathExtent,"<h1>%s</h1>\n",
cristy3ed852e2009-09-05 21:47:34 +0000316 image->filename);
317 (void) WriteBlobString(image,buffer);
318 (void) WriteBlobString(image,"<div>\n");
cristy151b66d2015-04-15 10:50:31 +0000319 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000320 AppendImageFormat("png",filename);
cristy151b66d2015-04-15 10:50:31 +0000321 (void) FormatLocaleString(buffer,MagickPathExtent,"<img usemap=\"#%s\" "
cristy3ed852e2009-09-05 21:47:34 +0000322 "src=\"%s\" style=\"border: 0;\" alt=\"Image map\" />\n",mapname,
323 filename);
324 (void) WriteBlobString(image,buffer);
325 /*
326 Determine the size and location of each image tile.
327 */
328 SetGeometry(image,&geometry);
329 if (image->montage != (char *) NULL)
330 (void) ParseAbsoluteGeometry(image->montage,&geometry);
331 /*
332 Write an image map.
333 */
cristy151b66d2015-04-15 10:50:31 +0000334 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000335 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
336 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +0000337 (void) FormatLocaleString(buffer,MagickPathExtent," <area href=\"%s",url);
cristy3ed852e2009-09-05 21:47:34 +0000338 (void) WriteBlobString(image,buffer);
339 if (image->directory == (char *) NULL)
340 {
cristy151b66d2015-04-15 10:50:31 +0000341 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +0000342 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
343 image->filename,(double) geometry.width-1,(double) geometry.height-
344 1);
cristy3ed852e2009-09-05 21:47:34 +0000345 (void) WriteBlobString(image,buffer);
346 }
347 else
348 for (p=image->directory; *p != '\0'; p++)
349 if (*p != '\n')
350 (void) WriteBlobByte(image,(unsigned char) *p);
351 else
352 {
cristy151b66d2015-04-15 10:50:31 +0000353 (void) FormatLocaleString(buffer,MagickPathExtent,"\" shape="
cristyebc891a2011-04-24 23:04:16 +0000354 "\"rect\" coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n",
cristye8c25f92010-06-03 00:53:06 +0000355 (double) geometry.x,(double) geometry.y,(double) (geometry.x+
356 geometry.width-1),(double) (geometry.y+geometry.height-1));
cristy3ed852e2009-09-05 21:47:34 +0000357 (void) WriteBlobString(image,buffer);
358 if (*(p+1) != '\0')
359 {
cristy151b66d2015-04-15 10:50:31 +0000360 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000361 " <area href=%s\"",url);
362 (void) WriteBlobString(image,buffer);
363 }
cristyeaedf062010-05-29 22:36:02 +0000364 geometry.x+=(ssize_t) geometry.width;
cristybb503372010-05-27 20:51:26 +0000365 if ((geometry.x+4) >= (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +0000366 {
367 geometry.x=0;
cristyeaedf062010-05-29 22:36:02 +0000368 geometry.y+=(ssize_t) geometry.height;
cristy3ed852e2009-09-05 21:47:34 +0000369 }
370 }
371 (void) WriteBlobString(image,"</map>\n");
cristy151b66d2015-04-15 10:50:31 +0000372 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000373 (void) WriteBlobString(image,"</div>\n");
374 (void) WriteBlobString(image,"</body>\n");
375 (void) WriteBlobString(image,"</html>\n");
376 (void) CloseBlob(image);
377 /*
378 Write the image as PNG.
379 */
cristy151b66d2015-04-15 10:50:31 +0000380 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000381 AppendImageFormat("png",image->filename);
382 next=GetNextImageInList(image);
383 image->next=NewImageList();
cristy151b66d2015-04-15 10:50:31 +0000384 (void) CopyMagickString(image->magick,"PNG",MagickPathExtent);
cristy1e178e72011-08-28 19:44:34 +0000385 (void) WriteImage(write_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000386 image->next=next;
387 /*
388 Determine image map filename.
389 */
390 GetPathComponent(image->filename,BasePath,filename);
cristy151b66d2015-04-15 10:50:31 +0000391 (void) ConcatenateMagickString(filename,"_map.shtml",MagickPathExtent);
392 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000393 }
394 /*
395 Open image map.
396 */
cristy1e178e72011-08-28 19:44:34 +0000397 status=OpenBlob(write_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000398 if (status == MagickFalse)
399 return(status);
400 write_info=DestroyImageInfo(write_info);
401 /*
402 Determine the size and location of each image tile.
403 */
404 SetGeometry(image,&geometry);
405 if (image->montage != (char *) NULL)
406 (void) ParseAbsoluteGeometry(image->montage,&geometry);
407 /*
408 Write an image map.
409 */
cristy151b66d2015-04-15 10:50:31 +0000410 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000411 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
412 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +0000413 (void) FormatLocaleString(buffer,MagickPathExtent," <area href=\"%s",url);
cristy3ed852e2009-09-05 21:47:34 +0000414 (void) WriteBlobString(image,buffer);
415 if (image->directory == (char *) NULL)
416 {
cristy151b66d2015-04-15 10:50:31 +0000417 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +0000418 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
419 image->filename,(double) geometry.width-1,(double) geometry.height-1);
cristy3ed852e2009-09-05 21:47:34 +0000420 (void) WriteBlobString(image,buffer);
421 }
422 else
423 for (p=image->directory; *p != '\0'; p++)
424 if (*p != '\n')
425 (void) WriteBlobByte(image,(unsigned char) *p);
426 else
427 {
cristy151b66d2015-04-15 10:50:31 +0000428 (void) FormatLocaleString(buffer,MagickPathExtent,"\" shape=\"rect\""
cristyebc891a2011-04-24 23:04:16 +0000429 " coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n",
cristye8c25f92010-06-03 00:53:06 +0000430 (double) geometry.x,(double) geometry.y,geometry.x+(double)
431 geometry.width-1,geometry.y+(double) geometry.height-1);
cristy3ed852e2009-09-05 21:47:34 +0000432 (void) WriteBlobString(image,buffer);
433 if (*(p+1) != '\0')
434 {
cristy151b66d2015-04-15 10:50:31 +0000435 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000436 " <area href=%s\"",url);
437 (void) WriteBlobString(image,buffer);
438 }
cristyeaedf062010-05-29 22:36:02 +0000439 geometry.x+=(ssize_t) geometry.width;
cristybb503372010-05-27 20:51:26 +0000440 if ((geometry.x+4) >= (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +0000441 {
442 geometry.x=0;
cristyeaedf062010-05-29 22:36:02 +0000443 geometry.y+=(ssize_t) geometry.height;
cristy3ed852e2009-09-05 21:47:34 +0000444 }
445 }
446 (void) WriteBlobString(image,"</map>\n");
447 (void) CloseBlob(image);
cristy151b66d2015-04-15 10:50:31 +0000448 (void) CopyMagickString(image->filename,filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000449 return(status);
450}