Coverage Report

Created: 2026-06-07 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/vips.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                        V   V  IIIII  PPPP   SSSSS                           %
7
%                        V   V    I    P   P  SS                              %
8
%                        V   V    I    PPPP    SSS                            %
9
%                         V V     I    P         SS                           %
10
%                          V    IIIII  P      SSSSS                           %
11
%                                                                             %
12
%                                                                             %
13
%                        Read/Write VIPS Image Format                         %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                Dirk Lemstra                                 %
17
%                                 April 2014                                  %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/license/                                         %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
*/
38

39
/*
40
  Include declarations.
41
*/
42
#include "MagickCore/studio.h"
43
#include "MagickCore/attribute.h"
44
#include "MagickCore/blob.h"
45
#include "MagickCore/blob-private.h"
46
#include "MagickCore/cache.h"
47
#include "MagickCore/colorspace.h"
48
#include "MagickCore/colorspace-private.h"
49
#include "MagickCore/exception.h"
50
#include "MagickCore/exception-private.h"
51
#include "MagickCore/image.h"
52
#include "MagickCore/image-private.h"
53
#include "MagickCore/list.h"
54
#include "MagickCore/magick.h"
55
#include "MagickCore/memory_.h"
56
#include "MagickCore/module.h"
57
#include "MagickCore/monitor.h"
58
#include "MagickCore/monitor-private.h"
59
#include "MagickCore/pixel-accessor.h"
60
#include "MagickCore/property.h"
61
#include "MagickCore/quantum-private.h"
62
#include "MagickCore/static.h"
63
#include "MagickCore/string_.h"
64
#include "coders/coders-private.h"
65
66
/*
67
  Define declarations.
68
*/
69
1.67k
#define VIPS_MAGIC_LSB 0x08f2a6b6U
70
770
#define VIPS_MAGIC_MSB 0xb6a6f208U
71
72
typedef enum
73
{
74
  VIPSBandFormatNOTSET    = -1,
75
  VIPSBandFormatUCHAR     = 0,  /* Unsigned 8-bit int */
76
  VIPSBandFormatCHAR      = 1,  /* Signed 8-bit int */
77
  VIPSBandFormatUSHORT    = 2,  /* Unsigned 16-bit int */
78
  VIPSBandFormatSHORT     = 3,  /* Signed 16-bit int */
79
  VIPSBandFormatUINT      = 4,  /* Unsigned 32-bit int */
80
  VIPSBandFormatINT       = 5,  /* Signed 32-bit int */
81
  VIPSBandFormatFLOAT     = 6,  /* 32-bit IEEE float */
82
  VIPSBandFormatCOMPLEX   = 7,  /* Complex (2 floats) */
83
  VIPSBandFormatDOUBLE    = 8,  /* 64-bit IEEE double */
84
  VIPSBandFormatDPCOMPLEX = 9   /* Complex (2 doubles) */
85
} VIPSBandFormat;
86
87
typedef enum
88
{
89
  VIPSCodingNONE  = 0,  /* VIPS computation format */
90
  VIPSCodingLABQ  = 2,  /* LABQ storage format */
91
  VIPSCodingRAD   = 6   /* Radiance storage format */
92
} VIPSCoding;
93
94
typedef enum
95
{
96
  VIPSTypeMULTIBAND = 0,   /* Some multiband image */
97
  VIPSTypeB_W       = 1,   /* Some single band image */
98
  VIPSTypeHISTOGRAM = 10,  /* Histogram or LUT */
99
  VIPSTypeFOURIER   = 24,  /* Image in Fourier space */
100
  VIPSTypeXYZ       = 12,  /* CIE XYZ color space */
101
  VIPSTypeLAB       = 13,  /* CIE LAB color space */
102
  VIPSTypeCMYK      = 15,  /* im_icc_export() */
103
  VIPSTypeLABQ      = 16,  /* 32-bit CIE LAB */
104
  VIPSTypeRGB       = 17,  /* Some RGB */
105
  VIPSTypeUCS       = 18,  /* UCS(1:1) color space */
106
  VIPSTypeLCH       = 19,  /* CIE LCh color space */
107
  VIPSTypeLABS      = 21,  /* 48-bit CIE LAB */
108
  VIPSTypesRGB      = 22,  /* sRGB color space */
109
  VIPSTypeYXY       = 23,  /* CIE Yxy color space */
110
  VIPSTypeRGB16     = 25,  /* 16-bit RGB */
111
  VIPSTypeGREY16    = 26   /* 16-bit monochrome */
112
} VIPSType;
113
114
/*
115
  Forward declarations.
116
*/
117
static MagickBooleanType
118
  WriteVIPSImage(const ImageInfo *,Image *,ExceptionInfo *);
119

120
/*
121
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122
%                                                                             %
123
%                                                                             %
124
%                                                                             %
125
%   I s V I P S                                                               %
126
%                                                                             %
127
%                                                                             %
128
%                                                                             %
129
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130
%
131
%  IsVIPS() returns MagickTrue if the image format type, identified by the
132
%  magick string, is VIPS.
133
%
134
%  The format of the IsVIPS method is:
135
%
136
%      MagickBooleanType IsVIPS(const unsigned char *magick,const size_t length)
137
%
138
%  A description of each parameter follows:
139
%
140
%    o magick: compare image format pattern against these bytes.
141
%
142
%    o length: Specifies the length of the magick string.
143
%
144
*/
145
static MagickBooleanType IsVIPS(const unsigned char *magick,const size_t length)
146
0
{
147
0
  if (length < 4)
148
0
    return(MagickFalse);
149
150
0
  if (memcmp(magick,"\010\362\246\266",4) == 0)
151
0
    return(MagickTrue);
152
153
0
  if (memcmp(magick,"\266\246\362\010",4) == 0)
154
0
    return(MagickTrue);
155
156
0
  return(MagickFalse);
157
0
}
158
159
/*
160
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161
%                                                                             %
162
%                                                                             %
163
%                                                                             %
164
%   R e a d V I P S I m a g e                                                 %
165
%                                                                             %
166
%                                                                             %
167
%                                                                             %
168
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169
%
170
%  ReadVIPSImage() reads a VIPS image file and returns it. It allocates the
171
%  memory necessary for the new Image structure and returns a pointer to the
172
%  new image.
173
%
174
%  The format of the ReadVIPSImage method is:
175
%
176
%      Image *ReadVIPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
177
%
178
%  A description of each parameter follows:
179
%
180
%    o image_info: the image info.
181
%
182
%    o exception: return any errors or warnings in this structure.
183
%
184
*/
185
186
static inline MagickBooleanType IsSupportedCombination(
187
  const VIPSBandFormat format,const VIPSType type)
188
894
{
189
894
  switch(type)
190
894
  {
191
243
    case VIPSTypeB_W:
192
404
    case VIPSTypeCMYK:
193
499
    case VIPSTypeRGB:
194
672
    case VIPSTypesRGB:
195
672
      return(MagickTrue);
196
105
    case VIPSTypeGREY16:
197
222
    case VIPSTypeRGB16:
198
222
      switch(format)
199
222
      {
200
43
        case VIPSBandFormatUSHORT:
201
75
        case VIPSBandFormatSHORT:
202
100
        case VIPSBandFormatUINT:
203
114
        case VIPSBandFormatINT:
204
163
        case VIPSBandFormatFLOAT:
205
210
        case VIPSBandFormatDOUBLE:
206
210
          return(MagickTrue);
207
12
        default:
208
12
          return(MagickFalse);
209
222
      }
210
0
    default:
211
0
      return(MagickFalse);
212
894
  }
213
894
}
214
215
static inline Quantum ReadVIPSPixelNONE(Image *image,
216
  const VIPSBandFormat format,const VIPSType type)
217
466M
{
218
466M
  switch(type)
219
466M
  {
220
62.6M
    case VIPSTypeB_W:
221
95.3M
    case VIPSTypeRGB:
222
95.3M
      {
223
95.3M
        unsigned char
224
95.3M
          c;
225
226
95.3M
        switch(format)
227
95.3M
        {
228
25.0M
          case VIPSBandFormatUCHAR:
229
31.0M
          case VIPSBandFormatCHAR:
230
31.0M
            c=(unsigned char) ReadBlobByte(image);
231
31.0M
            break;
232
5.55M
          case VIPSBandFormatUSHORT:
233
15.1M
          case VIPSBandFormatSHORT:
234
15.1M
            c=(unsigned char) ReadBlobShort(image);
235
15.1M
            break;
236
11.2M
          case VIPSBandFormatUINT:
237
12.7M
          case VIPSBandFormatINT:
238
12.7M
            c=(unsigned char) ReadBlobLong(image);
239
12.7M
            break;
240
7.54M
          case VIPSBandFormatFLOAT:
241
7.54M
            c=CastDoubleToUChar((double) ReadBlobFloat(image));
242
7.54M
            break;
243
28.9M
          case VIPSBandFormatDOUBLE:
244
28.9M
            c=CastDoubleToUChar(ReadBlobDouble(image));
245
28.9M
            break;
246
0
          default:
247
0
            c=0;
248
0
            break;
249
95.3M
        }
250
95.3M
        return(ScaleCharToQuantum(c));
251
95.3M
      }
252
103M
    case VIPSTypeGREY16:
253
153M
    case VIPSTypeRGB16:
254
153M
      {
255
153M
        unsigned short
256
153M
          s;
257
258
153M
        switch(format)
259
153M
        {
260
34.6M
          case VIPSBandFormatUSHORT:
261
71.9M
          case VIPSBandFormatSHORT:
262
71.9M
            s=(unsigned short) ReadBlobShort(image);
263
71.9M
            break;
264
37.7M
          case VIPSBandFormatUINT:
265
60.1M
          case VIPSBandFormatINT:
266
60.1M
            s=(unsigned short) ReadBlobLong(image);
267
60.1M
            break;
268
18.6M
          case VIPSBandFormatFLOAT:
269
18.6M
            s=CastDoubleToUShort((double) ReadBlobFloat(image));
270
18.6M
            break;
271
2.81M
          case VIPSBandFormatDOUBLE:
272
2.81M
            s=CastDoubleToUShort(ReadBlobDouble(image));
273
2.81M
            break;
274
0
          default:
275
0
            s=0;
276
0
            break;
277
153M
        }
278
153M
        return(ScaleShortToQuantum(s));
279
153M
      }
280
164M
    case VIPSTypeCMYK:
281
217M
    case VIPSTypesRGB:
282
217M
      switch(format)
283
217M
      {
284
49.3M
        case VIPSBandFormatUCHAR:
285
63.3M
        case VIPSBandFormatCHAR:
286
63.3M
          return(ScaleCharToQuantum((unsigned char) ReadBlobByte(image)));
287
56.3M
        case VIPSBandFormatUSHORT:
288
88.5M
        case VIPSBandFormatSHORT:
289
88.5M
          return(ScaleShortToQuantum(ReadBlobShort(image)));
290
12.7M
        case VIPSBandFormatUINT:
291
24.6M
        case VIPSBandFormatINT:
292
24.6M
          return(ScaleLongToQuantum(ReadBlobLong(image)));
293
12.3M
        case VIPSBandFormatFLOAT:
294
12.3M
          return((Quantum) ((double) QuantumRange*((double)
295
12.3M
            ReadBlobFloat(image)/1.0)));
296
28.7M
        case VIPSBandFormatDOUBLE:
297
28.7M
          return((Quantum) ((double) QuantumRange*(ReadBlobDouble(
298
28.7M
            image)/1.0)));
299
0
        default:
300
0
          return((Quantum) 0);
301
217M
      }
302
0
    default:
303
0
      return((Quantum) 0);
304
466M
  }
305
466M
}
306
307
static MagickBooleanType ReadVIPSPixelsNONE(Image *image,
308
  const VIPSBandFormat format,const VIPSType type,const unsigned int channels,
309
  ExceptionInfo *exception)
310
657
{
311
657
  Quantum
312
657
    pixel;
313
314
657
  Quantum
315
657
    *q;
316
317
657
  ssize_t
318
657
    x;
319
320
657
  ssize_t
321
657
    y;
322
323
217k
  for (y = 0; y < (ssize_t) image->rows; y++)
324
216k
  {
325
216k
    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
326
216k
    if (q == (Quantum *) NULL)
327
0
      return(MagickFalse);
328
167M
    for (x=0; x < (ssize_t) image->columns; x++)
329
167M
    {
330
167M
      pixel=ReadVIPSPixelNONE(image,format,type);
331
167M
      SetPixelRed(image,pixel,q);
332
167M
      if (channels < 3)
333
74.2M
        {
334
74.2M
          SetPixelGreen(image,pixel,q);
335
74.2M
          SetPixelBlue(image,pixel,q);
336
74.2M
          if (channels == 2)
337
35.2M
            SetPixelAlpha(image,ReadVIPSPixelNONE(image,format,type),q);
338
74.2M
        }
339
93.4M
      else
340
93.4M
        {
341
93.4M
          SetPixelGreen(image,ReadVIPSPixelNONE(image,format,type),q);
342
93.4M
          SetPixelBlue(image,ReadVIPSPixelNONE(image,format,type),q);
343
93.4M
          if (channels == 4)
344
29.8M
            {
345
29.8M
              if (image->colorspace == CMYKColorspace)
346
5.90M
                SetPixelIndex(image,ReadVIPSPixelNONE(image,format,type),q);
347
23.9M
              else
348
23.9M
                SetPixelAlpha(image,ReadVIPSPixelNONE(image,format,type),q);
349
29.8M
            }
350
63.5M
          else
351
63.5M
            if (channels == 5)
352
23.4M
              {
353
23.4M
                SetPixelIndex(image,ReadVIPSPixelNONE(image,format,type),q);
354
23.4M
                SetPixelAlpha(image,ReadVIPSPixelNONE(image,format,type),q);
355
23.4M
              }
356
93.4M
        }
357
167M
      q+=(ptrdiff_t) GetPixelChannels(image);
358
167M
    }
359
216k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
360
0
      return(MagickFalse);
361
216k
  }
362
657
  return(MagickTrue);
363
657
}
364
365
static Image *ReadVIPSImage(const ImageInfo *image_info,
366
  ExceptionInfo *exception)
367
1.24k
{
368
1.24k
  char
369
1.24k
    buffer[MagickPathExtent],
370
1.24k
    *metadata;
371
372
1.24k
  Image
373
1.24k
    *image;
374
375
1.24k
  MagickBooleanType
376
1.24k
    status;
377
378
1.24k
  ssize_t
379
1.24k
    n;
380
381
1.24k
  unsigned int
382
1.24k
    channels,
383
1.24k
    marker;
384
385
1.24k
  VIPSBandFormat
386
1.24k
    format;
387
388
1.24k
  VIPSCoding
389
1.24k
    coding;
390
391
1.24k
  VIPSType
392
1.24k
    type;
393
394
1.24k
  assert(image_info != (const ImageInfo *) NULL);
395
1.24k
  assert(image_info->signature == MagickCoreSignature);
396
1.24k
  assert(exception != (ExceptionInfo *) NULL);
397
1.24k
  assert(exception->signature == MagickCoreSignature);
398
1.24k
  if (IsEventLogging() != MagickFalse)
399
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
400
0
      image_info->filename);
401
1.24k
  image=AcquireImage(image_info,exception);
402
1.24k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
403
1.24k
  if (status == MagickFalse)
404
0
    {
405
0
      image=DestroyImageList(image);
406
0
      return((Image *) NULL);
407
0
    }
408
1.24k
  marker=ReadBlobLSBLong(image);
409
1.24k
  if (marker == VIPS_MAGIC_LSB)
410
707
    image->endian=LSBEndian;
411
541
  else
412
541
    if (marker == VIPS_MAGIC_MSB)
413
448
      image->endian=MSBEndian;
414
93
    else
415
1.15k
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
416
1.15k
  image->columns=(size_t) ReadBlobLong(image);
417
1.15k
  image->rows=(size_t) ReadBlobLong(image);
418
1.15k
  status=SetImageExtent(image,image->columns,image->rows,exception);
419
1.15k
  if (status == MagickFalse)
420
160
    return(DestroyImageList(image));
421
995
  channels=ReadBlobLong(image);
422
995
  (void) ReadBlobLong(image); /* Legacy */
423
995
  format=(VIPSBandFormat) ReadBlobLong(image);
424
995
  switch(format)
425
995
  {
426
261
    case VIPSBandFormatUCHAR:
427
339
    case VIPSBandFormatCHAR:
428
339
      image->depth=8;
429
339
      break;
430
120
    case VIPSBandFormatUSHORT:
431
219
    case VIPSBandFormatSHORT:
432
219
      image->depth=16;
433
219
      break;
434
51
    case VIPSBandFormatUINT:
435
102
    case VIPSBandFormatINT:
436
275
    case VIPSBandFormatFLOAT:
437
275
      image->depth=32;
438
275
      break;
439
119
    case VIPSBandFormatDOUBLE:
440
119
      image->depth=64;
441
119
      break;
442
41
    default:
443
42
    case VIPSBandFormatCOMPLEX:
444
42
    case VIPSBandFormatDPCOMPLEX:
445
43
    case VIPSBandFormatNOTSET:
446
43
      ThrowReaderException(CoderError,"Unsupported band format");
447
995
  }
448
952
  coding=(VIPSCoding) ReadBlobLong(image);
449
952
  type=(VIPSType) ReadBlobLong(image);
450
952
  switch(type)
451
952
  {
452
163
    case VIPSTypeCMYK:
453
163
      SetImageColorspace(image,CMYKColorspace,exception);
454
163
      if (channels == 5)
455
19
        image->alpha_trait=BlendPixelTrait;
456
163
      break;
457
245
    case VIPSTypeB_W:
458
351
    case VIPSTypeGREY16:
459
351
      SetImageColorspace(image,GRAYColorspace,exception);
460
351
      if (channels == 2)
461
100
        image->alpha_trait=BlendPixelTrait;
462
351
      break;
463
95
    case VIPSTypeRGB:
464
214
    case VIPSTypeRGB16:
465
214
      SetImageColorspace(image,RGBColorspace,exception);
466
214
      if (channels == 4)
467
54
        image->alpha_trait=BlendPixelTrait;
468
214
      break;
469
173
    case VIPSTypesRGB:
470
173
      SetImageColorspace(image,sRGBColorspace,exception);
471
173
      if (channels == 4)
472
61
        image->alpha_trait=BlendPixelTrait;
473
173
      break;
474
2
    default:
475
2
    case VIPSTypeFOURIER:
476
2
    case VIPSTypeHISTOGRAM:
477
2
    case VIPSTypeLAB:
478
2
    case VIPSTypeLABS:
479
2
    case VIPSTypeLABQ:
480
2
    case VIPSTypeLCH:
481
51
    case VIPSTypeMULTIBAND:
482
51
    case VIPSTypeUCS:
483
51
    case VIPSTypeXYZ:
484
51
    case VIPSTypeYXY:
485
51
      ThrowReaderException(CoderError,"Unsupported colorspace");
486
952
  }
487
901
  (void) SetImageBackgroundColor(image,exception);
488
901
  image->units=PixelsPerCentimeterResolution;
489
901
  image->resolution.x=ReadBlobFloat(image)*10;
490
901
  image->resolution.y=ReadBlobFloat(image)*10;
491
  /*
492
    Legacy, offsets, future
493
  */
494
901
  (void) ReadBlobLongLong(image);
495
901
  (void) ReadBlobLongLong(image);
496
901
  (void) ReadBlobLongLong(image);
497
901
  if (image_info->ping != MagickFalse)
498
7
    return(image);
499
894
  if (IsSupportedCombination(format,type) == MagickFalse)
500
12
    ThrowReaderException(CoderError,
501
894
      "Unsupported combination of band format and colorspace");
502
882
  if (channels == 0 || channels > 5)
503
698
    ThrowReaderException(CoderError,"Unsupported number of channels");
504
698
  if (coding == VIPSCodingNONE)
505
657
    status=ReadVIPSPixelsNONE(image,format,type,channels,exception);
506
41
  else
507
657
    ThrowReaderException(CoderError,"Unsupported coding");
508
657
  metadata=(char *) NULL;
509
768
  while ((n=ReadBlob(image,MagickPathExtent-1,(unsigned char *) buffer)) != 0)
510
111
  {
511
111
    buffer[n]='\0';
512
111
    if (metadata == (char *) NULL)
513
79
      metadata=ConstantString(buffer);
514
32
    else
515
32
      (void) ConcatenateString(&metadata,buffer);
516
111
  }
517
657
  if (metadata != (char *) NULL)
518
79
    {
519
79
      SetImageProperty(image,"vips:metadata",metadata,exception);
520
79
      metadata=(char *) RelinquishMagickMemory(metadata);
521
79
    }
522
657
  if (CloseBlob(image) == MagickFalse)
523
0
    status=MagickFalse;
524
657
  if (status == MagickFalse)
525
0
    return((Image *) NULL);
526
657
  return(image);
527
657
}
528

529
/*
530
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
531
%                                                                             %
532
%                                                                             %
533
%                                                                             %
534
%   R e g i s t e r V I P S I m a g e                                         %
535
%                                                                             %
536
%                                                                             %
537
%                                                                             %
538
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539
%
540
%  RegisterVIPSImage() adds attributes for the VIPS image format to the list
541
%  of supported formats.  The attributes include the image format tag, a
542
%  method to read and/or write the format, whether the format supports the
543
%  saving of more than one frame to the same file or blob, whether the format
544
%  supports native in-memory I/O, and a brief description of the format.
545
%
546
%  The format of the RegisterVIPSImage method is:
547
%
548
%      size_t RegisterVIPSImage(void)
549
%
550
*/
551
ModuleExport size_t RegisterVIPSImage(void)
552
10
{
553
10
  MagickInfo
554
10
    *entry;
555
556
10
  entry=AcquireMagickInfo("VIPS","VIPS","VIPS image");
557
10
  entry->decoder=(DecodeImageHandler *) ReadVIPSImage;
558
10
  entry->encoder=(EncodeImageHandler *) WriteVIPSImage;
559
10
  entry->magick=(IsImageFormatHandler *) IsVIPS;
560
10
  entry->flags|=CoderEndianSupportFlag;
561
10
  (void) RegisterMagickInfo(entry);
562
10
  return(MagickImageCoderSignature);
563
10
}
564

565
/*
566
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
567
%                                                                             %
568
%                                                                             %
569
%                                                                             %
570
%   U n r e g i s t e r V I P S I m a g e                                     %
571
%                                                                             %
572
%                                                                             %
573
%                                                                             %
574
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575
%
576
%  UnregisterVIPSImage() removes format registrations made by the
577
%  VIPS module from the list of supported formats.
578
%
579
%  The format of the UnregisterVIPSImage method is:
580
%
581
%      UnregisterVIPSImage(void)
582
%
583
*/
584
ModuleExport void UnregisterVIPSImage(void)
585
0
{
586
0
  (void) UnregisterMagickInfo("VIPS");
587
0
}
588

589
/*
590
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
591
%                                                                             %
592
%                                                                             %
593
%                                                                             %
594
%   W r i t e V I P S I m a g e                                               %
595
%                                                                             %
596
%                                                                             %
597
%                                                                             %
598
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599
%
600
%  WriteVIPSImage() writes an image to a file in VIPS image format.
601
%
602
%  The format of the WriteVIPSImage method is:
603
%
604
%      MagickBooleanType WriteVIPSImage(const ImageInfo *image_info,Image *image)
605
%
606
%  A description of each parameter follows.
607
%
608
%    o image_info: the image info.
609
%
610
%    o image:  The image.
611
%
612
*/
613
614
static inline void WriteVIPSPixel(Image *image,const Quantum value)
615
402M
{
616
402M
  if (image->depth == 16)
617
191M
    (void) WriteBlobShort(image,ScaleQuantumToShort(value));
618
210M
  else
619
210M
    (void) WriteBlobByte(image,ScaleQuantumToChar(value));
620
402M
}
621
622
static MagickBooleanType WriteVIPSImage(const ImageInfo *image_info,
623
  Image *image,ExceptionInfo *exception)
624
657
{
625
657
  const char
626
657
    *metadata;
627
628
657
  const Quantum
629
657
    *p;
630
631
657
  MagickBooleanType
632
657
    status;
633
634
657
  ssize_t
635
657
    x;
636
637
657
  ssize_t
638
657
    y;
639
640
657
  unsigned int
641
657
    channels;
642
643
657
  assert(image_info != (const ImageInfo *) NULL);
644
657
  assert(image_info->signature == MagickCoreSignature);
645
657
  assert(image != (Image *) NULL);
646
657
  assert(image->signature == MagickCoreSignature);
647
657
  if (IsEventLogging() != MagickFalse)
648
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
649
657
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
650
657
  if (status == MagickFalse)
651
0
    return(status);
652
657
  if (image->endian == LSBEndian)
653
428
    (void) WriteBlobLSBLong(image,VIPS_MAGIC_LSB);
654
229
  else
655
229
    (void) WriteBlobLSBLong(image,VIPS_MAGIC_MSB);
656
657
  (void) WriteBlobLong(image,(unsigned int) image->columns);
657
657
  (void) WriteBlobLong(image,(unsigned int) image->rows);
658
657
  (void) SetImageStorageClass(image,DirectClass,exception);
659
657
  channels=image->alpha_trait != UndefinedPixelTrait ? 4 : 3;
660
657
  if (IdentifyImageCoderGray(image,exception) != MagickFalse)
661
461
    {
662
461
      channels=image->alpha_trait != UndefinedPixelTrait ? 2 : 1;
663
461
      (void) SetImageColorspace(image,GRAYColorspace,exception);
664
461
    }
665
196
  else
666
196
    if (image->colorspace == CMYKColorspace)
667
104
      channels=image->alpha_trait != UndefinedPixelTrait ? 5 : 4;
668
657
  (void) WriteBlobLong(image,channels);
669
657
  (void) WriteBlobLong(image,0);
670
657
  if (image->depth == 16)
671
154
    (void) WriteBlobLong(image,(unsigned int) VIPSBandFormatUSHORT);
672
503
  else
673
503
    {
674
503
      image->depth=8;
675
503
      (void) WriteBlobLong(image,(unsigned int) VIPSBandFormatUCHAR);
676
503
    }
677
657
  (void) WriteBlobLong(image,VIPSCodingNONE);
678
657
  switch (image->colorspace)
679
657
  {
680
104
    case CMYKColorspace:
681
104
      (void) WriteBlobLong(image,VIPSTypeCMYK);
682
104
      break;
683
461
    case GRAYColorspace:
684
461
      if (image->depth == 16)
685
83
        (void) WriteBlobLong(image,VIPSTypeGREY16);
686
378
      else
687
378
        (void) WriteBlobLong(image,VIPSTypeB_W);
688
461
      break;
689
0
    case LabColorspace:
690
0
      (void) WriteBlobLong(image,VIPSTypeLAB);
691
0
      break;
692
0
    case LCHColorspace:
693
0
      (void) WriteBlobLong(image,VIPSTypeLCH);
694
0
      break;
695
48
    case RGBColorspace:
696
48
      if (image->depth == 16)
697
17
        (void) WriteBlobLong(image,VIPSTypeRGB16);
698
31
      else
699
31
        (void) WriteBlobLong(image,VIPSTypeRGB);
700
48
      break;
701
0
    case XYZColorspace:
702
0
      (void) WriteBlobLong(image,VIPSTypeXYZ);
703
0
      break;
704
44
    case sRGBColorspace:
705
44
    default:
706
44
      (void) SetImageColorspace(image,sRGBColorspace,exception);
707
44
      (void) WriteBlobLong(image,VIPSTypesRGB);
708
44
      break;
709
657
  }
710
657
  if (image->units == PixelsPerCentimeterResolution)
711
657
    {
712
657
      (void) WriteBlobFloat(image,(float) (image->resolution.x/10));
713
657
      (void) WriteBlobFloat(image,(float) (image->resolution.y/10));
714
657
    }
715
0
  else
716
0
    if (image->units == PixelsPerInchResolution)
717
0
      {
718
0
        (void) WriteBlobFloat(image,(float) (image->resolution.x/25.4));
719
0
        (void) WriteBlobFloat(image,(float) (image->resolution.y/25.4));
720
0
      }
721
0
    else
722
0
      {
723
0
        (void) WriteBlobLong(image,0);
724
0
        (void) WriteBlobLong(image,0);
725
0
      }
726
  /*
727
    Legacy, offsets, future.
728
  */
729
16.4k
  for (y=0; y < 24; y++)
730
15.7k
    (void) WriteBlobByte(image,0);
731
217k
  for (y=0; y < (ssize_t) image->rows; y++)
732
216k
  {
733
216k
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
734
216k
    if (p == (const Quantum *) NULL)
735
0
      break;
736
167M
    for (x=0; x < (ssize_t) image->columns; x++)
737
167M
    {
738
167M
      WriteVIPSPixel(image,GetPixelRed(image,p));
739
167M
      if (channels == 2)
740
28.9M
        WriteVIPSPixel(image,GetPixelAlpha(image,p));
741
138M
      else
742
138M
        {
743
138M
          if (channels >= 3)
744
69.8M
            {
745
69.8M
              WriteVIPSPixel(image,GetPixelGreen(image,p));
746
69.8M
              WriteVIPSPixel(image,GetPixelBlue(image,p));
747
69.8M
            }
748
138M
          if (channels >= 4)
749
65.9M
            {
750
65.9M
              if (image->colorspace == CMYKColorspace)
751
61.0M
                WriteVIPSPixel(image,GetPixelIndex(image,p));
752
4.84M
              else
753
4.84M
                WriteVIPSPixel(image,GetPixelAlpha(image,p));
754
65.9M
            }
755
72.7M
          else
756
72.7M
            if (channels == 5)
757
0
              {
758
0
                WriteVIPSPixel(image,GetPixelIndex(image,p));
759
0
                WriteVIPSPixel(image,GetPixelAlpha(image,p));
760
0
              }
761
138M
        }
762
167M
      p+=(ptrdiff_t) GetPixelChannels(image);
763
167M
    }
764
216k
  }
765
657
  metadata=GetImageProperty(image,"vips:metadata",exception);
766
657
  if (metadata != (const char*) NULL)
767
79
    WriteBlobString(image,metadata);
768
657
  if (CloseBlob(image) == MagickFalse)
769
0
    status=MagickFalse;
770
657
  return(status);
771
657
}