Coverage Report

Created: 2026-05-16 07:22

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