1/* 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 % 16% Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2016 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% http://www.imagemagick.org/script/license.php % 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-accessor.h" 58#include "MagickCore/quantum-private.h" 59#include "MagickCore/static.h" 60#include "MagickCore/string_.h" 61#include "MagickCore/module.h" 62 63/* 64 Forward declarations. 65*/ 66static MagickBooleanType 67 WriteMTVImage(const ImageInfo *,Image *,ExceptionInfo *); 68 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 98 buffer[MagickPathExtent]; 99 100 Image 101 *image; 102 103 MagickBooleanType 104 status; 105 106 register ssize_t 107 x; 108 109 register Quantum 110 *q; 111 112 register unsigned char 113 *p; 114 115 ssize_t 116 count, 117 y; 118 119 unsigned char 120 *pixels; 121 122 unsigned long 123 columns, 124 rows; 125 126 /* 127 Open image file. 128 */ 129 assert(image_info != (const ImageInfo *) NULL); 130 assert(image_info->signature == MagickCoreSignature); 131 if (image_info->debug != MagickFalse) 132 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 133 image_info->filename); 134 assert(exception != (ExceptionInfo *) NULL); 135 assert(exception->signature == MagickCoreSignature); 136 image=AcquireImage(image_info,exception); 137 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 */ 146 (void) ReadBlobString(image,buffer); 147 count=(ssize_t) sscanf(buffer,"%lu %lu\n",&columns,&rows); 148 if (count <= 0) 149 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 150 do 151 { 152 /* 153 Initialize image structure. 154 */ 155 image->columns=columns; 156 image->rows=rows; 157 image->depth=8; 158 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) 159 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 160 break; 161 status=SetImageExtent(image,image->columns,image->rows,exception); 162 if (status == MagickFalse) 163 return(DestroyImageList(image)); 164 /* 165 Convert MTV raster image to pixel packets. 166 */ 167 pixels=(unsigned char *) AcquireQuantumMemory(image->columns, 168 3UL*sizeof(*pixels)); 169 if (pixels == (unsigned char *) NULL) 170 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 171 for (y=0; y < (ssize_t) image->rows; y++) 172 { 173 count=(ssize_t) ReadBlob(image,(size_t) (3*image->columns),pixels); 174 if (count != (ssize_t) (3*image->columns)) 175 ThrowReaderException(CorruptImageError,"UnableToReadImageData"); 176 p=pixels; 177 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 178 if (q == (Quantum *) NULL) 179 break; 180 for (x=0; x < (ssize_t) image->columns; x++) 181 { 182 SetPixelRed(image,ScaleCharToQuantum(*p++),q); 183 SetPixelGreen(image,ScaleCharToQuantum(*p++),q); 184 SetPixelBlue(image,ScaleCharToQuantum(*p++),q); 185 SetPixelAlpha(image,OpaqueAlpha,q); 186 q+=GetPixelChannels(image); 187 } 188 if (SyncAuthenticPixels(image,exception) == MagickFalse) 189 break; 190 if (image->previous == (Image *) NULL) 191 { 192 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 193 image->rows); 194 if (status == MagickFalse) 195 break; 196 } 197 } 198 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 199 if (EOFBlob(image) != MagickFalse) 200 { 201 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 202 image->filename); 203 break; 204 } 205 /* 206 Proceed to next image. 207 */ 208 if (image_info->number_scenes != 0) 209 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 210 break; 211 *buffer='\0'; 212 (void) ReadBlobString(image,buffer); 213 count=(ssize_t) sscanf(buffer,"%lu %lu\n",&columns,&rows); 214 if (count > 0) 215 { 216 /* 217 Allocate next image structure. 218 */ 219 AcquireNextImage(image_info,image,exception); 220 if (GetNextImageInList(image) == (Image *) NULL) 221 { 222 image=DestroyImageList(image); 223 return((Image *) NULL); 224 } 225 image=SyncNextImageInList(image); 226 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 227 GetBlobSize(image)); 228 if (status == MagickFalse) 229 break; 230 } 231 } while (count > 0); 232 (void) CloseBlob(image); 233 return(GetFirstImageInList(image)); 234} 235 236/* 237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 238% % 239% % 240% % 241% R e g i s t e r M T V I m a g e % 242% % 243% % 244% % 245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 246% 247% RegisterMTVImage() adds attributes for the MTV image format to 248% the list of supported formats. The attributes include the image format 249% tag, a method to read and/or write the format, whether the format 250% supports the saving of more than one frame to the same file or blob, 251% whether the format supports native in-memory I/O, and a brief 252% description of the format. 253% 254% The format of the RegisterMTVImage method is: 255% 256% size_t RegisterMTVImage(void) 257% 258*/ 259ModuleExport size_t RegisterMTVImage(void) 260{ 261 MagickInfo 262 *entry; 263 264 entry=AcquireMagickInfo("MTV","MTV","MTV Raytracing image format"); 265 entry->decoder=(DecodeImageHandler *) ReadMTVImage; 266 entry->encoder=(EncodeImageHandler *) WriteMTVImage; 267 (void) RegisterMagickInfo(entry); 268 return(MagickImageCoderSignature); 269} 270 271/* 272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 273% % 274% % 275% % 276% U n r e g i s t e r M T V I m a g e % 277% % 278% % 279% % 280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 281% 282% UnregisterMTVImage() removes format registrations made by the 283% MTV module from the list of supported formats. 284% 285% The format of the UnregisterMTVImage method is: 286% 287% UnregisterMTVImage(void) 288% 289*/ 290ModuleExport void UnregisterMTVImage(void) 291{ 292 (void) UnregisterMagickInfo("MTV"); 293} 294 295/* 296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 297% % 298% % 299% % 300% W r i t e M T V I m a g e % 301% % 302% % 303% % 304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 305% 306% WriteMTVImage() writes an image to a file in red, green, and blue MTV 307% rasterfile format. 308% 309% The format of the WriteMTVImage method is: 310% 311% MagickBooleanType WriteMTVImage(const ImageInfo *image_info, 312% Image *image,ExceptionInfo *exception) 313% 314% A description of each parameter follows. 315% 316% o image_info: the image info. 317% 318% o image: The image. 319% 320% o exception: return any errors or warnings in this structure. 321% 322*/ 323static MagickBooleanType WriteMTVImage(const ImageInfo *image_info,Image *image, 324 ExceptionInfo *exception) 325{ 326 char 327 buffer[MagickPathExtent]; 328 329 MagickBooleanType 330 status; 331 332 MagickOffsetType 333 scene; 334 335 register const Quantum 336 *p; 337 338 register ssize_t 339 x; 340 341 register unsigned char 342 *q; 343 344 ssize_t 345 y; 346 347 unsigned char 348 *pixels; 349 350 /* 351 Open output image file. 352 */ 353 assert(image_info != (const ImageInfo *) NULL); 354 assert(image_info->signature == MagickCoreSignature); 355 assert(image != (Image *) NULL); 356 assert(image->signature == MagickCoreSignature); 357 if (image->debug != MagickFalse) 358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 359 assert(exception != (ExceptionInfo *) NULL); 360 assert(exception->signature == MagickCoreSignature); 361 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 362 if (status == MagickFalse) 363 return(status); 364 scene=0; 365 do 366 { 367 /* 368 Allocate memory for pixels. 369 */ 370 (void) TransformImageColorspace(image,sRGBColorspace,exception); 371 pixels=(unsigned char *) AcquireQuantumMemory(image->columns, 372 3UL*sizeof(*pixels)); 373 if (pixels == (unsigned char *) NULL) 374 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 375 /* 376 Initialize raster file header. 377 */ 378 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n",(double) 379 image->columns,(double) image->rows); 380 (void) WriteBlobString(image,buffer); 381 for (y=0; y < (ssize_t) image->rows; y++) 382 { 383 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 384 if (p == (const Quantum *) NULL) 385 break; 386 q=pixels; 387 for (x=0; x < (ssize_t) image->columns; x++) 388 { 389 *q++=ScaleQuantumToChar(GetPixelRed(image,p)); 390 *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); 391 *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); 392 p+=GetPixelChannels(image); 393 } 394 (void) WriteBlob(image,(size_t) (q-pixels),pixels); 395 if (image->previous == (Image *) NULL) 396 { 397 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 398 image->rows); 399 if (status == MagickFalse) 400 break; 401 } 402 } 403 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 404 if (GetNextImageInList(image) == (Image *) NULL) 405 break; 406 image=SyncNextImageInList(image); 407 status=SetImageProgress(image,SaveImagesTag,scene, 408 GetImageListLength(image)); 409 if (status == MagickFalse) 410 break; 411 scene++; 412 } while (image_info->adjoin != MagickFalse); 413 (void) CloseBlob(image); 414 return(MagickTrue); 415} 416