blob: aa40d2acb9f2f14ae8544f0f9ddbe48b5ea806de [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 %
17% John Cristy %
18% July 1992 %
19% %
20% %
cristy1454be72011-12-19 01:52:48 +000021% Copyright 1999-2012 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
132 entry=SetMagickInfo("HTM");
133 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
134 entry->magick=(IsImageFormatHandler *) IsHTML;
135 entry->adjoin=MagickFalse;
136 entry->description=ConstantString(
137 "Hypertext Markup Language and a client-side image map");
138 entry->module=ConstantString("HTML");
139 (void) RegisterMagickInfo(entry);
140 entry=SetMagickInfo("HTML");
141 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
142 entry->magick=(IsImageFormatHandler *) IsHTML;
143 entry->adjoin=MagickFalse;
144 entry->description=ConstantString(
145 "Hypertext Markup Language and a client-side image map");
146 entry->module=ConstantString("HTML");
147 (void) RegisterMagickInfo(entry);
148 entry=SetMagickInfo("SHTML");
149 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
150 entry->magick=(IsImageFormatHandler *) IsHTML;
151 entry->adjoin=MagickFalse;
152 entry->description=ConstantString(
153 "Hypertext Markup Language and a client-side image map");
154 entry->module=ConstantString("HTML");
155 (void) RegisterMagickInfo(entry);
156 return(MagickImageCoderSignature);
157}
158
159/*
160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161% %
162% %
163% %
164% U n r e g i s t e r H T M L I m a g e %
165% %
166% %
167% %
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169%
170% UnregisterHTMLImage() removes format registrations made by the
171% HTML module from the list of supported formats.
172%
173% The format of the UnregisterHTMLImage method is:
174%
175% UnregisterHTMLImage(void)
176%
177*/
178ModuleExport void UnregisterHTMLImage(void)
179{
180 (void) UnregisterMagickInfo("HTM");
181 (void) UnregisterMagickInfo("HTML");
182 (void) UnregisterMagickInfo("SHTML");
183}
184
185/*
186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187% %
188% %
189% %
190% W r i t e H T M L I m a g e %
191% %
192% %
193% %
194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195%
196% WriteHTMLImage() writes an image in the HTML encoded image format.
197%
198% The format of the WriteHTMLImage method is:
199%
cristy1e178e72011-08-28 19:44:34 +0000200% MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
201% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000202%
203% A description of each parameter follows.
204%
205% o image_info: the image info.
206%
207% o image: The image.
208%
cristy1e178e72011-08-28 19:44:34 +0000209% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +0000210%
211*/
212static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000213 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000214{
215 char
216 basename[MaxTextExtent],
217 buffer[MaxTextExtent],
218 filename[MaxTextExtent],
219 mapname[MaxTextExtent],
220 url[MaxTextExtent];
221
222 Image
223 *next;
224
225 ImageInfo
226 *write_info;
227
228 MagickBooleanType
229 status;
230
231 RectangleInfo
232 geometry;
233
234 register char
235 *p;
236
237 /*
238 Open image.
239 */
240 assert(image_info != (const ImageInfo *) NULL);
241 assert(image_info->signature == MagickSignature);
242 assert(image != (Image *) NULL);
243 assert(image->signature == MagickSignature);
244 if (image->debug != MagickFalse)
245 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
246 image_info->filename);
cristy3a37efd2011-08-28 20:31:03 +0000247 assert(exception != (ExceptionInfo *) NULL);
248 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000249 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000250 if (status == MagickFalse)
251 return(status);
252 (void) CloseBlob(image);
cristy3d9f5ba2012-06-26 13:37:31 +0000253 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy8d951092012-02-08 18:54:56 +0000254 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000255 *url='\0';
256 if ((LocaleCompare(image_info->magick,"FTP") == 0) ||
257 (LocaleCompare(image_info->magick,"HTTP") == 0))
258 {
259 /*
260 Extract URL base from filename.
261 */
262 p=strrchr(image->filename,'/');
cristyfc7f59b2011-09-16 00:41:11 +0000263 if (p != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000264 {
265 p++;
266 (void) CopyMagickString(url,image_info->magick,MaxTextExtent);
267 (void) ConcatenateMagickString(url,":",MaxTextExtent);
268 url[strlen(url)+p-image->filename]='\0';
269 (void) ConcatenateMagickString(url,image->filename,
270 p-image->filename+2);
271 (void) CopyMagickString(image->filename,p,MaxTextExtent);
272 }
273 }
274 /*
275 Refer to image map file.
276 */
277 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
278 AppendImageFormat("map",filename);
279 GetPathComponent(filename,BasePath,basename);
280 (void) CopyMagickString(mapname,basename,MaxTextExtent);
281 (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
282 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
283 write_info=CloneImageInfo(image_info);
284 write_info->adjoin=MagickTrue;
285 status=MagickTrue;
286 if (LocaleCompare(image_info->magick,"SHTML") != 0)
287 {
288 const char
289 *value;
290
291 /*
292 Open output image file.
293 */
cristy3a37efd2011-08-28 20:31:03 +0000294 assert(exception != (ExceptionInfo *) NULL);
cristyb06ced82012-01-21 16:19:35 +0000295 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000296 if (status == MagickFalse)
297 return(status);
298 /*
299 Write the HTML image file.
300 */
301 (void) WriteBlobString(image,"<?xml version=\"1.0\" "
302 "encoding=\"US-ASCII\"?>\n");
303 (void) WriteBlobString(image,"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML "
304 "1.0 Strict//EN\" "
305 "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
306 (void) WriteBlobString(image,"<html>\n");
307 (void) WriteBlobString(image,"<head>\n");
cristyd15e6592011-10-15 00:13:06 +0000308 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000309 if (value != (const char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000310 (void) FormatLocaleString(buffer,MaxTextExtent,"<title>%s</title>\n",
cristy3ed852e2009-09-05 21:47:34 +0000311 value);
312 else
313 {
314 GetPathComponent(filename,BasePath,basename);
cristyb51dff52011-05-19 16:55:47 +0000315 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000316 "<title>%s</title>\n",basename);
317 }
318 (void) WriteBlobString(image,buffer);
319 (void) WriteBlobString(image,"</head>\n");
320 (void) WriteBlobString(image,"<body style=\"text-align: center;\">\n");
cristyb51dff52011-05-19 16:55:47 +0000321 (void) FormatLocaleString(buffer,MaxTextExtent,"<h1>%s</h1>\n",
cristy3ed852e2009-09-05 21:47:34 +0000322 image->filename);
323 (void) WriteBlobString(image,buffer);
324 (void) WriteBlobString(image,"<div>\n");
325 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
326 AppendImageFormat("png",filename);
cristyb51dff52011-05-19 16:55:47 +0000327 (void) FormatLocaleString(buffer,MaxTextExtent,"<img usemap=\"#%s\" "
cristy3ed852e2009-09-05 21:47:34 +0000328 "src=\"%s\" style=\"border: 0;\" alt=\"Image map\" />\n",mapname,
329 filename);
330 (void) WriteBlobString(image,buffer);
331 /*
332 Determine the size and location of each image tile.
333 */
334 SetGeometry(image,&geometry);
335 if (image->montage != (char *) NULL)
336 (void) ParseAbsoluteGeometry(image->montage,&geometry);
337 /*
338 Write an image map.
339 */
cristyb51dff52011-05-19 16:55:47 +0000340 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000341 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
342 (void) WriteBlobString(image,buffer);
cristyc4f49f52012-04-03 17:30:53 +0000343 (void) FormatLocaleString(buffer,MaxTextExtent," <area href=\"%s",url);
cristy3ed852e2009-09-05 21:47:34 +0000344 (void) WriteBlobString(image,buffer);
345 if (image->directory == (char *) NULL)
346 {
cristyb51dff52011-05-19 16:55:47 +0000347 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000348 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
349 image->filename,(double) geometry.width-1,(double) geometry.height-
350 1);
cristy3ed852e2009-09-05 21:47:34 +0000351 (void) WriteBlobString(image,buffer);
352 }
353 else
354 for (p=image->directory; *p != '\0'; p++)
355 if (*p != '\n')
356 (void) WriteBlobByte(image,(unsigned char) *p);
357 else
358 {
cristyb51dff52011-05-19 16:55:47 +0000359 (void) FormatLocaleString(buffer,MaxTextExtent,"\" shape="
cristyebc891a2011-04-24 23:04:16 +0000360 "\"rect\" coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n",
cristye8c25f92010-06-03 00:53:06 +0000361 (double) geometry.x,(double) geometry.y,(double) (geometry.x+
362 geometry.width-1),(double) (geometry.y+geometry.height-1));
cristy3ed852e2009-09-05 21:47:34 +0000363 (void) WriteBlobString(image,buffer);
364 if (*(p+1) != '\0')
365 {
cristyb51dff52011-05-19 16:55:47 +0000366 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000367 " <area href=%s\"",url);
368 (void) WriteBlobString(image,buffer);
369 }
cristyeaedf062010-05-29 22:36:02 +0000370 geometry.x+=(ssize_t) geometry.width;
cristybb503372010-05-27 20:51:26 +0000371 if ((geometry.x+4) >= (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +0000372 {
373 geometry.x=0;
cristyeaedf062010-05-29 22:36:02 +0000374 geometry.y+=(ssize_t) geometry.height;
cristy3ed852e2009-09-05 21:47:34 +0000375 }
376 }
377 (void) WriteBlobString(image,"</map>\n");
378 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
379 (void) WriteBlobString(image,"</div>\n");
380 (void) WriteBlobString(image,"</body>\n");
381 (void) WriteBlobString(image,"</html>\n");
382 (void) CloseBlob(image);
383 /*
384 Write the image as PNG.
385 */
386 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
387 AppendImageFormat("png",image->filename);
388 next=GetNextImageInList(image);
389 image->next=NewImageList();
390 (void) CopyMagickString(image->magick,"PNG",MaxTextExtent);
cristy1e178e72011-08-28 19:44:34 +0000391 (void) WriteImage(write_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000392 image->next=next;
393 /*
394 Determine image map filename.
395 */
396 GetPathComponent(image->filename,BasePath,filename);
397 (void) ConcatenateMagickString(filename,"_map.shtml",MaxTextExtent);
398 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
399 }
400 /*
401 Open image map.
402 */
cristy1e178e72011-08-28 19:44:34 +0000403 status=OpenBlob(write_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000404 if (status == MagickFalse)
405 return(status);
406 write_info=DestroyImageInfo(write_info);
407 /*
408 Determine the size and location of each image tile.
409 */
410 SetGeometry(image,&geometry);
411 if (image->montage != (char *) NULL)
412 (void) ParseAbsoluteGeometry(image->montage,&geometry);
413 /*
414 Write an image map.
415 */
cristyb51dff52011-05-19 16:55:47 +0000416 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000417 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
418 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +0000419 (void) FormatLocaleString(buffer,MaxTextExtent," <area href=\"%s",url);
cristy3ed852e2009-09-05 21:47:34 +0000420 (void) WriteBlobString(image,buffer);
421 if (image->directory == (char *) NULL)
422 {
cristyb51dff52011-05-19 16:55:47 +0000423 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000424 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
425 image->filename,(double) geometry.width-1,(double) geometry.height-1);
cristy3ed852e2009-09-05 21:47:34 +0000426 (void) WriteBlobString(image,buffer);
427 }
428 else
429 for (p=image->directory; *p != '\0'; p++)
430 if (*p != '\n')
431 (void) WriteBlobByte(image,(unsigned char) *p);
432 else
433 {
cristyb51dff52011-05-19 16:55:47 +0000434 (void) FormatLocaleString(buffer,MaxTextExtent,"\" shape=\"rect\""
cristyebc891a2011-04-24 23:04:16 +0000435 " coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n",
cristye8c25f92010-06-03 00:53:06 +0000436 (double) geometry.x,(double) geometry.y,geometry.x+(double)
437 geometry.width-1,geometry.y+(double) geometry.height-1);
cristy3ed852e2009-09-05 21:47:34 +0000438 (void) WriteBlobString(image,buffer);
439 if (*(p+1) != '\0')
440 {
cristyb51dff52011-05-19 16:55:47 +0000441 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000442 " <area href=%s\"",url);
443 (void) WriteBlobString(image,buffer);
444 }
cristyeaedf062010-05-29 22:36:02 +0000445 geometry.x+=(ssize_t) geometry.width;
cristybb503372010-05-27 20:51:26 +0000446 if ((geometry.x+4) >= (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +0000447 {
448 geometry.x=0;
cristyeaedf062010-05-29 22:36:02 +0000449 geometry.y+=(ssize_t) geometry.height;
cristy3ed852e2009-09-05 21:47:34 +0000450 }
451 }
452 (void) WriteBlobString(image,"</map>\n");
453 (void) CloseBlob(image);
454 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
455 return(status);
456}