blob: 7bc6d40a3578058355b44e46052d39d2a79c24bf [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% %
cristy16af1cb2009-12-11 21:38:29 +000021% Copyright 1999-2010 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*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/color-private.h"
47#include "magick/colorspace.h"
48#include "magick/constitute.h"
49#include "magick/exception.h"
50#include "magick/exception-private.h"
51#include "magick/geometry.h"
52#include "magick/list.h"
53#include "magick/magick.h"
54#include "magick/memory_.h"
55#include "magick/paint.h"
56#include "magick/property.h"
57#include "magick/quantum-private.h"
58#include "magick/static.h"
59#include "magick/string_.h"
60#include "magick/module.h"
61#include "magick/utility.h"
62
63/*
64 Forward declarations.
65*/
66static MagickBooleanType
67 WriteHTMLImage(const ImageInfo *,Image *);
68
69/*
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71% %
72% %
73% %
74% I s H T M L %
75% %
76% %
77% %
78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79%
80% IsHTML() returns MagickTrue if the image format type, identified by the
81% magick string, is HTML.
82%
83% The format of the IsHTML method is:
84%
85% MagickBooleanType IsHTML(const unsigned char *magick,const size_t length)
86%
87% A description of each parameter follows:
88%
89% o magick: compare image format pattern against these bytes.
90%
91% o length: Specifies the length of the magick string.
92%
93*/
94static MagickBooleanType IsHTML(const unsigned char *magick,const size_t length)
95{
96 if (length < 5)
97 return(MagickFalse);
98 if (LocaleNCompare((char *) magick,"<html",5) == 0)
99 return(MagickTrue);
100 return(MagickFalse);
101}
102
103/*
104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105% %
106% %
107% %
108% R e g i s t e r H T M L I m a g e %
109% %
110% %
111% %
112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113%
114% RegisterHTMLImage() adds properties for the HTML image format to
115% the list of supported formats. The properties include the image format
116% tag, a method to read and/or write the format, whether the format
117% supports the saving of more than one frame to the same file or blob,
118% whether the format supports native in-memory I/O, and a brief
119% description of the format.
120%
121% The format of the RegisterHTMLImage method is:
122%
cristybb503372010-05-27 20:51:26 +0000123% size_t RegisterHTMLImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000124%
125*/
cristybb503372010-05-27 20:51:26 +0000126ModuleExport size_t RegisterHTMLImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000127{
128 MagickInfo
129 *entry;
130
131 entry=SetMagickInfo("HTM");
132 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
133 entry->magick=(IsImageFormatHandler *) IsHTML;
134 entry->adjoin=MagickFalse;
135 entry->description=ConstantString(
136 "Hypertext Markup Language and a client-side image map");
137 entry->module=ConstantString("HTML");
138 (void) RegisterMagickInfo(entry);
139 entry=SetMagickInfo("HTML");
140 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
141 entry->magick=(IsImageFormatHandler *) IsHTML;
142 entry->adjoin=MagickFalse;
143 entry->description=ConstantString(
144 "Hypertext Markup Language and a client-side image map");
145 entry->module=ConstantString("HTML");
146 (void) RegisterMagickInfo(entry);
147 entry=SetMagickInfo("SHTML");
148 entry->encoder=(EncodeImageHandler *) WriteHTMLImage;
149 entry->magick=(IsImageFormatHandler *) IsHTML;
150 entry->adjoin=MagickFalse;
151 entry->description=ConstantString(
152 "Hypertext Markup Language and a client-side image map");
153 entry->module=ConstantString("HTML");
154 (void) RegisterMagickInfo(entry);
155 return(MagickImageCoderSignature);
156}
157
158/*
159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160% %
161% %
162% %
163% U n r e g i s t e r H T M L I m a g e %
164% %
165% %
166% %
167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168%
169% UnregisterHTMLImage() removes format registrations made by the
170% HTML module from the list of supported formats.
171%
172% The format of the UnregisterHTMLImage method is:
173%
174% UnregisterHTMLImage(void)
175%
176*/
177ModuleExport void UnregisterHTMLImage(void)
178{
179 (void) UnregisterMagickInfo("HTM");
180 (void) UnregisterMagickInfo("HTML");
181 (void) UnregisterMagickInfo("SHTML");
182}
183
184/*
185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186% %
187% %
188% %
189% W r i t e H T M L I m a g e %
190% %
191% %
192% %
193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194%
195% WriteHTMLImage() writes an image in the HTML encoded image format.
196%
197% The format of the WriteHTMLImage method is:
198%
199% MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,Image *image)
200%
201% A description of each parameter follows.
202%
203% o image_info: the image info.
204%
205% o image: The image.
206%
207%
208*/
209static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
210 Image *image)
211{
212 char
213 basename[MaxTextExtent],
214 buffer[MaxTextExtent],
215 filename[MaxTextExtent],
216 mapname[MaxTextExtent],
217 url[MaxTextExtent];
218
219 Image
220 *next;
221
222 ImageInfo
223 *write_info;
224
225 MagickBooleanType
226 status;
227
228 RectangleInfo
229 geometry;
230
231 register char
232 *p;
233
234 /*
235 Open image.
236 */
237 assert(image_info != (const ImageInfo *) NULL);
238 assert(image_info->signature == MagickSignature);
239 assert(image != (Image *) NULL);
240 assert(image->signature == MagickSignature);
241 if (image->debug != MagickFalse)
242 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
243 image_info->filename);
244 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
245 if (status == MagickFalse)
246 return(status);
247 (void) CloseBlob(image);
248 if (image->colorspace != RGBColorspace)
249 (void) TransformImageColorspace(image,RGBColorspace);
250 *url='\0';
251 if ((LocaleCompare(image_info->magick,"FTP") == 0) ||
252 (LocaleCompare(image_info->magick,"HTTP") == 0))
253 {
254 /*
255 Extract URL base from filename.
256 */
257 p=strrchr(image->filename,'/');
258 if (p)
259 {
260 p++;
261 (void) CopyMagickString(url,image_info->magick,MaxTextExtent);
262 (void) ConcatenateMagickString(url,":",MaxTextExtent);
263 url[strlen(url)+p-image->filename]='\0';
264 (void) ConcatenateMagickString(url,image->filename,
265 p-image->filename+2);
266 (void) CopyMagickString(image->filename,p,MaxTextExtent);
267 }
268 }
269 /*
270 Refer to image map file.
271 */
272 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
273 AppendImageFormat("map",filename);
274 GetPathComponent(filename,BasePath,basename);
275 (void) CopyMagickString(mapname,basename,MaxTextExtent);
276 (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
277 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
278 write_info=CloneImageInfo(image_info);
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 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
290 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");
302 value=GetImageProperty(image,"label");
303 if (value != (const char *) NULL)
304 (void) FormatMagickString(buffer,MaxTextExtent,"<title>%s</title>\n",
305 value);
306 else
307 {
308 GetPathComponent(filename,BasePath,basename);
309 (void) FormatMagickString(buffer,MaxTextExtent,
310 "<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");
315 (void) FormatMagickString(buffer,MaxTextExtent,"<h1>%s</h1>\n",
316 image->filename);
317 (void) WriteBlobString(image,buffer);
318 (void) WriteBlobString(image,"<div>\n");
319 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
320 AppendImageFormat("png",filename);
321 (void) FormatMagickString(buffer,MaxTextExtent,"<img usemap=\"#%s\" "
322 "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 */
334 (void) FormatMagickString(buffer,MaxTextExtent,
335 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
336 (void) WriteBlobString(image,buffer);
337 (void) FormatMagickString(buffer,MaxTextExtent," <area href=\"%s",
338 url);
339 (void) WriteBlobString(image,buffer);
340 if (image->directory == (char *) NULL)
341 {
342 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000343 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
344 image->filename,(double) geometry.width-1,(double) geometry.height-
345 1);
cristy3ed852e2009-09-05 21:47:34 +0000346 (void) WriteBlobString(image,buffer);
347 }
348 else
349 for (p=image->directory; *p != '\0'; p++)
350 if (*p != '\n')
351 (void) WriteBlobByte(image,(unsigned char) *p);
352 else
353 {
354 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000355 "\" shape=\"rect\" coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n",
356 (double) geometry.x,(double) geometry.y,(double) (geometry.x+
357 geometry.width-1),(double) (geometry.y+geometry.height-1));
cristy3ed852e2009-09-05 21:47:34 +0000358 (void) WriteBlobString(image,buffer);
359 if (*(p+1) != '\0')
360 {
361 (void) FormatMagickString(buffer,MaxTextExtent,
362 " <area href=%s\"",url);
363 (void) WriteBlobString(image,buffer);
364 }
cristyeaedf062010-05-29 22:36:02 +0000365 geometry.x+=(ssize_t) geometry.width;
cristybb503372010-05-27 20:51:26 +0000366 if ((geometry.x+4) >= (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +0000367 {
368 geometry.x=0;
cristyeaedf062010-05-29 22:36:02 +0000369 geometry.y+=(ssize_t) geometry.height;
cristy3ed852e2009-09-05 21:47:34 +0000370 }
371 }
372 (void) WriteBlobString(image,"</map>\n");
373 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
374 (void) WriteBlobString(image,"</div>\n");
375 (void) WriteBlobString(image,"</body>\n");
376 (void) WriteBlobString(image,"</html>\n");
377 (void) CloseBlob(image);
378 /*
379 Write the image as PNG.
380 */
381 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
382 AppendImageFormat("png",image->filename);
383 next=GetNextImageInList(image);
384 image->next=NewImageList();
385 (void) CopyMagickString(image->magick,"PNG",MaxTextExtent);
386 (void) WriteImage(write_info,image);
387 image->next=next;
388 /*
389 Determine image map filename.
390 */
391 GetPathComponent(image->filename,BasePath,filename);
392 (void) ConcatenateMagickString(filename,"_map.shtml",MaxTextExtent);
393 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
394 }
395 /*
396 Open image map.
397 */
398 status=OpenBlob(write_info,image,WriteBinaryBlobMode,&image->exception);
399 if (status == MagickFalse)
400 return(status);
401 write_info=DestroyImageInfo(write_info);
402 /*
403 Determine the size and location of each image tile.
404 */
405 SetGeometry(image,&geometry);
406 if (image->montage != (char *) NULL)
407 (void) ParseAbsoluteGeometry(image->montage,&geometry);
408 /*
409 Write an image map.
410 */
411 (void) FormatMagickString(buffer,MaxTextExtent,
412 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
413 (void) WriteBlobString(image,buffer);
414 (void) FormatMagickString(buffer,MaxTextExtent," <area href=\"%s",url);
415 (void) WriteBlobString(image,buffer);
416 if (image->directory == (char *) NULL)
417 {
418 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000419 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
420 image->filename,(double) geometry.width-1,(double) geometry.height-1);
cristy3ed852e2009-09-05 21:47:34 +0000421 (void) WriteBlobString(image,buffer);
422 }
423 else
424 for (p=image->directory; *p != '\0'; p++)
425 if (*p != '\n')
426 (void) WriteBlobByte(image,(unsigned char) *p);
427 else
428 {
429 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000430 "\" shape=\"rect\" coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n",
431 (double) geometry.x,(double) geometry.y,geometry.x+(double)
432 geometry.width-1,geometry.y+(double) geometry.height-1);
cristy3ed852e2009-09-05 21:47:34 +0000433 (void) WriteBlobString(image,buffer);
434 if (*(p+1) != '\0')
435 {
436 (void) FormatMagickString(buffer,MaxTextExtent,
437 " <area href=%s\"",url);
438 (void) WriteBlobString(image,buffer);
439 }
cristyeaedf062010-05-29 22:36:02 +0000440 geometry.x+=(ssize_t) geometry.width;
cristybb503372010-05-27 20:51:26 +0000441 if ((geometry.x+4) >= (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +0000442 {
443 geometry.x=0;
cristyeaedf062010-05-29 22:36:02 +0000444 geometry.y+=(ssize_t) geometry.height;
cristy3ed852e2009-09-05 21:47:34 +0000445 }
446 }
447 (void) WriteBlobString(image,"</map>\n");
448 (void) CloseBlob(image);
449 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
450 return(status);
451}