1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % %
7 % FFFFF AAA RRRR BBBB FFFFF EEEEE L DDDD %
8 % F A A R R B B F E L D D %
9 % FFF AAAAA RRRR BBBB FFF EEE L D D %
10 % F A A R R B B F E L D D %
11 % F A A R R BBBB F EEEEE LLLLL DDDD %
12 % %
13 % %
14 % Support Farbfeld Image Format %
15 % %
16 % Software Design %
17 % Dirk Lemstra %
18 % November 2020 %
19 % %
20 % %
21 % Copyright 1999-2021 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/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/attribute.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/blob-private.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colormap.h"
50 #include "MagickCore/colorspace.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/quantum-private.h"
62 #include "MagickCore/static.h"
63 #include "MagickCore/string_.h"
64 #include "MagickCore/module.h"
65
66 /*
67 Forward declarations.
68 */
69 static MagickBooleanType
70 WriteFARBFELDImage(const ImageInfo *,Image *,ExceptionInfo *);
71
72 /*
73 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74 % %
75 % %
76 % %
77 % I s F A R B F E L D %
78 % %
79 % %
80 % %
81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82 %
83 % IsFARBFELD() returns MagickTrue if the image format type, identified by the
84 % magick string, is Farbeld.
85 %
86 % The format of the IsFarbeld method is:
87 %
88 % MagickBooleanType IsFARBFELD(const unsigned char *magick,
89 % const size_t extent)
90 %
91 % A description of each parameter follows:
92 %
93 % o magick: compare image format pattern against these bytes.
94 %
95 % o extent: Specifies the extent of the magick string.
96 %
97 */
IsFARBFELD(const unsigned char * magick,const size_t extent)98 static MagickBooleanType IsFARBFELD(const unsigned char *magick,
99 const size_t extent)
100 {
101 if (extent < 8)
102 return(MagickFalse);
103 if (LocaleNCompare((char *) magick,"farbfeld",8) == 0)
104 return(MagickTrue);
105 return(MagickFalse);
106 }
107
108 /*
109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 % %
111 % %
112 % %
113 % R e a d F A R B F E L D I m a g e %
114 % %
115 % %
116 % %
117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118 %
119 % ReadFARBFELDImage() reads an image of raw bits in LSB order and returns it.
120 % It allocates the memory necessary for the new Image structure and returns
121 % a pointer to the new image.
122 %
123 % The format of the ReadFARBFELDImage method is:
124 %
125 % Image *ReadFARBFELDImage(const ImageInfo *image_info,
126 % ExceptionInfo *exception)
127 %
128 % A description of each parameter follows:
129 %
130 % o image_info: the image info.
131 %
132 % o exception: return any errors or warnings in this structure.
133 %
134 */
ReadFARBFELDImage(const ImageInfo * image_info,ExceptionInfo * exception)135 static Image *ReadFARBFELDImage(const ImageInfo *image_info,
136 ExceptionInfo *exception)
137 {
138 Image
139 *image;
140
141 QuantumInfo
142 *quantum_info;
143
144 MagickBooleanType
145 status;
146
147 MagickSizeType
148 magic;
149
150 size_t
151 extent;
152
153 ssize_t
154 count,
155 y;
156
157 unsigned char
158 *pixels;
159
160 /*
161 Open image file.
162 */
163 assert(image_info != (const ImageInfo *) NULL);
164 assert(image_info->signature == MagickCoreSignature);
165 if (image_info->debug != MagickFalse)
166 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
167 image_info->filename);
168 assert(exception != (ExceptionInfo *) NULL);
169 assert(exception->signature == MagickCoreSignature);
170 image=AcquireImage(image_info,exception);
171 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
172 if (status == MagickFalse)
173 {
174 image=DestroyImageList(image);
175 return((Image *) NULL);
176 }
177 image->depth=16;
178 image->endian=MSBEndian;
179 magic=ReadBlobLongLong(image);
180 if (magic != MagickULLConstant(7377303431559867492))
181 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
182 image->columns=(size_t) ReadBlobLong(image);
183 image->rows=(size_t) ReadBlobLong(image);
184 image->alpha_trait=BlendPixelTrait;
185 if (image_info->ping != MagickFalse)
186 {
187 (void) CloseBlob(image);
188 return(GetFirstImageInList(image));
189 }
190 status=SetImageExtent(image,image->columns,image->rows,exception);
191 if (status == MagickFalse)
192 return(DestroyImageList(image));
193 quantum_info=AcquireQuantumInfo(image_info,image);
194 if (quantum_info == (QuantumInfo *) NULL)
195 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
196 status=SetQuantumFormat(image,quantum_info,UnsignedQuantumFormat);
197 extent=GetQuantumExtent(image,quantum_info,RGBAQuantum);
198 pixels=GetQuantumPixels(quantum_info);
199 for (y=0; y < (ssize_t) image->rows; y++)
200 {
201 const void
202 *stream;
203
204 Quantum
205 *magick_restrict q;
206
207 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
208 if (q == (Quantum *) NULL)
209 break;
210 stream=ReadBlobStream(image,extent,pixels,&count);
211 if (count != (ssize_t) extent)
212 break;
213 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
214 RGBAQuantum,(unsigned char *) stream,exception);
215 if (SyncAuthenticPixels(image,exception) == MagickFalse)
216 break;
217 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
218 break;
219 }
220 SetQuantumImageType(image,RGBAQuantum);
221 quantum_info=DestroyQuantumInfo(quantum_info);
222 if (y < (ssize_t) image->rows)
223 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
224 if (EOFBlob(image) != MagickFalse)
225 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
226 image->filename);
227 (void) CloseBlob(image);
228 return(GetFirstImageInList(image));
229 }
230
231 /*
232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % %
234 % %
235 % %
236 % R e g i s t e r F A R B F E L D I m a g e %
237 % %
238 % %
239 % %
240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241 %
242 % RegisterFARBFELDImage() adds attributes for the FARBFELD image format to
243 % the list of supported formats. The attributes include the image format
244 % tag, a method to read and/or write the format, whether the format
245 % supports the saving of more than one frame to the same file or blob,
246 % whether the format supports native in-memory I/O, and a brief
247 % description of the format.
248 %
249 % The format of the RegisterFARBFELDImage method is:
250 %
251 % size_t RegisterFARBFELDImage(void)
252 %
253 */
RegisterFARBFELDImage(void)254 ModuleExport size_t RegisterFARBFELDImage(void)
255 {
256 MagickInfo
257 *entry;
258
259 entry=AcquireMagickInfo("FARBFELD","FARBFELD","Farbfeld");
260 entry->decoder=(DecodeImageHandler *) ReadFARBFELDImage;
261 entry->encoder=(EncodeImageHandler *) WriteFARBFELDImage;
262 entry->magick=(IsImageFormatHandler *) IsFARBFELD;
263 entry->flags|=CoderRawSupportFlag;
264 entry->flags^=CoderAdjoinFlag;
265 (void) RegisterMagickInfo(entry);
266 entry=AcquireMagickInfo("FARBFELD","FF","Farbfeld");
267 entry->decoder=(DecodeImageHandler *) ReadFARBFELDImage;
268 entry->encoder=(EncodeImageHandler *) WriteFARBFELDImage;
269 entry->magick=(IsImageFormatHandler *) IsFARBFELD;
270 entry->flags|=CoderRawSupportFlag;
271 entry->flags^=CoderAdjoinFlag;
272 (void) RegisterMagickInfo(entry);
273 return(MagickImageCoderSignature);
274 }
275
276 /*
277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278 % %
279 % %
280 % %
281 % U n r e g i s t e r F A R B F E L D I m a g e %
282 % %
283 % %
284 % %
285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 %
287 % UnregisterFARBFELDImage() removes format registrations made by the
288 % Farbfeld module from the list of supported formats.
289 %
290 % The format of the UnregisterFARBFELDImage method is:
291 %
292 % UnregisterFARBFELDImage(void)
293 %
294 */
UnregisterFARBFELDImage(void)295 ModuleExport void UnregisterFARBFELDImage(void)
296 {
297 (void) UnregisterMagickInfo("FARBFELD");
298 }
299
300 /*
301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
302 % %
303 % %
304 % %
305 % W r i t e F A R B F E L D I m a g e %
306 % %
307 % %
308 % %
309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310 %
311 % WriteFARBFELDImage() writes an image of raw bits in MSB order to a file.
312 %
313 % The format of the WriteFARBFELDImage method is:
314 %
315 % MagickBooleanType WriteFARBFELDImage(const ImageInfo *image_info,
316 % Image *image,ExceptionInfo *exception)
317 %
318 % A description of each parameter follows.
319 %
320 % o image_info: the image info.
321 %
322 % o image: The image.
323 %
324 % o exception: return any errors or warnings in this structure.
325 %
326 */
WriteFARBFELDImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)327 static MagickBooleanType WriteFARBFELDImage(const ImageInfo *image_info,
328 Image *image,ExceptionInfo *exception)
329 {
330 MagickBooleanType
331 status;
332
333 QuantumInfo
334 *quantum_info;
335
336 const Quantum
337 *p;
338
339 size_t
340 extent;
341
342 ssize_t
343 count,
344 y;
345
346 unsigned char
347 *pixels;
348
349 /*
350 Open output image file.
351 */
352 assert(image_info != (const ImageInfo *) NULL);
353 assert(image_info->signature == MagickCoreSignature);
354 assert(image != (Image *) NULL);
355 assert(image->signature == MagickCoreSignature);
356 if (image->debug != MagickFalse)
357 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
358 assert(exception != (ExceptionInfo *) NULL);
359 assert(exception->signature == MagickCoreSignature);
360 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
361 if (status == MagickFalse)
362 return(status);
363 image->endian=MSBEndian;
364 (void) WriteBlobLongLong(image,MagickULLConstant(7377303431559867492));
365 (void) WriteBlobLong(image,(unsigned int) image->columns);
366 (void) WriteBlobLong(image,(unsigned int) image->rows);
367 image->depth=16;
368 quantum_info=AcquireQuantumInfo(image_info,image);
369 if (quantum_info == (QuantumInfo *) NULL)
370 ThrowWriterException(ImageError,"MemoryAllocationFailed");
371 status=SetQuantumFormat(image,quantum_info,UnsignedQuantumFormat);
372 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
373 for (y=0; y < (ssize_t) image->rows; y++)
374 {
375 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
376 if (p == (const Quantum *) NULL)
377 break;
378 extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
379 RGBAQuantum,pixels,exception);
380 count=WriteBlob(image,extent,pixels);
381 if (count != (ssize_t) extent)
382 break;
383 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
384 image->rows);
385 if (status == MagickFalse)
386 break;
387 }
388 quantum_info=DestroyQuantumInfo(quantum_info);
389 if (y < (ssize_t) image->rows)
390 ThrowWriterException(CorruptImageError,"UnableToWriteImageData");
391 (void) CloseBlob(image);
392 return(status);
393 }
394