/src/graphicsmagick/coders/mtv.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % |
6 | | % This program is covered by multiple licenses, which are described in |
7 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
8 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
9 | | % |
10 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
11 | | % % |
12 | | % % |
13 | | % % |
14 | | % M M TTTTT V V % |
15 | | % MM MM T V V % |
16 | | % M M M T V V % |
17 | | % M M T V V % |
18 | | % M M T V % |
19 | | % % |
20 | | % % |
21 | | % Read/Write MTV Raytracer Image Format. % |
22 | | % % |
23 | | % % |
24 | | % Software Design % |
25 | | % John Cristy % |
26 | | % July 1992 % |
27 | | % % |
28 | | % % |
29 | | % % |
30 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
31 | | % |
32 | | % |
33 | | */ |
34 | | |
35 | | /* |
36 | | Include declarations. |
37 | | */ |
38 | | #include "magick/studio.h" |
39 | | #include "magick/blob.h" |
40 | | #include "magick/pixel_cache.h" |
41 | | #include "magick/log.h" |
42 | | #include "magick/magick.h" |
43 | | #include "magick/monitor.h" |
44 | | #include "magick/utility.h" |
45 | | #include "magick/static.h" |
46 | | |
47 | | /* |
48 | | Forward declarations. |
49 | | */ |
50 | | static unsigned int |
51 | | WriteMTVImage(const ImageInfo *,Image *); |
52 | | |
53 | | /* |
54 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
55 | | % % |
56 | | % % |
57 | | % % |
58 | | % R e a d M T V I m a g e % |
59 | | % % |
60 | | % % |
61 | | % % |
62 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
63 | | % |
64 | | % Method ReadMTVImage reads a MTV image file and returns it. It allocates |
65 | | % the memory necessary for the new Image structure and returns a pointer to |
66 | | % the new image. |
67 | | % |
68 | | % The format of the ReadMTVImage method is: |
69 | | % |
70 | | % Image *ReadMTVImage(const ImageInfo *image_info,ExceptionInfo *exception) |
71 | | % |
72 | | % A description of each parameter follows: |
73 | | % |
74 | | % o image: Method ReadMTVImage returns a pointer to the image after |
75 | | % reading. A null image is returned if there is a memory shortage or |
76 | | % if the image cannot be read. |
77 | | % |
78 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
79 | | % |
80 | | % o exception: return any errors or warnings in this structure. |
81 | | % |
82 | | % |
83 | | */ |
84 | | static Image *ReadMTVImage(const ImageInfo *image_info,ExceptionInfo *exception) |
85 | 911 | { |
86 | 911 | char |
87 | 911 | buffer[MaxTextExtent]; |
88 | | |
89 | 911 | Image |
90 | 911 | *image; |
91 | | |
92 | 911 | long |
93 | 911 | count, |
94 | 911 | y; |
95 | | |
96 | 911 | register long |
97 | 911 | x; |
98 | | |
99 | 911 | register PixelPacket |
100 | 911 | *q; |
101 | | |
102 | 911 | register unsigned char |
103 | 911 | *p; |
104 | | |
105 | 911 | unsigned char |
106 | 911 | *pixels; |
107 | | |
108 | 911 | unsigned int |
109 | 911 | status; |
110 | | |
111 | 911 | unsigned long |
112 | 911 | columns, |
113 | 911 | rows; |
114 | | |
115 | | /* |
116 | | Open image file. |
117 | | */ |
118 | 911 | assert(image_info != (const ImageInfo *) NULL); |
119 | 911 | assert(image_info->signature == MagickSignature); |
120 | 911 | assert(exception != (ExceptionInfo *) NULL); |
121 | 911 | assert(exception->signature == MagickSignature); |
122 | 911 | image=AllocateImage(image_info); |
123 | 911 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
124 | 911 | if (status == False) |
125 | 911 | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
126 | | /* |
127 | | Read MTV image. |
128 | | */ |
129 | 911 | buffer[0]='\0'; |
130 | 911 | (void) ReadBlobString(image,buffer); |
131 | 911 | columns=0; |
132 | 911 | rows=0; |
133 | 911 | count=sscanf(buffer,"%lu %lu\n",&columns,&rows); |
134 | 911 | if (count != 2) |
135 | 868 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
136 | 868 | do |
137 | 868 | { |
138 | 868 | size_t |
139 | 868 | row_size; |
140 | | |
141 | | /* |
142 | | Initialize image structure. |
143 | | */ |
144 | 868 | image->columns=columns; |
145 | 868 | image->rows=rows; |
146 | 868 | image->depth=8; |
147 | 868 | if (image->logging) |
148 | 868 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
149 | 868 | "Image[%lu] Geometry %lux%lu", image->scene, |
150 | 868 | image->columns, image->rows); |
151 | 868 | if (image_info->ping && (image_info->subrange != 0)) |
152 | 0 | if (image->scene >= (image_info->subimage+image_info->subrange-1)) |
153 | 0 | break; |
154 | | |
155 | 868 | if (CheckImagePixelLimits(image, exception) != MagickPass) |
156 | 573 | ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
157 | | |
158 | | /* |
159 | | Convert MTV raster image to pixel packets. |
160 | | */ |
161 | 573 | pixels=MagickAllocateResourceLimitedArray(unsigned char *,image->columns,3); |
162 | 573 | if (pixels == (unsigned char *) NULL) |
163 | 573 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
164 | 573 | row_size= (size_t) image->columns*3; |
165 | 124k | for (y=0; y < (long) image->rows; y++) |
166 | 124k | { |
167 | 124k | if (ReadBlob(image,row_size,pixels) != row_size) |
168 | 396 | break; |
169 | 123k | p=pixels; |
170 | 123k | q=SetImagePixelsEx(image,0,y,image->columns,1,exception); |
171 | 123k | if (q == (PixelPacket *) NULL) |
172 | 0 | break; |
173 | 17.1M | for (x=0; x < (long) image->columns; x++) |
174 | 17.0M | { |
175 | 17.0M | q->red=ScaleCharToQuantum(*p++); |
176 | 17.0M | q->green=ScaleCharToQuantum(*p++); |
177 | 17.0M | q->blue=ScaleCharToQuantum(*p++); |
178 | 17.0M | q++; |
179 | 17.0M | } |
180 | 123k | if (!SyncImagePixelsEx(image,exception)) |
181 | 0 | break; |
182 | 123k | if (image->previous == (Image *) NULL) |
183 | 123k | if (QuantumTick(y,image->rows)) |
184 | 20.8k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
185 | 20.8k | image->filename, |
186 | 20.8k | image->columns,image->rows)) |
187 | 0 | break; |
188 | 123k | } |
189 | 573 | MagickFreeResourceLimitedMemory(unsigned char *,pixels); |
190 | 573 | if (EOFBlob(image)) |
191 | 396 | { |
192 | 396 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
193 | 396 | image->filename); |
194 | 396 | break; |
195 | 396 | } |
196 | 177 | StopTimer(&image->timer); |
197 | | /* |
198 | | Proceed to next image. |
199 | | */ |
200 | 177 | if (image_info->subrange != 0) |
201 | 177 | if (image->scene >= (image_info->subimage+image_info->subrange-1)) |
202 | 177 | break; |
203 | 0 | *buffer='\0'; |
204 | 0 | count=0; |
205 | 0 | if (ReadBlobString(image,buffer) == NULL) |
206 | 0 | break; |
207 | 0 | count=sscanf(buffer,"%lu %lu\n",&columns,&rows); |
208 | 0 | if (count == 2) |
209 | 0 | { |
210 | | /* |
211 | | Allocate next image structure. |
212 | | */ |
213 | 0 | AllocateNextImage(image_info,image); |
214 | 0 | if (image->next == (Image *) NULL) |
215 | 0 | { |
216 | 0 | DestroyImageList(image); |
217 | 0 | return((Image *) NULL); |
218 | 0 | } |
219 | 0 | image=SyncNextImageInList(image); |
220 | 0 | if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image), |
221 | 0 | exception,LoadImagesText, |
222 | 0 | image->filename)) |
223 | 0 | break; |
224 | 0 | } |
225 | 0 | } while (count == 2); |
226 | 573 | while (image->previous != (Image *) NULL) |
227 | 0 | image=image->previous; |
228 | 573 | CloseBlob(image); |
229 | 573 | return(image); |
230 | 868 | } |
231 | | |
232 | | /* |
233 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
234 | | % % |
235 | | % % |
236 | | % % |
237 | | % R e g i s t e r M T V I m a g e % |
238 | | % % |
239 | | % % |
240 | | % % |
241 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
242 | | % |
243 | | % Method RegisterMTVImage adds attributes for the MTV image format to |
244 | | % the list of supported formats. The attributes include the image format |
245 | | % tag, a method to read and/or write the format, whether the format |
246 | | % supports the saving of more than one frame to the same file or blob, |
247 | | % whether the format supports native in-memory I/O, and a brief |
248 | | % description of the format. |
249 | | % |
250 | | % The format of the RegisterMTVImage method is: |
251 | | % |
252 | | % RegisterMTVImage(void) |
253 | | % |
254 | | */ |
255 | | ModuleExport void RegisterMTVImage(void) |
256 | 1 | { |
257 | 1 | MagickInfo |
258 | 1 | *entry; |
259 | | |
260 | 1 | entry=SetMagickInfo("MTV"); |
261 | 1 | entry->decoder=(DecoderHandler) ReadMTVImage; |
262 | 1 | entry->encoder=(EncoderHandler) WriteMTVImage; |
263 | 1 | entry->description="MTV Raytracing image format"; |
264 | 1 | entry->module="MTV"; |
265 | 1 | entry->coder_class=UnstableCoderClass; |
266 | 1 | (void) RegisterMagickInfo(entry); |
267 | 1 | } |
268 | | |
269 | | /* |
270 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
271 | | % % |
272 | | % % |
273 | | % % |
274 | | % U n r e g i s t e r M T V I m a g e % |
275 | | % % |
276 | | % % |
277 | | % % |
278 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
279 | | % |
280 | | % Method UnregisterMTVImage removes format registrations made by the |
281 | | % MTV module from the list of supported formats. |
282 | | % |
283 | | % The format of the UnregisterMTVImage method is: |
284 | | % |
285 | | % UnregisterMTVImage(void) |
286 | | % |
287 | | */ |
288 | | ModuleExport void UnregisterMTVImage(void) |
289 | 0 | { |
290 | 0 | (void) UnregisterMagickInfo("MTV"); |
291 | 0 | } |
292 | | |
293 | | /* |
294 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
295 | | % % |
296 | | % % |
297 | | % % |
298 | | % W r i t e M T V I m a g e % |
299 | | % % |
300 | | % % |
301 | | % % |
302 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
303 | | % |
304 | | % Method WriteMTVImage writes an image to a file in red, green, and blue |
305 | | % MTV rasterfile format. |
306 | | % |
307 | | % The format of the WriteMTVImage method is: |
308 | | % |
309 | | % unsigned int WriteMTVImage(const ImageInfo *image_info,Image *image) |
310 | | % |
311 | | % A description of each parameter follows. |
312 | | % |
313 | | % o status: Method WriteMTVImage return True if the image is written. |
314 | | % False is returned is there is a memory shortage or if the image file |
315 | | % fails to write. |
316 | | % |
317 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
318 | | % |
319 | | % o image: A pointer to an Image structure. |
320 | | % |
321 | | % |
322 | | */ |
323 | | static unsigned int WriteMTVImage(const ImageInfo *image_info,Image *image) |
324 | 177 | { |
325 | 177 | char |
326 | 177 | buffer[MaxTextExtent]; |
327 | | |
328 | 177 | int |
329 | 177 | y; |
330 | | |
331 | 177 | register const PixelPacket |
332 | 177 | *p; |
333 | | |
334 | 177 | register long |
335 | 177 | x; |
336 | | |
337 | 177 | register unsigned char |
338 | 177 | *q; |
339 | | |
340 | 177 | unsigned char |
341 | 177 | *pixels; |
342 | | |
343 | 177 | unsigned int |
344 | 177 | status; |
345 | | |
346 | 177 | unsigned long |
347 | 177 | scene; |
348 | | |
349 | 177 | size_t |
350 | 177 | image_list_length; |
351 | | |
352 | | /* |
353 | | Open output image file. |
354 | | */ |
355 | 177 | assert(image_info != (const ImageInfo *) NULL); |
356 | 177 | assert(image_info->signature == MagickSignature); |
357 | 177 | assert(image != (Image *) NULL); |
358 | 177 | assert(image->signature == MagickSignature); |
359 | 177 | image_list_length=GetImageListLength(image); |
360 | 177 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
361 | 177 | if (status == False) |
362 | 177 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
363 | 177 | scene=0; |
364 | 177 | do |
365 | 177 | { |
366 | | /* |
367 | | Set image to RGB colorspace |
368 | | */ |
369 | 177 | if (TransformColorspace(image,RGBColorspace) == MagickFail) |
370 | 177 | ThrowWriterException(CoderError,UnableToTransformColorspace,image); |
371 | | /* |
372 | | Allocate memory for pixels. |
373 | | */ |
374 | 177 | pixels=MagickAllocateResourceLimitedMemory(unsigned char *, |
375 | 177 | image->columns*sizeof(PixelPacket)); |
376 | 177 | if (pixels == (unsigned char *) NULL) |
377 | 177 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
378 | | /* |
379 | | Initialize raster file header. |
380 | | */ |
381 | 177 | MagickFormatString(buffer,sizeof(buffer),"%lu %lu\n",image->columns,image->rows); |
382 | 177 | (void) WriteBlobString(image,buffer); |
383 | 76.1k | for (y=0; y < (long) image->rows; y++) |
384 | 76.0k | { |
385 | 76.0k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
386 | 76.0k | if (p == (const PixelPacket *) NULL) |
387 | 0 | break; |
388 | 76.0k | q=pixels; |
389 | 2.81M | for (x=0; x < (long) image->columns; x++) |
390 | 2.73M | { |
391 | 2.73M | *q++=ScaleQuantumToChar(p->red); |
392 | 2.73M | *q++=ScaleQuantumToChar(p->green); |
393 | 2.73M | *q++=ScaleQuantumToChar(p->blue); |
394 | 2.73M | p++; |
395 | 2.73M | } |
396 | 76.0k | (void) WriteBlob(image,q-pixels,(char *) pixels); |
397 | 76.0k | if (image->previous == (Image *) NULL) |
398 | 76.0k | if (QuantumTick(y,image->rows)) |
399 | 11.9k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
400 | 11.9k | SaveImageText,image->filename, |
401 | 11.9k | image->columns,image->rows)) |
402 | 0 | break; |
403 | 76.0k | } |
404 | 177 | MagickFreeResourceLimitedMemory(unsigned char *,pixels); |
405 | 177 | if (image->next == (Image *) NULL) |
406 | 177 | break; |
407 | 0 | image=SyncNextImageInList(image); |
408 | 0 | status=MagickMonitorFormatted(scene++,image_list_length, |
409 | 0 | &image->exception,SaveImagesText, |
410 | 0 | image->filename); |
411 | 0 | if (status == False) |
412 | 0 | break; |
413 | 0 | } while (image_info->adjoin); |
414 | 177 | if (image_info->adjoin) |
415 | 177 | while (image->previous != (Image *) NULL) |
416 | 0 | image=image->previous; |
417 | 177 | status &= CloseBlob(image); |
418 | 177 | return(status); |
419 | 177 | } |