/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 | } |