/src/imagemagick/coders/aai.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % AAA AAA IIIII % |
7 | | % A A A A I % |
8 | | % AAAAA AAAAA I % |
9 | | % A A A A I % |
10 | | % A A A A IIIII % |
11 | | % % |
12 | | % % |
13 | | % Read/Write AAI X Image 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/blob.h" |
44 | | #include "MagickCore/blob-private.h" |
45 | | #include "MagickCore/cache.h" |
46 | | #include "MagickCore/colorspace.h" |
47 | | #include "MagickCore/colorspace-private.h" |
48 | | #include "MagickCore/exception.h" |
49 | | #include "MagickCore/exception-private.h" |
50 | | #include "MagickCore/image.h" |
51 | | #include "MagickCore/image-private.h" |
52 | | #include "MagickCore/list.h" |
53 | | #include "MagickCore/magick.h" |
54 | | #include "MagickCore/memory_.h" |
55 | | #include "MagickCore/monitor.h" |
56 | | #include "MagickCore/monitor-private.h" |
57 | | #include "MagickCore/pixel.h" |
58 | | #include "MagickCore/pixel-accessor.h" |
59 | | #include "MagickCore/quantum-private.h" |
60 | | #include "MagickCore/static.h" |
61 | | #include "MagickCore/string_.h" |
62 | | #include "MagickCore/module.h" |
63 | | |
64 | | /* |
65 | | Forward declarations. |
66 | | */ |
67 | | static MagickBooleanType |
68 | | WriteAAIImage(const ImageInfo *,Image *,ExceptionInfo *); |
69 | | |
70 | | /* |
71 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
72 | | % % |
73 | | % % |
74 | | % % |
75 | | % R e a d A A I I m a g e % |
76 | | % % |
77 | | % % |
78 | | % % |
79 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
80 | | % |
81 | | % ReadAAIImage() reads an AAI Dune image file and returns it. It |
82 | | % allocates the memory necessary for the new Image structure and returns a |
83 | | % pointer to the new image. |
84 | | % |
85 | | % The format of the ReadAAIImage method is: |
86 | | % |
87 | | % Image *ReadAAIImage(const ImageInfo *image_info,ExceptionInfo *exception) |
88 | | % |
89 | | % A description of each parameter follows: |
90 | | % |
91 | | % o image_info: the image info. |
92 | | % |
93 | | % o exception: return any errors or warnings in this structure. |
94 | | % |
95 | | */ |
96 | | static Image *ReadAAIImage(const ImageInfo *image_info,ExceptionInfo *exception) |
97 | 607 | { |
98 | 607 | Image |
99 | 607 | *image; |
100 | | |
101 | 607 | MagickBooleanType |
102 | 607 | status; |
103 | | |
104 | 607 | Quantum |
105 | 607 | *q; |
106 | | |
107 | 607 | size_t |
108 | 607 | height, |
109 | 607 | length, |
110 | 607 | width; |
111 | | |
112 | 607 | ssize_t |
113 | 607 | count, |
114 | 607 | x, |
115 | 607 | y; |
116 | | |
117 | 607 | unsigned char |
118 | 607 | *p, |
119 | 607 | *pixels; |
120 | | |
121 | | /* |
122 | | Open image file. |
123 | | */ |
124 | 607 | assert(image_info != (const ImageInfo *) NULL); |
125 | 607 | assert(image_info->signature == MagickCoreSignature); |
126 | 607 | assert(exception != (ExceptionInfo *) NULL); |
127 | 607 | assert(exception->signature == MagickCoreSignature); |
128 | 607 | if (IsEventLogging() != MagickFalse) |
129 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
130 | 0 | image_info->filename); |
131 | 607 | image=AcquireImage(image_info,exception); |
132 | 607 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
133 | 607 | if (status == MagickFalse) |
134 | 0 | { |
135 | 0 | image=DestroyImageList(image); |
136 | 0 | return((Image *) NULL); |
137 | 0 | } |
138 | | /* |
139 | | Read AAI Dune image. |
140 | | */ |
141 | 607 | width=ReadBlobLSBLong(image); |
142 | 607 | height=ReadBlobLSBLong(image); |
143 | 607 | if (EOFBlob(image) != MagickFalse) |
144 | 601 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
145 | 601 | if ((width == 0UL) || (height == 0UL)) |
146 | 599 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
147 | 599 | do |
148 | 1.00k | { |
149 | | /* |
150 | | Convert AAI raster image to pixel packets. |
151 | | */ |
152 | 1.00k | image->columns=width; |
153 | 1.00k | image->rows=height; |
154 | 1.00k | image->depth=8; |
155 | 1.00k | if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) |
156 | 0 | if (image->scene >= (image_info->scene+image_info->number_scenes-1)) |
157 | 0 | break; |
158 | 1.00k | status=SetImageExtent(image,image->columns,image->rows,exception); |
159 | 1.00k | if (status == MagickFalse) |
160 | 187 | return(DestroyImageList(image)); |
161 | 818 | pixels=(unsigned char *) AcquireQuantumMemory(image->columns, |
162 | 818 | 4*sizeof(*pixels)); |
163 | 818 | if (pixels == (unsigned char *) NULL) |
164 | 818 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
165 | 818 | length=(size_t) 4*image->columns; |
166 | 38.1k | for (y=0; y < (ssize_t) image->rows; y++) |
167 | 37.5k | { |
168 | 37.5k | count=ReadBlob(image,length,pixels); |
169 | 37.5k | if (count != (ssize_t) length) |
170 | 176 | { |
171 | 176 | pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
172 | 176 | ThrowReaderException(CorruptImageError,"UnableToReadImageData"); |
173 | 0 | } |
174 | 37.3k | p=pixels; |
175 | 37.3k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
176 | 37.3k | if (q == (Quantum *) NULL) |
177 | 0 | break; |
178 | 110k | for (x=0; x < (ssize_t) image->columns; x++) |
179 | 73.3k | { |
180 | 73.3k | SetPixelBlue(image,ScaleCharToQuantum(*p++),q); |
181 | 73.3k | SetPixelGreen(image,ScaleCharToQuantum(*p++),q); |
182 | 73.3k | SetPixelRed(image,ScaleCharToQuantum(*p++),q); |
183 | 73.3k | if (*p == 254) |
184 | 1.85k | *p=255; |
185 | 73.3k | SetPixelAlpha(image,ScaleCharToQuantum(*p++),q); |
186 | 73.3k | if (GetPixelAlpha(image,q) != OpaqueAlpha) |
187 | 0 | image->alpha_trait=BlendPixelTrait; |
188 | 73.3k | q+=(ptrdiff_t) GetPixelChannels(image); |
189 | 73.3k | } |
190 | 37.3k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
191 | 0 | break; |
192 | 37.3k | if (image->previous == (Image *) NULL) |
193 | 36.5k | { |
194 | 36.5k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
195 | 36.5k | image->rows); |
196 | 36.5k | if (status == MagickFalse) |
197 | 0 | break; |
198 | 36.5k | } |
199 | 37.3k | } |
200 | 642 | pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
201 | 642 | if (EOFBlob(image) != MagickFalse) |
202 | 0 | { |
203 | 0 | ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", |
204 | 0 | image->filename); |
205 | 0 | break; |
206 | 0 | } |
207 | | /* |
208 | | Proceed to next image. |
209 | | */ |
210 | 642 | if (image_info->number_scenes != 0) |
211 | 0 | if (image->scene >= (image_info->scene+image_info->number_scenes-1)) |
212 | 0 | break; |
213 | 642 | width=ReadBlobLSBLong(image); |
214 | 642 | height=ReadBlobLSBLong(image); |
215 | 642 | if ((width != 0UL) && (height != 0UL)) |
216 | 406 | { |
217 | | /* |
218 | | Allocate next image structure. |
219 | | */ |
220 | 406 | AcquireNextImage(image_info,image,exception); |
221 | 406 | if (GetNextImageInList(image) == (Image *) NULL) |
222 | 0 | { |
223 | 0 | status=MagickFalse; |
224 | 0 | break; |
225 | 0 | } |
226 | 406 | image=SyncNextImageInList(image); |
227 | 406 | status=SetImageProgress(image,LoadImagesTag,TellBlob(image), |
228 | 406 | GetBlobSize(image)); |
229 | 406 | if (status == MagickFalse) |
230 | 0 | break; |
231 | 406 | } |
232 | 642 | } while ((width != 0UL) && (height != 0UL)); |
233 | 236 | if (CloseBlob(image) == MagickFalse) |
234 | 0 | status=MagickFalse; |
235 | 236 | if (status == MagickFalse) |
236 | 0 | return(DestroyImageList(image)); |
237 | 236 | return(GetFirstImageInList(image)); |
238 | 236 | } |
239 | | |
240 | | /* |
241 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
242 | | % % |
243 | | % % |
244 | | % % |
245 | | % R e g i s t e r A A I I m a g e % |
246 | | % % |
247 | | % % |
248 | | % % |
249 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
250 | | % |
251 | | % RegisterAAIImage() adds attributes for the AAI Dune image format to the list |
252 | | % of supported formats. The attributes include the image format tag, a |
253 | | % method to read and/or write the format, whether the format supports the |
254 | | % saving of more than one frame to the same file or blob, whether the format |
255 | | % supports native in-memory I/O, and a brief description of the format. |
256 | | % |
257 | | % The format of the RegisterAAIImage method is: |
258 | | % |
259 | | % size_t RegisterAAIImage(void) |
260 | | % |
261 | | */ |
262 | | ModuleExport size_t RegisterAAIImage(void) |
263 | 8 | { |
264 | 8 | MagickInfo |
265 | 8 | *entry; |
266 | | |
267 | 8 | entry=AcquireMagickInfo("AAI","AAI","AAI Dune image"); |
268 | 8 | entry->decoder=(DecodeImageHandler *) ReadAAIImage; |
269 | 8 | entry->encoder=(EncodeImageHandler *) WriteAAIImage; |
270 | 8 | (void) RegisterMagickInfo(entry); |
271 | 8 | return(MagickImageCoderSignature); |
272 | 8 | } |
273 | | |
274 | | /* |
275 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
276 | | % % |
277 | | % % |
278 | | % % |
279 | | % U n r e g i s t e r A A I I m a g e % |
280 | | % % |
281 | | % % |
282 | | % % |
283 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
284 | | % |
285 | | % UnregisterAAIImage() removes format registrations made by the |
286 | | % AAI module from the list of supported formats. |
287 | | % |
288 | | % The format of the UnregisterAAIImage method is: |
289 | | % |
290 | | % UnregisterAAIImage(void) |
291 | | % |
292 | | */ |
293 | | ModuleExport void UnregisterAAIImage(void) |
294 | 0 | { |
295 | 0 | (void) UnregisterMagickInfo("AAI"); |
296 | 0 | } |
297 | | |
298 | | /* |
299 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
300 | | % % |
301 | | % % |
302 | | % % |
303 | | % W r i t e A A I I m a g e % |
304 | | % % |
305 | | % % |
306 | | % % |
307 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
308 | | % |
309 | | % WriteAAIImage() writes an image to a file in AAI Dune image format. |
310 | | % |
311 | | % The format of the WriteAAIImage method is: |
312 | | % |
313 | | % MagickBooleanType WriteAAIImage(const ImageInfo *image_info, |
314 | | % Image *image,ExceptionInfo *exception) |
315 | | % |
316 | | % A description of each parameter follows. |
317 | | % |
318 | | % o image_info: the image info. |
319 | | % |
320 | | % o image: The image. |
321 | | % |
322 | | % o exception: return any errors or warnings in this structure. |
323 | | % |
324 | | */ |
325 | | static MagickBooleanType WriteAAIImage(const ImageInfo *image_info,Image *image, |
326 | | ExceptionInfo *exception) |
327 | 236 | { |
328 | 236 | const Quantum |
329 | 236 | *magick_restrict p; |
330 | | |
331 | 236 | MagickBooleanType |
332 | 236 | status; |
333 | | |
334 | 236 | MagickOffsetType |
335 | 236 | scene; |
336 | | |
337 | 236 | size_t |
338 | 236 | number_scenes; |
339 | | |
340 | 236 | ssize_t |
341 | 236 | count, |
342 | 236 | x, |
343 | 236 | y; |
344 | | |
345 | 236 | unsigned char |
346 | 236 | *pixels, |
347 | 236 | *magick_restrict q; |
348 | | |
349 | | /* |
350 | | Open output image file. |
351 | | */ |
352 | 236 | assert(image_info != (const ImageInfo *) NULL); |
353 | 236 | assert(image_info->signature == MagickCoreSignature); |
354 | 236 | assert(image != (Image *) NULL); |
355 | 236 | assert(image->signature == MagickCoreSignature); |
356 | 236 | assert(exception != (ExceptionInfo *) NULL); |
357 | 236 | assert(exception->signature == MagickCoreSignature); |
358 | 236 | if (IsEventLogging() != MagickFalse) |
359 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
360 | 236 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
361 | 236 | if (status == MagickFalse) |
362 | 0 | return(status); |
363 | 236 | scene=0; |
364 | 236 | number_scenes=GetImageListLength(image); |
365 | 236 | do |
366 | 236 | { |
367 | | /* |
368 | | Write AAI header. |
369 | | */ |
370 | 236 | if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) |
371 | 0 | (void) TransformImageColorspace(image,sRGBColorspace,exception); |
372 | 236 | (void) WriteBlobLSBLong(image,(unsigned int) image->columns); |
373 | 236 | (void) WriteBlobLSBLong(image,(unsigned int) image->rows); |
374 | | /* |
375 | | Allocate memory for pixels. |
376 | | */ |
377 | 236 | pixels=(unsigned char *) AcquireQuantumMemory(image->columns, |
378 | 236 | 4*sizeof(*pixels)); |
379 | 236 | if (pixels == (unsigned char *) NULL) |
380 | 236 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
381 | | /* |
382 | | Convert MIFF to AAI raster pixels. |
383 | | */ |
384 | 22.8k | for (y=0; y < (ssize_t) image->rows; y++) |
385 | 22.5k | { |
386 | 22.5k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
387 | 22.5k | if (p == (const Quantum *) NULL) |
388 | 0 | break; |
389 | 22.5k | q=pixels; |
390 | 66.7k | for (x=0; x < (ssize_t) image->columns; x++) |
391 | 44.1k | { |
392 | 44.1k | *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); |
393 | 44.1k | *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); |
394 | 44.1k | *q++=ScaleQuantumToChar(GetPixelRed(image,p)); |
395 | 44.1k | *q=ScaleQuantumToChar((Quantum) (image->alpha_trait != |
396 | 44.1k | UndefinedPixelTrait ? GetPixelAlpha(image,p) : OpaqueAlpha)); |
397 | 44.1k | if (*q == 255) |
398 | 44.1k | *q=254; |
399 | 44.1k | p+=(ptrdiff_t) GetPixelChannels(image); |
400 | 44.1k | q++; |
401 | 44.1k | } |
402 | 22.5k | count=WriteBlob(image,(size_t) (q-pixels),pixels); |
403 | 22.5k | if (count != (ssize_t) (q-pixels)) |
404 | 0 | break; |
405 | 22.5k | if (image->previous == (Image *) NULL) |
406 | 22.5k | { |
407 | 22.5k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, |
408 | 22.5k | image->rows); |
409 | 22.5k | if (status == MagickFalse) |
410 | 0 | break; |
411 | 22.5k | } |
412 | 22.5k | } |
413 | 236 | pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
414 | 236 | if (GetNextImageInList(image) == (Image *) NULL) |
415 | 236 | break; |
416 | 0 | image=SyncNextImageInList(image); |
417 | 0 | status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes); |
418 | 0 | if (status == MagickFalse) |
419 | 0 | break; |
420 | 0 | } while (image_info->adjoin != MagickFalse); |
421 | 236 | if (CloseBlob(image) == MagickFalse) |
422 | 0 | status=MagickFalse; |
423 | 236 | return(status); |
424 | 236 | } |