blob: 7b4b09af52b3741b3e6ee3384c4b91d575cf3b50 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% M M TTTTT V V %
7% MM MM T V V %
8% M M M T V V %
9% M M T V V %
10% M M T V %
11% %
12% %
13% Read/Write MTV Raytracer Image Format %
14% %
15% Software Design %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
Cristy252dd2c2018-12-02 09:42:06 -050020% Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% %
Cristy83d74de2018-10-13 10:17:25 -040026% https://imagemagick.org/script/license.php %
cristy3ed852e2009-09-05 21:47:34 +000027% %
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*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristy510d06a2011-07-06 23:43:54 +000047#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000048#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-accessor.h"
58#include "MagickCore/quantum-private.h"
59#include "MagickCore/static.h"
60#include "MagickCore/string_.h"
61#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000062
63/*
64 Forward declarations.
65*/
66static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000067 WriteMTVImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000068
69/*
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71% %
72% %
73% %
74% R e a d M T V I m a g e %
75% %
76% %
77% %
78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79%
80% ReadMTVImage() reads a MTV image file and returns it. It allocates
81% the memory necessary for the new Image structure and returns a pointer to
82% the new image.
83%
84% The format of the ReadMTVImage method is:
85%
86% Image *ReadMTVImage(const ImageInfo *image_info,ExceptionInfo *exception)
87%
88% A description of each parameter follows:
89%
90% o image_info: the image info.
91%
92% o exception: return any errors or warnings in this structure.
93%
94*/
95static Image *ReadMTVImage(const ImageInfo *image_info,ExceptionInfo *exception)
96{
97 char
cristy151b66d2015-04-15 10:50:31 +000098 buffer[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000099
100 Image
101 *image;
102
cristy3ed852e2009-09-05 21:47:34 +0000103 MagickBooleanType
104 status;
105
cristybb503372010-05-27 20:51:26 +0000106 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000107 x;
108
cristy4c08aed2011-07-01 19:47:50 +0000109 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000110 *q;
111
112 register unsigned char
113 *p;
114
115 ssize_t
cristyaff6d802011-04-26 01:46:31 +0000116 count,
117 y;
cristy3ed852e2009-09-05 21:47:34 +0000118
119 unsigned char
120 *pixels;
121
cristyf2faecf2010-05-28 19:19:36 +0000122 unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000123 columns,
124 rows;
125
126 /*
127 Open image file.
128 */
129 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000130 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000131 if (image_info->debug != MagickFalse)
132 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
133 image_info->filename);
134 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000135 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +0000136 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000137 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
138 if (status == MagickFalse)
139 {
140 image=DestroyImageList(image);
141 return((Image *) NULL);
142 }
143 /*
144 Read MTV image.
145 */
Cristy7f3dd512018-03-25 17:46:14 -0400146 (void) memset(buffer,0,sizeof(buffer));
cristy3ed852e2009-09-05 21:47:34 +0000147 (void) ReadBlobString(image,buffer);
148 count=(ssize_t) sscanf(buffer,"%lu %lu\n",&columns,&rows);
Cristy7f3dd512018-03-25 17:46:14 -0400149 if (count != 2)
cristy3ed852e2009-09-05 21:47:34 +0000150 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
151 do
152 {
153 /*
154 Initialize image structure.
155 */
156 image->columns=columns;
157 image->rows=rows;
158 image->depth=8;
159 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
160 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
161 break;
cristyacabb842014-12-14 23:36:33 +0000162 status=SetImageExtent(image,image->columns,image->rows,exception);
163 if (status == MagickFalse)
164 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000165 /*
166 Convert MTV raster image to pixel packets.
167 */
cristybc4a1d42014-12-15 21:47:00 +0000168 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
cristy3ed852e2009-09-05 21:47:34 +0000169 3UL*sizeof(*pixels));
170 if (pixels == (unsigned char *) NULL)
171 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000172 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000173 {
174 count=(ssize_t) ReadBlob(image,(size_t) (3*image->columns),pixels);
175 if (count != (ssize_t) (3*image->columns))
Cristyf0649392017-04-26 17:21:42 -0400176 {
177 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
178 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
179 }
cristy3ed852e2009-09-05 21:47:34 +0000180 p=pixels;
181 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000182 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000183 break;
cristybb503372010-05-27 20:51:26 +0000184 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000185 {
cristy4c08aed2011-07-01 19:47:50 +0000186 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
187 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
188 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
189 SetPixelAlpha(image,OpaqueAlpha,q);
cristyed231572011-07-14 02:18:59 +0000190 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000191 }
192 if (SyncAuthenticPixels(image,exception) == MagickFalse)
193 break;
194 if (image->previous == (Image *) NULL)
195 {
cristycee97112010-05-28 00:44:52 +0000196 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristyaff6d802011-04-26 01:46:31 +0000197 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000198 if (status == MagickFalse)
199 break;
200 }
201 }
202 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
203 if (EOFBlob(image) != MagickFalse)
204 {
205 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
206 image->filename);
207 break;
208 }
209 /*
210 Proceed to next image.
211 */
212 if (image_info->number_scenes != 0)
213 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
214 break;
215 *buffer='\0';
Cristye80a30b2018-03-25 17:43:24 -0400216 if (ReadBlobString(image,buffer) == (char *) NULL)
217 break;
cristy3ed852e2009-09-05 21:47:34 +0000218 count=(ssize_t) sscanf(buffer,"%lu %lu\n",&columns,&rows);
219 if (count > 0)
220 {
221 /*
222 Allocate next image structure.
223 */
cristy9950d572011-10-01 18:22:35 +0000224 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000225 if (GetNextImageInList(image) == (Image *) NULL)
226 {
Cristy3b48d202018-07-01 17:11:51 -0400227 status=MagickFalse;
228 break;
cristy3ed852e2009-09-05 21:47:34 +0000229 }
230 image=SyncNextImageInList(image);
231 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
232 GetBlobSize(image));
233 if (status == MagickFalse)
234 break;
235 }
236 } while (count > 0);
237 (void) CloseBlob(image);
Cristy3b48d202018-07-01 17:11:51 -0400238 if (status == MagickFalse)
239 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000240 return(GetFirstImageInList(image));
241}
242
243/*
244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245% %
246% %
247% %
248% R e g i s t e r M T V I m a g e %
249% %
250% %
251% %
252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253%
254% RegisterMTVImage() adds attributes for the MTV image format to
255% the list of supported formats. The attributes include the image format
256% tag, a method to read and/or write the format, whether the format
257% supports the saving of more than one frame to the same file or blob,
258% whether the format supports native in-memory I/O, and a brief
259% description of the format.
260%
261% The format of the RegisterMTVImage method is:
262%
cristybb503372010-05-27 20:51:26 +0000263% size_t RegisterMTVImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000264%
265*/
cristybb503372010-05-27 20:51:26 +0000266ModuleExport size_t RegisterMTVImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000267{
268 MagickInfo
269 *entry;
270
dirk06b627a2015-04-06 18:59:17 +0000271 entry=AcquireMagickInfo("MTV","MTV","MTV Raytracing image format");
cristy3ed852e2009-09-05 21:47:34 +0000272 entry->decoder=(DecodeImageHandler *) ReadMTVImage;
273 entry->encoder=(EncodeImageHandler *) WriteMTVImage;
cristy3ed852e2009-09-05 21:47:34 +0000274 (void) RegisterMagickInfo(entry);
275 return(MagickImageCoderSignature);
276}
277
278/*
279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280% %
281% %
282% %
283% U n r e g i s t e r M T V I m a g e %
284% %
285% %
286% %
287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288%
289% UnregisterMTVImage() removes format registrations made by the
290% MTV module from the list of supported formats.
291%
292% The format of the UnregisterMTVImage method is:
293%
294% UnregisterMTVImage(void)
295%
296*/
297ModuleExport void UnregisterMTVImage(void)
298{
299 (void) UnregisterMagickInfo("MTV");
300}
301
302/*
303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304% %
305% %
306% %
307% W r i t e M T V I m a g e %
308% %
309% %
310% %
311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312%
cristyaff6d802011-04-26 01:46:31 +0000313% WriteMTVImage() writes an image to a file in red, green, and blue MTV
314% rasterfile format.
cristy3ed852e2009-09-05 21:47:34 +0000315%
316% The format of the WriteMTVImage method is:
317%
cristy1e178e72011-08-28 19:44:34 +0000318% MagickBooleanType WriteMTVImage(const ImageInfo *image_info,
319% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000320%
321% A description of each parameter follows.
322%
323% o image_info: the image info.
324%
325% o image: The image.
326%
cristy1e178e72011-08-28 19:44:34 +0000327% o exception: return any errors or warnings in this structure.
328%
cristy3ed852e2009-09-05 21:47:34 +0000329*/
cristy1e178e72011-08-28 19:44:34 +0000330static MagickBooleanType WriteMTVImage(const ImageInfo *image_info,Image *image,
331 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000332{
333 char
cristy151b66d2015-04-15 10:50:31 +0000334 buffer[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000335
cristy3ed852e2009-09-05 21:47:34 +0000336 MagickBooleanType
337 status;
338
339 MagickOffsetType
340 scene;
341
cristy4c08aed2011-07-01 19:47:50 +0000342 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000343 *p;
344
cristybb503372010-05-27 20:51:26 +0000345 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000346 x;
347
348 register unsigned char
349 *q;
350
Cristyc45b2bb2018-04-07 12:32:12 -0400351 size_t
352 imageListLength;
353
cristyaff6d802011-04-26 01:46:31 +0000354 ssize_t
355 y;
356
cristy3ed852e2009-09-05 21:47:34 +0000357 unsigned char
358 *pixels;
359
360 /*
361 Open output image file.
362 */
363 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000364 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000365 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000366 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000367 if (image->debug != MagickFalse)
368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000369 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000370 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +0000371 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000372 if (status == MagickFalse)
373 return(status);
374 scene=0;
Cristyc45b2bb2018-04-07 12:32:12 -0400375 imageListLength=GetImageListLength(image);
cristy3ed852e2009-09-05 21:47:34 +0000376 do
377 {
378 /*
379 Allocate memory for pixels.
380 */
cristyaf8d3912014-02-21 14:50:33 +0000381 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristybc4a1d42014-12-15 21:47:00 +0000382 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
cristy3ed852e2009-09-05 21:47:34 +0000383 3UL*sizeof(*pixels));
384 if (pixels == (unsigned char *) NULL)
385 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
386 /*
387 Initialize raster file header.
388 */
cristy151b66d2015-04-15 10:50:31 +0000389 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n",(double)
cristye8c25f92010-06-03 00:53:06 +0000390 image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000391 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +0000392 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000393 {
cristy1e178e72011-08-28 19:44:34 +0000394 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000395 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000396 break;
397 q=pixels;
cristybb503372010-05-27 20:51:26 +0000398 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000399 {
cristy4c08aed2011-07-01 19:47:50 +0000400 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
401 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
402 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
cristyed231572011-07-14 02:18:59 +0000403 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000404 }
405 (void) WriteBlob(image,(size_t) (q-pixels),pixels);
406 if (image->previous == (Image *) NULL)
407 {
cristycee97112010-05-28 00:44:52 +0000408 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy4c08aed2011-07-01 19:47:50 +0000409 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000410 if (status == MagickFalse)
411 break;
412 }
413 }
414 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
415 if (GetNextImageInList(image) == (Image *) NULL)
416 break;
417 image=SyncNextImageInList(image);
Cristyc45b2bb2018-04-07 12:32:12 -0400418 status=SetImageProgress(image,SaveImagesTag,scene,imageListLength);
cristy3ed852e2009-09-05 21:47:34 +0000419 if (status == MagickFalse)
420 break;
421 scene++;
422 } while (image_info->adjoin != MagickFalse);
423 (void) CloseBlob(image);
424 return(MagickTrue);
425}