/src/imagemagick/coders/vicar.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % V V IIIII CCCC AAA RRRR % |
7 | | % V V I C A A R R % |
8 | | % V V I C AAAAA RRRR % |
9 | | % V V I C A A R R % |
10 | | % V IIIII CCCC A A R R % |
11 | | % % |
12 | | % % |
13 | | % Read/Write VICAR Rasterfile Format % |
14 | | % % |
15 | | % Software Design % |
16 | | % Cristy % |
17 | | % July 1992 % |
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/colormap.h" |
48 | | #include "MagickCore/colorspace.h" |
49 | | #include "MagickCore/colorspace-private.h" |
50 | | #include "MagickCore/constitute.h" |
51 | | #include "MagickCore/exception.h" |
52 | | #include "MagickCore/exception-private.h" |
53 | | #include "MagickCore/image.h" |
54 | | #include "MagickCore/image-private.h" |
55 | | #include "MagickCore/list.h" |
56 | | #include "MagickCore/locale_.h" |
57 | | #include "MagickCore/magick.h" |
58 | | #include "MagickCore/memory_.h" |
59 | | #include "MagickCore/module.h" |
60 | | #include "MagickCore/monitor.h" |
61 | | #include "MagickCore/monitor-private.h" |
62 | | #include "MagickCore/property.h" |
63 | | #include "MagickCore/quantum-private.h" |
64 | | #include "MagickCore/quantum-private.h" |
65 | | #include "MagickCore/static.h" |
66 | | #include "MagickCore/string_.h" |
67 | | #include "MagickCore/string-private.h" |
68 | | |
69 | | /* |
70 | | Forward declarations. |
71 | | */ |
72 | | static MagickBooleanType |
73 | | WriteVICARImage(const ImageInfo *,Image *,ExceptionInfo *); |
74 | | |
75 | | /* |
76 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
77 | | % % |
78 | | % % |
79 | | % % |
80 | | % I s V I C A R % |
81 | | % % |
82 | | % % |
83 | | % % |
84 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
85 | | % |
86 | | % IsVICAR() returns MagickTrue if the image format type, identified by the |
87 | | % magick string, is VICAR. |
88 | | % |
89 | | % The format of the IsVICAR method is: |
90 | | % |
91 | | % MagickBooleanType IsVICAR(const unsigned char *magick, |
92 | | % const size_t length) |
93 | | % |
94 | | % A description of each parameter follows: |
95 | | % |
96 | | % o magick: compare image format pattern against these bytes. |
97 | | % |
98 | | % o length: Specifies the length of the magick string. |
99 | | % |
100 | | */ |
101 | | static MagickBooleanType IsVICAR(const unsigned char *magick, |
102 | | const size_t length) |
103 | 0 | { |
104 | 0 | if (length < 14) |
105 | 0 | return(MagickFalse); |
106 | 0 | if (LocaleNCompare((const char *) magick,"LBLSIZE",7) == 0) |
107 | 0 | return(MagickTrue); |
108 | 0 | if (LocaleNCompare((const char *) magick,"NJPL1I",6) == 0) |
109 | 0 | return(MagickTrue); |
110 | 0 | if (LocaleNCompare((const char *) magick,"PDS_VERSION_ID",14) == 0) |
111 | 0 | return(MagickTrue); |
112 | 0 | return(MagickFalse); |
113 | 0 | } |
114 | | |
115 | | /* |
116 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
117 | | % % |
118 | | % % |
119 | | % % |
120 | | % R e a d V I C A R I m a g e % |
121 | | % % |
122 | | % % |
123 | | % % |
124 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
125 | | % |
126 | | % ReadVICARImage() reads a VICAR image file and returns it. It |
127 | | % allocates the memory necessary for the new Image structure and returns a |
128 | | % pointer to the new image. |
129 | | % |
130 | | % The format of the ReadVICARImage method is: |
131 | | % |
132 | | % Image *ReadVICARImage(const ImageInfo *image_info, |
133 | | % ExceptionInfo *exception) |
134 | | % |
135 | | % A description of each parameter follows: |
136 | | % |
137 | | % o image: Method ReadVICARImage returns a pointer to the image after |
138 | | % reading. A null image is returned if there is a memory shortage or if |
139 | | % the image cannot be read. |
140 | | % |
141 | | % o image_info: the image info. |
142 | | % |
143 | | % o exception: return any errors or warnings in this structure. |
144 | | % |
145 | | % |
146 | | */ |
147 | | static Image *ReadVICARImage(const ImageInfo *image_info, |
148 | | ExceptionInfo *exception) |
149 | 2.02k | { |
150 | 2.02k | char |
151 | 2.02k | format[MagickPathExtent] = "byte", |
152 | 2.02k | keyword[MagickPathExtent], |
153 | 2.02k | value[MagickPathExtent]; |
154 | | |
155 | 2.02k | Image |
156 | 2.02k | *image; |
157 | | |
158 | 2.02k | int |
159 | 2.02k | c; |
160 | | |
161 | 2.02k | MagickBooleanType |
162 | 2.02k | status, |
163 | 2.02k | value_expected; |
164 | | |
165 | 2.02k | QuantumInfo |
166 | 2.02k | *quantum_info; |
167 | | |
168 | 2.02k | QuantumType |
169 | 2.02k | quantum_type; |
170 | | |
171 | 2.02k | Quantum |
172 | 2.02k | *q; |
173 | | |
174 | 2.02k | size_t |
175 | 2.02k | length, |
176 | 2.02k | number_pixels; |
177 | | |
178 | 2.02k | ssize_t |
179 | 2.02k | count, |
180 | 2.02k | y; |
181 | | |
182 | 2.02k | unsigned char |
183 | 2.02k | *pixels; |
184 | | |
185 | | /* |
186 | | Open image file. |
187 | | */ |
188 | 2.02k | assert(image_info != (const ImageInfo *) NULL); |
189 | 2.02k | assert(image_info->signature == MagickCoreSignature); |
190 | 2.02k | assert(exception != (ExceptionInfo *) NULL); |
191 | 2.02k | assert(exception->signature == MagickCoreSignature); |
192 | 2.02k | if (IsEventLogging() != MagickFalse) |
193 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
194 | 0 | image_info->filename); |
195 | 2.02k | image=AcquireImage(image_info,exception); |
196 | 2.02k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
197 | 2.02k | if (status == MagickFalse) |
198 | 0 | { |
199 | 0 | image=DestroyImageList(image); |
200 | 0 | return((Image *) NULL); |
201 | 0 | } |
202 | | /* |
203 | | Decode image header. |
204 | | */ |
205 | 2.02k | c=ReadBlobByte(image); |
206 | 2.02k | count=1; |
207 | 2.02k | if (c == EOF) |
208 | 0 | { |
209 | 0 | image=DestroyImage(image); |
210 | 0 | return((Image *) NULL); |
211 | 0 | } |
212 | 2.02k | length=0; |
213 | 2.02k | image->columns=0; |
214 | 2.02k | image->rows=0; |
215 | 55.0k | while ((isgraph((int) ((unsigned char) c)) != 0) && |
216 | 54.5k | ((image->columns == 0) || (image->rows == 0))) |
217 | 54.2k | { |
218 | 54.2k | if (isalnum((int) ((unsigned char) c)) == 0) |
219 | 26.5k | { |
220 | 26.5k | c=ReadBlobByte(image); |
221 | 26.5k | count++; |
222 | 26.5k | } |
223 | 27.7k | else |
224 | 27.7k | { |
225 | 27.7k | MagickOffsetType |
226 | 27.7k | offset; |
227 | | |
228 | 27.7k | char |
229 | 27.7k | *p, |
230 | 27.7k | property[MagickPathExtent]; |
231 | | |
232 | | /* |
233 | | Determine a keyword and its value. |
234 | | */ |
235 | 27.7k | offset=TellBlob(image)-1; |
236 | 27.7k | p=keyword; |
237 | 27.7k | do |
238 | 221k | { |
239 | 221k | if ((size_t) (p-keyword) < (MagickPathExtent-1)) |
240 | 216k | *p++=(char) c; |
241 | 221k | c=ReadBlobByte(image); |
242 | 221k | if (c == EOF) |
243 | 85 | break; |
244 | 220k | count++; |
245 | 220k | } while (isalnum((int) ((unsigned char) c)) || (c == '_')); |
246 | 27.7k | *p='\0'; |
247 | 27.7k | value_expected=MagickFalse; |
248 | 55.9k | while ((isspace((int) ((unsigned char) c)) != 0) || (c == '=')) |
249 | 28.5k | { |
250 | 28.5k | if (c == '=') |
251 | 25.0k | value_expected=MagickTrue; |
252 | 28.5k | c=ReadBlobByte(image); |
253 | 28.5k | if (c == EOF) |
254 | 286 | break; |
255 | 28.2k | count++; |
256 | 28.2k | } |
257 | 27.7k | if (value_expected == MagickFalse) |
258 | 3.20k | continue; |
259 | 24.5k | p=value; |
260 | 24.5k | switch (c) |
261 | 24.5k | { |
262 | 880 | case '\'': |
263 | 880 | { |
264 | 880 | c=ReadBlobByte(image); |
265 | 880 | count++; |
266 | 129k | while (c != '\'') |
267 | 128k | { |
268 | 128k | if ((size_t) (p-value) < (MagickPathExtent-1)) |
269 | 116k | *p++=(char) c; |
270 | 128k | c=ReadBlobByte(image); |
271 | 128k | if (c == EOF) |
272 | 231 | break; |
273 | 128k | count++; |
274 | 128k | } |
275 | 880 | break; |
276 | 0 | } |
277 | 782 | case '"': |
278 | 782 | { |
279 | 782 | c=ReadBlobByte(image); |
280 | 782 | count++; |
281 | 107k | while (c != '"') |
282 | 106k | { |
283 | 106k | if ((size_t) (p-value) < (MagickPathExtent-1)) |
284 | 105k | *p++=(char) c; |
285 | 106k | c=ReadBlobByte(image); |
286 | 106k | if (c == EOF) |
287 | 60 | break; |
288 | 106k | count++; |
289 | 106k | } |
290 | 782 | break; |
291 | 0 | } |
292 | 689 | case '(': |
293 | 689 | { |
294 | 689 | c=ReadBlobByte(image); |
295 | 689 | count++; |
296 | 136k | while (c != ')') |
297 | 135k | { |
298 | 135k | if ((size_t) (p-value) < (MagickPathExtent-1)) |
299 | 121k | *p++=(char) c; |
300 | 135k | c=ReadBlobByte(image); |
301 | 135k | if (c == EOF) |
302 | 108 | break; |
303 | 135k | count++; |
304 | 135k | } |
305 | 689 | break; |
306 | 0 | } |
307 | 22.1k | default: |
308 | 22.1k | { |
309 | 22.1k | while (isalnum((int) ((unsigned char) c))) |
310 | 111k | { |
311 | 111k | if ((size_t) (p-value) < (MagickPathExtent-1)) |
312 | 110k | *p++=(char) c; |
313 | 111k | c=ReadBlobByte(image); |
314 | 111k | if (c == EOF) |
315 | 334 | break; |
316 | 110k | count++; |
317 | 110k | } |
318 | 22.1k | break; |
319 | 0 | } |
320 | 24.5k | } |
321 | 24.5k | *p='\0'; |
322 | | /* |
323 | | Assign a value to the specified keyword. |
324 | | */ |
325 | 24.5k | (void) FormatLocaleString(property,MagickPathExtent,"vicar:%s",keyword); |
326 | 24.5k | LocaleLower(property); |
327 | 24.5k | (void) SetImageProperty(image,property,value,exception); |
328 | 24.5k | if (LocaleCompare(keyword,"END") == 0) |
329 | 2 | break; |
330 | 24.5k | if (LocaleCompare(keyword,"FORMAT") == 0) |
331 | 5.85k | (void) CopyMagickString(format,value,MagickPathExtent); |
332 | 24.5k | if (LocaleCompare(keyword,"LABEL_RECORDS") == 0) |
333 | 195 | length*=(size_t) StringToLong(value); |
334 | 24.5k | if (LocaleCompare(keyword,"LBLSIZE") == 0) |
335 | 481 | length=(size_t) (StringToLong(value)+offset); |
336 | 24.5k | if (LocaleCompare(keyword,"LINES") == 0) |
337 | 202 | image->rows=StringToUnsignedLong(value); |
338 | 24.5k | if (LocaleCompare(keyword,"NL") == 0) |
339 | 2.02k | image->rows=StringToUnsignedLong(value); |
340 | 24.5k | if (LocaleCompare(keyword,"NS") == 0) |
341 | 1.59k | image->columns=StringToUnsignedLong(value); |
342 | 24.5k | } |
343 | 51.0k | if (c == EOF) |
344 | 1.18k | break; |
345 | 52.9k | while (isspace((int) ((unsigned char) c)) != 0) |
346 | 3.11k | { |
347 | 3.11k | c=ReadBlobByte(image); |
348 | 3.11k | if (c == EOF) |
349 | 16 | break; |
350 | 3.09k | count++; |
351 | 3.09k | } |
352 | 49.8k | } |
353 | 6.64k | while (count < (ssize_t) length) |
354 | 4.68k | { |
355 | 4.68k | c=ReadBlobByte(image); |
356 | 4.68k | if (c == EOF) |
357 | 55 | break; |
358 | 4.62k | count++; |
359 | 4.62k | } |
360 | 2.02k | if ((image->columns == 0) || (image->rows == 0)) |
361 | 1.15k | ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize"); |
362 | 868 | image->depth=8; |
363 | 868 | if (LocaleCompare(format,"byte") == 0) |
364 | 682 | ; |
365 | 186 | else |
366 | 186 | if (LocaleCompare(format,"half") == 0) |
367 | 22 | image->depth=16; |
368 | 164 | else |
369 | 164 | if ((LocaleCompare(format,"full") == 0) || |
370 | 163 | (LocaleCompare(format,"real") == 0)) |
371 | 51 | image->depth=32; |
372 | 113 | else |
373 | 113 | image->depth=64; |
374 | 868 | if (image_info->ping != MagickFalse) |
375 | 0 | { |
376 | 0 | (void) CloseBlob(image); |
377 | 0 | return(GetFirstImageInList(image)); |
378 | 0 | } |
379 | 868 | if (HeapOverflowSanityCheckGetSize(image->columns,image->rows,&number_pixels) != MagickFalse) |
380 | 786 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
381 | 786 | if (number_pixels > (size_t) GetBlobSize(image)) |
382 | 577 | ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); |
383 | 577 | status=SetImageExtent(image,image->columns,image->rows,exception); |
384 | 577 | if (status == MagickFalse) |
385 | 24 | return(DestroyImageList(image)); |
386 | | /* |
387 | | Read VICAR pixels. |
388 | | */ |
389 | 553 | (void) SetImageColorspace(image,GRAYColorspace,exception); |
390 | 553 | quantum_type=GrayQuantum; |
391 | 553 | quantum_info=AcquireQuantumInfo(image_info,image); |
392 | 553 | if (quantum_info == (QuantumInfo *) NULL) |
393 | 553 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
394 | 553 | length=GetQuantumExtent(image,quantum_info,quantum_type); |
395 | 553 | pixels=GetQuantumPixels(quantum_info); |
396 | 553 | if (LocaleCompare(format,"byte") == 0) |
397 | 379 | ; |
398 | 174 | else |
399 | 174 | if (LocaleCompare(format,"half") == 0) |
400 | 22 | SetQuantumFormat(image,quantum_info,SignedQuantumFormat); |
401 | 152 | else |
402 | 152 | SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat); |
403 | 42.0k | for (y=0; y < (ssize_t) image->rows; y++) |
404 | 41.8k | { |
405 | 41.8k | const void |
406 | 41.8k | *stream; |
407 | | |
408 | 41.8k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
409 | 41.8k | if (q == (Quantum *) NULL) |
410 | 0 | break; |
411 | 41.8k | stream=ReadBlobStream(image,length,pixels,&count); |
412 | 41.8k | if (count != (ssize_t) length) |
413 | 313 | break; |
414 | 41.5k | (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, |
415 | 41.5k | quantum_type,(unsigned char *) stream,exception); |
416 | 41.5k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
417 | 0 | break; |
418 | 41.5k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
419 | 41.5k | image->rows); |
420 | 41.5k | if (status == MagickFalse) |
421 | 0 | break; |
422 | 41.5k | } |
423 | 553 | SetQuantumImageType(image,quantum_type); |
424 | 553 | quantum_info=DestroyQuantumInfo(quantum_info); |
425 | 553 | if (EOFBlob(image) != MagickFalse) |
426 | 313 | ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", |
427 | 553 | image->filename); |
428 | 553 | if (CloseBlob(image) == MagickFalse) |
429 | 0 | status=MagickFalse; |
430 | 553 | if (status == MagickFalse) |
431 | 0 | return(DestroyImageList(image)); |
432 | 553 | return(GetFirstImageInList(image)); |
433 | 553 | } |
434 | | |
435 | | /* |
436 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
437 | | % % |
438 | | % % |
439 | | % % |
440 | | % R e g i s t e r V I C A R I m a g e % |
441 | | % % |
442 | | % % |
443 | | % % |
444 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
445 | | % |
446 | | % RegisterVICARImage() adds attributes for the VICAR image format to |
447 | | % the list of supported formats. The attributes include the image format |
448 | | % tag, a method to read and/or write the format, whether the format |
449 | | % supports the saving of more than one frame to the same file or blob, |
450 | | % whether the format supports native in-memory I/O, and a brief |
451 | | % description of the format. |
452 | | % |
453 | | % The format of the RegisterVICARImage method is: |
454 | | % |
455 | | % size_t RegisterVICARImage(void) |
456 | | % |
457 | | */ |
458 | | ModuleExport size_t RegisterVICARImage(void) |
459 | 9 | { |
460 | 9 | MagickInfo |
461 | 9 | *entry; |
462 | | |
463 | 9 | entry=AcquireMagickInfo("VICAR","VICAR", |
464 | 9 | "Video Image Communication And Retrieval"); |
465 | 9 | entry->decoder=(DecodeImageHandler *) ReadVICARImage; |
466 | 9 | entry->encoder=(EncodeImageHandler *) WriteVICARImage; |
467 | 9 | entry->magick=(IsImageFormatHandler *) IsVICAR; |
468 | 9 | entry->flags^=CoderAdjoinFlag; |
469 | 9 | (void) RegisterMagickInfo(entry); |
470 | 9 | return(MagickImageCoderSignature); |
471 | 9 | } |
472 | | |
473 | | /* |
474 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
475 | | % % |
476 | | % % |
477 | | % % |
478 | | % U n r e g i s t e r V I C A R I m a g e % |
479 | | % % |
480 | | % % |
481 | | % % |
482 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
483 | | % |
484 | | % UnregisterVICARImage() removes format registrations made by the |
485 | | % VICAR module from the list of supported formats. |
486 | | % |
487 | | % The format of the UnregisterVICARImage method is: |
488 | | % |
489 | | % UnregisterVICARImage(void) |
490 | | % |
491 | | */ |
492 | | ModuleExport void UnregisterVICARImage(void) |
493 | 0 | { |
494 | 0 | (void) UnregisterMagickInfo("VICAR"); |
495 | 0 | } |
496 | | |
497 | | /* |
498 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
499 | | % % |
500 | | % % |
501 | | % % |
502 | | % W r i t e V I C A R I m a g e % |
503 | | % % |
504 | | % % |
505 | | % % |
506 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
507 | | % |
508 | | % WriteVICARImage() writes an image in the VICAR rasterfile format. |
509 | | % Vicar files contain a text header, followed by one or more planes of binary |
510 | | % grayscale image data. Vicar files are designed to allow many planes to be |
511 | | % stacked together to form image cubes. This method only writes a single |
512 | | % grayscale plane. |
513 | | % |
514 | | % WriteVICARImage was written contributed by gorelick@esther.la.asu.edu. |
515 | | % |
516 | | % The format of the WriteVICARImage method is: |
517 | | % |
518 | | % MagickBooleanType WriteVICARImage(const ImageInfo *image_info, |
519 | | % Image *image,ExceptionInfo *exception) |
520 | | % |
521 | | % A description of each parameter follows. |
522 | | % |
523 | | % o image_info: the image info. |
524 | | % |
525 | | % o image: The image. |
526 | | % |
527 | | % o exception: return any errors or warnings in this structure. |
528 | | % |
529 | | */ |
530 | | static MagickBooleanType WriteVICARImage(const ImageInfo *image_info, |
531 | | Image *image,ExceptionInfo *exception) |
532 | 240 | { |
533 | 240 | char |
534 | 240 | header[MagickPathExtent]; |
535 | | |
536 | 240 | int |
537 | 240 | y; |
538 | | |
539 | 240 | MagickBooleanType |
540 | 240 | status; |
541 | | |
542 | 240 | QuantumInfo |
543 | 240 | *quantum_info; |
544 | | |
545 | 240 | const Quantum |
546 | 240 | *p; |
547 | | |
548 | 240 | size_t |
549 | 240 | length; |
550 | | |
551 | 240 | ssize_t |
552 | 240 | count; |
553 | | |
554 | 240 | unsigned char |
555 | 240 | *pixels; |
556 | | |
557 | | /* |
558 | | Open output image file. |
559 | | */ |
560 | 240 | assert(image_info != (const ImageInfo *) NULL); |
561 | 240 | assert(image_info->signature == MagickCoreSignature); |
562 | 240 | assert(image != (Image *) NULL); |
563 | 240 | assert(image->signature == MagickCoreSignature); |
564 | 240 | assert(exception != (ExceptionInfo *) NULL); |
565 | 240 | assert(exception->signature == MagickCoreSignature); |
566 | 240 | if (IsEventLogging() != MagickFalse) |
567 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
568 | 240 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
569 | 240 | if (status == MagickFalse) |
570 | 0 | return(status); |
571 | 240 | if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) |
572 | 0 | (void) TransformImageColorspace(image,sRGBColorspace,exception); |
573 | | /* |
574 | | Write header. |
575 | | */ |
576 | 240 | (void) memset(header,' ',MagickPathExtent); |
577 | 240 | (void) FormatLocaleString(header,MagickPathExtent, |
578 | 240 | "LBLSIZE=%.17g FORMAT='BYTE' TYPE='IMAGE' BUFSIZE=20000 DIM=2 EOL=0 " |
579 | 240 | "RECSIZE=%.17g ORG='BSQ' NL=%.17g NS=%.17g NB=1 N1=0 N2=0 N3=0 N4=0 NBB=0 " |
580 | 240 | "NLB=0 TASK='ImageMagick'",(double) MagickPathExtent,(double) |
581 | 240 | image->columns,(double) image->rows,(double) image->columns); |
582 | 240 | (void) WriteBlob(image,MagickPathExtent,(unsigned char *) header); |
583 | | /* |
584 | | Write VICAR pixels. |
585 | | */ |
586 | 240 | image->depth=8; |
587 | 240 | quantum_info=AcquireQuantumInfo(image_info,image); |
588 | 240 | if (quantum_info == (QuantumInfo *) NULL) |
589 | 240 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
590 | 240 | pixels=(unsigned char *) GetQuantumPixels(quantum_info); |
591 | 17.3k | for (y=0; y < (ssize_t) image->rows; y++) |
592 | 17.0k | { |
593 | 17.0k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
594 | 17.0k | if (p == (const Quantum *) NULL) |
595 | 0 | break; |
596 | 17.0k | length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info, |
597 | 17.0k | GrayQuantum,pixels,exception); |
598 | 17.0k | count=WriteBlob(image,length,pixels); |
599 | 17.0k | if (count != (ssize_t) length) |
600 | 0 | break; |
601 | 17.0k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, |
602 | 17.0k | image->rows); |
603 | 17.0k | if (status == MagickFalse) |
604 | 0 | break; |
605 | 17.0k | } |
606 | 240 | quantum_info=DestroyQuantumInfo(quantum_info); |
607 | 240 | if (CloseBlob(image) == MagickFalse) |
608 | 0 | status=MagickFalse; |
609 | 240 | return(status); |
610 | 240 | } |