1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % M M GGGG K K % 7 % MM MM G K K % 8 % M M M G GG KKK % 9 % M M G G K K % 10 % M M GGG K K % 11 % % 12 % % 13 % Read/Write MGK Image Format. % 14 % % 15 % Software Design % 16 % Cristy % 17 % July 1992 % 18 % % 19 % % 20 % Copyright 1999-2011 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 /* 41 Include declarations. 42 */ 43 #include "magick/studio.h" 44 #include "magick/blob.h" 45 #include "magick/blob-private.h" 46 #include "magick/cache.h" 47 #include "magick/colorspace.h" 48 #include "magick/exception.h" 49 #include "magick/exception-private.h" 50 #include "magick/image.h" 51 #include "magick/image-private.h" 52 #include "magick/list.h" 53 #include "magick/magick.h" 54 #include "magick/memory_.h" 55 #include "magick/monitor.h" 56 #include "magick/monitor-private.h" 57 #include "magick/quantum-private.h" 58 #include "magick/static.h" 59 #include "magick/string_.h" 60 #include "magick/module.h" 61 62 /* 64 Forward declarations. 65 */ 66 static MagickBooleanType 67 WriteMGKImage(const ImageInfo *,Image *); 68 69 /* 71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 72 % % 73 % % 74 % % 75 % I s M G K % 76 % % 77 % % 78 % % 79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 80 % 81 % IsMGK() returns MagickTrue if the image format type, identified by the 82 % magick string, is MGK. 83 % 84 % The format of the IsMGK method is: 85 % 86 % MagickBooleanType IsMGK(const unsigned char *magick,const size_t length) 87 % 88 % A description of each parameter follows: 89 % 90 % o magick: This string is generally the first few bytes of an image file 91 % or blob. 92 % 93 % o length: Specifies the length of the magick string. 94 % 95 */ 96 static MagickBooleanType IsMGK(const unsigned char *magick,const size_t length) 97 { 98 if (length < 7) 99 return(MagickFalse); 100 if (LocaleNCompare((char *) magick,"id=mgk",7) == 0) 101 return(MagickTrue); 102 return(MagickFalse); 103 } 104 105 /* 107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 108 % % 109 % % 110 % % 111 % R e a d M G K I m a g e % 112 % % 113 % % 114 % % 115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 116 % 117 % ReadMGKImage() reads a MGK image file and returns it. It allocates 118 % the memory necessary for the new Image structure and returns a pointer to 119 % the new image. 120 % 121 % The format of the ReadMGKImage method is: 122 % 123 % Image *ReadMGKImage(const ImageInfo *image_info, 124 % ExceptionInfo *exception) 125 % 126 % A description of each parameter follows: 127 % 128 % o image_info: the image info. 129 % 130 % o exception: return any errors or warnings in this structure. 131 % 132 */ 133 static Image *ReadMGKImage(const ImageInfo *image_info, 134 ExceptionInfo *exception) 135 { 136 char 137 buffer[MagickPathExtent]; 138 139 Image 140 *image; 141 142 MagickBooleanType 143 status; 144 145 register ssize_t 146 x; 147 148 register PixelPacket 149 *q; 150 151 register unsigned char 152 *p; 153 154 ssize_t 155 count, 156 y; 157 158 size_t 159 columns, 160 rows; 161 162 unsigned char 163 *pixels; 164 165 /* 166 Open image file. 167 */ 168 assert(image_info != (const ImageInfo *) NULL); 169 assert(image_info->signature == MagickSignature); 170 if (image_info->debug != MagickFalse) 171 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 172 image_info->filename); 173 assert(exception != (ExceptionInfo *) NULL); 174 assert(exception->signature == MagickSignature); 175 image=AcquireImage(image_info); 176 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 177 if (status == MagickFalse) 178 { 179 image=DestroyImageList(image); 180 return((Image *) NULL); 181 } 182 /* 183 Read MGK image. 184 */ 185 (void) ReadBlobString(image,buffer); /* read magic number */ 186 if (IsMGK(buffer,7) == MagickFalse) 187 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 188 (void) ReadBlobString(image,buffer); 189 count=(ssize_t) sscanf(buffer,"%lu %lu\n",&columns,&rows); 190 if (count <= 0) 191 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 192 do 193 { 194 /* 195 Initialize image structure. 196 */ 197 image->columns=columns; 198 image->rows=rows; 199 image->depth=8; 200 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) 201 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 202 break; 203 /* 204 Convert MGK raster image to pixel packets. 205 */ 206 if (SetImageExtent(image,0,0) == MagickFalse) 207 { 208 InheritException(exception,&image->exception); 209 return(DestroyImageList(image)); 210 } 211 pixels=(unsigned char *) AcquireQuantumMemory((size_t) image->columns, 212 3UL*sizeof(*pixels)); 213 if (pixels == (unsigned char *) NULL) 214 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 215 for (y=0; y < (ssize_t) image->rows; y++) 216 { 217 count=(ssize_t) ReadBlob(image,(size_t) (3*image->columns),pixels); 218 if (count != (ssize_t) (3*image->columns)) 219 ThrowReaderException(CorruptImageError,"UnableToReadImageData"); 220 p=pixels; 221 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 222 if (q == (PixelPacket *) NULL) 223 break; 224 for (x=0; x < (ssize_t) image->columns; x++) 225 { 226 SetPixelRed(q,ScaleCharToQuantum(*p++)); 227 SetPixelGreen(q,ScaleCharToQuantum(*p++)); 228 SetPixelBlue(q,ScaleCharToQuantum(*p++)); 229 q++; 230 } 231 if (SyncAuthenticPixels(image,exception) == MagickFalse) 232 break; 233 if ((image->previous == (Image *) NULL) && 234 (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)) 235 break; 236 } 237 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 238 if (EOFBlob(image) != MagickFalse) 239 { 240 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 241 image->filename); 242 break; 243 } 244 /* 245 Proceed to next image. 246 */ 247 if (image_info->number_scenes != 0) 248 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 249 break; 250 *buffer='\0'; 251 (void) ReadBlobString(image,buffer); 252 count=(ssize_t) sscanf(buffer,"%lu %lu\n",&columns,&rows); 253 if (count > 0) 254 { 255 /* 256 Allocate next image structure. 257 */ 258 AcquireNextImage(image_info,image); 259 if (GetNextImageInList(image) == (Image *) NULL) 260 { 261 image=DestroyImageList(image); 262 return((Image *) NULL); 263 } 264 image=SyncNextImageInList(image); 265 if (image->progress_monitor != (MagickProgressMonitor) NULL) 266 { 267 status=SetImageProgress(image,LoadImageTag,TellBlob(image), 268 GetBlobSize(image)); 269 if (status == MagickFalse) 270 break; 271 } 272 } 273 } while (count > 0); 274 (void) CloseBlob(image); 275 return(GetFirstImageInList(image)); 276 } 277 278 /* 280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 281 % % 282 % % 283 % % 284 % R e g i s t e r M G K I m a g e % 285 % % 286 % % 287 % % 288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 289 % 290 % RegisterMGKImage() adds attributes for the MGK image format to 291 % the list of supported formats. The attributes include the image format 292 % tag, a method to read and/or write the format, whether the format 293 % supports the saving of more than one frame to the same file or blob, 294 % whether the format supports native in-memory I/O, and a brief 295 % description of the format. 296 % 297 % The format of the RegisterMGKImage method is: 298 % 299 % size_t RegisterMGKImage(void) 300 % 301 */ 302 ModuleExport size_t RegisterMGKImage(void) 303 { 304 MagickInfo 305 *entry; 306 307 entry=SetMagickInfo("MGK"); 308 entry->decoder=(DecodeImageHandler *) ReadMGKImage; 309 entry->encoder=(EncodeImageHandler *) WriteMGKImage; 310 entry->magick=(IsImageFormatHandler *) IsMGK; 311 entry->description=ConstantString("MGK"); 312 entry->module=ConstantString("MGK"); 313 (void) RegisterMagickInfo(entry); 314 return(MagickImageCoderSignature); 315 } 316 317 /* 319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 320 % % 321 % % 322 % % 323 % U n r e g i s t e r M G K I m a g e % 324 % % 325 % % 326 % % 327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 328 % 329 % UnregisterMGKImage() removes format registrations made by the 330 % MGK module from the list of supported formats. 331 % 332 % The format of the UnregisterMGKImage method is: 333 % 334 % UnregisterMGKImage(void) 335 % 336 */ 337 ModuleExport void UnregisterMGKImage(void) 338 { 339 (void) UnregisterMagickInfo("MGK"); 340 } 341 342 /* 344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 345 % % 346 % % 347 % % 348 % W r i t e M G K I m a g e % 349 % % 350 % % 351 % % 352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 353 % 354 % WriteMGKImage() writes an image to a file in red, green, and blue 355 % MGK rasterfile format. 356 % 357 % The format of the WriteMGKImage method is: 358 % 359 % MagickBooleanType WriteMGKImage(const ImageInfo *image_info, 360 % Image *image) 361 % 362 % A description of each parameter follows. 363 % 364 % o image_info: the image info. 365 % 366 % o image: The image. 367 % 368 */ 369 static MagickBooleanType WriteMGKImage(const ImageInfo *image_info, 370 Image *image) 371 { 372 char 373 buffer[MagickPathExtent]; 374 375 MagickBooleanType 376 status; 377 378 MagickOffsetType 379 scene; 380 381 register const PixelPacket 382 *p; 383 384 register ssize_t 385 x; 386 387 register unsigned char 388 *q; 389 390 ssize_t 391 y; 392 393 unsigned char 394 *pixels; 395 396 /* 397 Open output image file. 398 */ 399 assert(image_info != (const ImageInfo *) NULL); 400 assert(image_info->signature == MagickSignature); 401 assert(image != (Image *) NULL); 402 assert(image->signature == MagickSignature); 403 if (image->debug != MagickFalse) 404 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 405 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); 406 if (status == MagickFalse) 407 return(status); 408 scene=0; 409 do 410 { 411 /* 412 Allocate memory for pixels. 413 */ 414 if (image->colorspace != RGBColorspace) 415 (void) SetImageColorspace(image,RGBColorspace); 416 pixels=(unsigned char *) AcquireQuantumMemory((size_t) image->columns, 417 3UL*sizeof(*pixels)); 418 if (pixels == (unsigned char *) NULL) 419 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 420 /* 421 Initialize raster file header. 422 */ 423 (void) WriteBlobString(image,"id=mgk\n"); 424 (void) FormatMagickString(buffer,MagickPathExtent,"%lu %lu\n",image->columns, 425 image->rows); 426 (void) WriteBlobString(image,buffer); 427 for (y=0; y < (ssize_t) image->rows; y++) 428 { 429 p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); 430 if (p == (const PixelPacket *) NULL) 431 break; 432 q=pixels; 433 for (x=0; x < (ssize_t) image->columns; x++) 434 { 435 *q++=ScaleQuantumToChar(GetRedSample(p)); 436 *q++=ScaleQuantumToChar(GetGreenSample(p)); 437 *q++=ScaleQuantumToChar(GetBlueSample(p)); 438 p++; 439 } 440 (void) WriteBlob(image,(size_t) (q-pixels),pixels); 441 if ((image->previous == (Image *) NULL) && 442 (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)) 443 break; 444 } 445 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 446 if (GetNextImageInList(image) == (Image *) NULL) 447 break; 448 image=SyncNextImageInList(image); 449 status=SetImageProgress(image,SaveImagesTag,scene, 450 GetImageListLength(image)); 451 if (status == MagickFalse) 452 break; 453 scene++; 454 } while (image_info->adjoin != MagickFalse); 455 (void) CloseBlob(image); 456 return(MagickTrue); 457 } 458