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-2016 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% 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 "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*/ 67static 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*/ 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% 124% size_t RegisterHTMLImage(void) 125% 126*/ 127ModuleExport 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*/ 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% 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*/ 206static 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 register 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,MagickPathExtent); 275 (void) CopyMagickString(filename,image->filename,MagickPathExtent); 276 write_info=CloneImageInfo(image_info); 277 *write_info->magick='\0'; 278 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 */ 288 assert(exception != (ExceptionInfo *) NULL); 289 status=OpenBlob(image_info,image,WriteBinaryBlobMode,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",exception); 303 if (value != (const char *) NULL) 304 (void) FormatLocaleString(buffer,MagickPathExtent,"<title>%s</title>\n", 305 value); 306 else 307 { 308 GetPathComponent(filename,BasePath,basename); 309 (void) FormatLocaleString(buffer,MagickPathExtent, 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) FormatLocaleString(buffer,MagickPathExtent,"<h1>%s</h1>\n", 316 image->filename); 317 (void) WriteBlobString(image,buffer); 318 (void) WriteBlobString(image,"<div>\n"); 319 (void) CopyMagickString(filename,image->filename,MagickPathExtent); 320 AppendImageFormat("png",filename); 321 (void) FormatLocaleString(buffer,MagickPathExtent,"<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) FormatLocaleString(buffer,MagickPathExtent, 335 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname); 336 (void) WriteBlobString(image,buffer); 337 (void) FormatLocaleString(buffer,MagickPathExtent," <area href=\"%s",url); 338 (void) WriteBlobString(image,buffer); 339 if (image->directory == (char *) NULL) 340 { 341 (void) FormatLocaleString(buffer,MagickPathExtent, 342 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n", 343 image->filename,(double) geometry.width-1,(double) geometry.height- 344 1); 345 (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 { 353 (void) FormatLocaleString(buffer,MagickPathExtent,"\" shape=" 354 "\"rect\" coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n", 355 (double) geometry.x,(double) geometry.y,(double) (geometry.x+ 356 geometry.width-1),(double) (geometry.y+geometry.height-1)); 357 (void) WriteBlobString(image,buffer); 358 if (*(p+1) != '\0') 359 { 360 (void) FormatLocaleString(buffer,MagickPathExtent, 361 " <area href=%s\"",url); 362 (void) WriteBlobString(image,buffer); 363 } 364 geometry.x+=(ssize_t) geometry.width; 365 if ((geometry.x+4) >= (ssize_t) image->columns) 366 { 367 geometry.x=0; 368 geometry.y+=(ssize_t) geometry.height; 369 } 370 } 371 (void) WriteBlobString(image,"</map>\n"); 372 (void) CopyMagickString(filename,image->filename,MagickPathExtent); 373 (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 */ 380 (void) CopyMagickString(image->filename,filename,MagickPathExtent); 381 AppendImageFormat("png",image->filename); 382 next=GetNextImageInList(image); 383 image->next=NewImageList(); 384 (void) CopyMagickString(image->magick,"PNG",MagickPathExtent); 385 (void) WriteImage(write_info,image,exception); 386 image->next=next; 387 /* 388 Determine image map filename. 389 */ 390 GetPathComponent(image->filename,BasePath,filename); 391 (void) ConcatenateMagickString(filename,"_map.shtml",MagickPathExtent); 392 (void) CopyMagickString(image->filename,filename,MagickPathExtent); 393 } 394 /* 395 Open image map. 396 */ 397 status=OpenBlob(write_info,image,WriteBinaryBlobMode,exception); 398 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 */ 410 (void) FormatLocaleString(buffer,MagickPathExtent, 411 "<map id=\"%s\" name=\"%s\">\n",mapname,mapname); 412 (void) WriteBlobString(image,buffer); 413 (void) FormatLocaleString(buffer,MagickPathExtent," <area href=\"%s",url); 414 (void) WriteBlobString(image,buffer); 415 if (image->directory == (char *) NULL) 416 { 417 (void) FormatLocaleString(buffer,MagickPathExtent, 418 "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n", 419 image->filename,(double) geometry.width-1,(double) geometry.height-1); 420 (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 { 428 (void) FormatLocaleString(buffer,MagickPathExtent,"\" shape=\"rect\"" 429 " coords=\"%.20g,%.20g,%.20g,%.20g\" alt=\"\" />\n", 430 (double) geometry.x,(double) geometry.y,geometry.x+(double) 431 geometry.width-1,geometry.y+(double) geometry.height-1); 432 (void) WriteBlobString(image,buffer); 433 if (*(p+1) != '\0') 434 { 435 (void) FormatLocaleString(buffer,MagickPathExtent, 436 " <area href=%s\"",url); 437 (void) WriteBlobString(image,buffer); 438 } 439 geometry.x+=(ssize_t) geometry.width; 440 if ((geometry.x+4) >= (ssize_t) image->columns) 441 { 442 geometry.x=0; 443 geometry.y+=(ssize_t) geometry.height; 444 } 445 } 446 (void) WriteBlobString(image,"</map>\n"); 447 (void) CloseBlob(image); 448 (void) CopyMagickString(image->filename,filename,MagickPathExtent); 449 return(status); 450} 451