1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% RRRR AAA W W % 7% R R A A W W % 8% RRRR AAAAA W W W % 9% R R A A WW WW % 10% R R A A W W % 11% % 12% % 13% Read/Write RAW 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/constitute.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/quantum-private.h" 60#include "MagickCore/static.h" 61#include "MagickCore/statistic.h" 62#include "MagickCore/string_.h" 63#include "MagickCore/module.h" 64 65/* 66 Forward declarations. 67*/ 68static MagickBooleanType 69 WriteRAWImage(const ImageInfo *,Image *,ExceptionInfo *); 70 71/* 72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 73% % 74% % 75% % 76% R e a d R A W I m a g e % 77% % 78% % 79% % 80%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 81% 82% ReadRAWImage() reads an image of raw samples and returns it. It allocates 83% the memory necessary for the new Image structure and returns a pointer to 84% the new image. 85% 86% The format of the ReadRAWImage method is: 87% 88% Image *ReadRAWImage(const ImageInfo *image_info,ExceptionInfo *exception) 89% 90% A description of each parameter follows: 91% 92% o image_info: the image info. 93% 94% o exception: return any errors or warnings in this structure. 95% 96*/ 97static Image *ReadRAWImage(const ImageInfo *image_info,ExceptionInfo *exception) 98{ 99 const unsigned char 100 *pixels; 101 102 Image 103 *canvas_image, 104 *image; 105 106 MagickBooleanType 107 status; 108 109 MagickOffsetType 110 scene; 111 112 QuantumInfo 113 *quantum_info; 114 115 QuantumType 116 quantum_type; 117 118 size_t 119 length; 120 121 ssize_t 122 count, 123 y; 124 125 /* 126 Open image file. 127 */ 128 assert(image_info != (const ImageInfo *) NULL); 129 assert(image_info->signature == MagickCoreSignature); 130 if (image_info->debug != MagickFalse) 131 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 132 image_info->filename); 133 assert(exception != (ExceptionInfo *) NULL); 134 assert(exception->signature == MagickCoreSignature); 135 image=AcquireImage(image_info,exception); 136 if ((image->columns == 0) || (image->rows == 0)) 137 ThrowReaderException(OptionError,"MustSpecifyImageSize"); 138 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 139 if (status == MagickFalse) 140 { 141 image=DestroyImageList(image); 142 return((Image *) NULL); 143 } 144 if (DiscardBlobBytes(image,image->offset) == MagickFalse) 145 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 146 image->filename); 147 /* 148 Create virtual canvas to support cropping (i.e. image.gray[100x100+10+20]). 149 */ 150 canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse, 151 exception); 152 (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod, 153 exception); 154 quantum_type=GrayQuantum; 155 quantum_info=AcquireQuantumInfo(image_info,canvas_image); 156 if (quantum_info == (QuantumInfo *) NULL) 157 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 158 pixels=(const unsigned char *) NULL; 159 if (image_info->number_scenes != 0) 160 while (image->scene < image_info->scene) 161 { 162 /* 163 Skip to next image. 164 */ 165 image->scene++; 166 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type); 167 for (y=0; y < (ssize_t) image->rows; y++) 168 { 169 pixels=(const unsigned char *) ReadBlobStream(image,length, 170 GetQuantumPixels(quantum_info),&count); 171 if (count != (ssize_t) length) 172 break; 173 } 174 } 175 scene=0; 176 count=0; 177 length=0; 178 do 179 { 180 /* 181 Read pixels to virtual canvas image then push to image. 182 */ 183 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) 184 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 185 break; 186 status=SetImageExtent(image,image->columns,image->rows,exception); 187 if (status == MagickFalse) 188 return(DestroyImageList(image)); 189 if (scene == 0) 190 { 191 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type); 192 pixels=(const unsigned char *) ReadBlobStream(image,length, 193 GetQuantumPixels(quantum_info),&count); 194 } 195 for (y=0; y < (ssize_t) image->extract_info.height; y++) 196 { 197 register const Quantum 198 *magick_restrict p; 199 200 register Quantum 201 *magick_restrict q; 202 203 register ssize_t 204 x; 205 206 if (count != (ssize_t) length) 207 { 208 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 209 image->filename); 210 break; 211 } 212 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,exception); 213 if (q == (Quantum *) NULL) 214 break; 215 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,quantum_info, 216 quantum_type,pixels,exception); 217 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) 218 break; 219 if (((y-image->extract_info.y) >= 0) && 220 ((y-image->extract_info.y) < (ssize_t) image->rows)) 221 { 222 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, 223 image->columns,1,exception); 224 q=QueueAuthenticPixels(image,0,y-image->extract_info.y,image->columns, 225 1,exception); 226 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 227 break; 228 for (x=0; x < (ssize_t) image->columns; x++) 229 { 230 SetPixelRed(image,GetPixelRed(canvas_image,p),q); 231 SetPixelGreen(image,GetPixelGreen(canvas_image,p),q); 232 SetPixelBlue(image,GetPixelBlue(canvas_image,p),q); 233 p+=GetPixelChannels(canvas_image); 234 q+=GetPixelChannels(image); 235 } 236 if (SyncAuthenticPixels(image,exception) == MagickFalse) 237 break; 238 } 239 if (image->previous == (Image *) NULL) 240 { 241 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 242 image->rows); 243 if (status == MagickFalse) 244 break; 245 } 246 pixels=(const unsigned char *) ReadBlobStream(image,length, 247 GetQuantumPixels(quantum_info),&count); 248 } 249 SetQuantumImageType(image,quantum_type); 250 /* 251 Proceed to next image. 252 */ 253 if (image_info->number_scenes != 0) 254 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 255 break; 256 if (count == (ssize_t) length) 257 { 258 /* 259 Allocate next image structure. 260 */ 261 AcquireNextImage(image_info,image,exception); 262 if (GetNextImageInList(image) == (Image *) NULL) 263 { 264 image=DestroyImageList(image); 265 return((Image *) NULL); 266 } 267 image=SyncNextImageInList(image); 268 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 269 GetBlobSize(image)); 270 if (status == MagickFalse) 271 break; 272 } 273 scene++; 274 } while (count == (ssize_t) length); 275 quantum_info=DestroyQuantumInfo(quantum_info); 276 canvas_image=DestroyImage(canvas_image); 277 (void) CloseBlob(image); 278 return(GetFirstImageInList(image)); 279} 280 281/* 282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 283% % 284% % 285% % 286% R e g i s t e r R A W I m a g e % 287% % 288% % 289% % 290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 291% 292% RegisterRAWImage() adds attributes for the RAW image format to the list of 293% supported formats. The attributes include the image format tag, a method to 294% read and/or write the format, whether the format supports the saving of 295% more than one frame to the same file or blob, whether the format supports 296% native in-memory I/O, and a brief description of the format. 297% 298% The format of the RegisterRAWImage method is: 299% 300% size_t RegisterRAWImage(void) 301% 302*/ 303ModuleExport size_t RegisterRAWImage(void) 304{ 305 MagickInfo 306 *entry; 307 308 entry=AcquireMagickInfo("RAW","R","Raw red samples"); 309 entry->decoder=(DecodeImageHandler *) ReadRAWImage; 310 entry->encoder=(EncodeImageHandler *) WriteRAWImage; 311 entry->flags|=CoderRawSupportFlag; 312 entry->flags|=CoderEndianSupportFlag; 313 entry->format_type=ImplicitFormatType; 314 (void) RegisterMagickInfo(entry); 315 entry=AcquireMagickInfo("RAW","C","Raw cyan samples"); 316 entry->decoder=(DecodeImageHandler *) ReadRAWImage; 317 entry->encoder=(EncodeImageHandler *) WriteRAWImage; 318 entry->flags|=CoderRawSupportFlag; 319 entry->flags|=CoderEndianSupportFlag; 320 entry->format_type=ImplicitFormatType; 321 (void) RegisterMagickInfo(entry); 322 entry=AcquireMagickInfo("RAW","G","Raw green samples"); 323 entry->decoder=(DecodeImageHandler *) ReadRAWImage; 324 entry->encoder=(EncodeImageHandler *) WriteRAWImage; 325 entry->flags|=CoderRawSupportFlag; 326 entry->flags|=CoderEndianSupportFlag; 327 entry->format_type=ImplicitFormatType; 328 (void) RegisterMagickInfo(entry); 329 entry=AcquireMagickInfo("RAW","M","Raw magenta samples"); 330 entry->decoder=(DecodeImageHandler *) ReadRAWImage; 331 entry->encoder=(EncodeImageHandler *) WriteRAWImage; 332 entry->flags|=CoderRawSupportFlag; 333 entry->flags|=CoderEndianSupportFlag; 334 entry->format_type=ImplicitFormatType; 335 (void) RegisterMagickInfo(entry); 336 entry=AcquireMagickInfo("RAW","B","Raw blue samples"); 337 entry->decoder=(DecodeImageHandler *) ReadRAWImage; 338 entry->encoder=(EncodeImageHandler *) WriteRAWImage; 339 entry->flags|=CoderRawSupportFlag; 340 entry->flags|=CoderEndianSupportFlag; 341 entry->format_type=ImplicitFormatType; 342 (void) RegisterMagickInfo(entry); 343 entry=AcquireMagickInfo("RAW","Y","Raw yellow samples"); 344 entry->decoder=(DecodeImageHandler *) ReadRAWImage; 345 entry->encoder=(EncodeImageHandler *) WriteRAWImage; 346 entry->flags|=CoderRawSupportFlag; 347 entry->flags|=CoderEndianSupportFlag; 348 entry->format_type=ImplicitFormatType; 349 (void) RegisterMagickInfo(entry); 350 entry=AcquireMagickInfo("RAW","A","Raw alpha samples"); 351 entry->decoder=(DecodeImageHandler *) ReadRAWImage; 352 entry->encoder=(EncodeImageHandler *) WriteRAWImage; 353 entry->flags|=CoderRawSupportFlag; 354 entry->flags|=CoderEndianSupportFlag; 355 entry->format_type=ImplicitFormatType; 356 (void) RegisterMagickInfo(entry); 357 entry=AcquireMagickInfo("RAW","O","Raw opacity samples"); 358 entry->decoder=(DecodeImageHandler *) ReadRAWImage; 359 entry->encoder=(EncodeImageHandler *) WriteRAWImage; 360 entry->flags|=CoderRawSupportFlag; 361 entry->flags|=CoderEndianSupportFlag; 362 entry->format_type=ImplicitFormatType; 363 (void) RegisterMagickInfo(entry); 364 entry=AcquireMagickInfo("RAW","K","Raw black samples"); 365 entry->decoder=(DecodeImageHandler *) ReadRAWImage; 366 entry->encoder=(EncodeImageHandler *) WriteRAWImage; 367 entry->flags|=CoderRawSupportFlag; 368 entry->flags|=CoderEndianSupportFlag; 369 entry->format_type=ImplicitFormatType; 370 (void) RegisterMagickInfo(entry); 371 return(MagickImageCoderSignature); 372} 373 374/* 375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 376% % 377% % 378% % 379% U n r e g i s t e r R A W I m a g e % 380% % 381% % 382% % 383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 384% 385% UnregisterRAWImage() removes format registrations made by the RAW module 386% from the list of supported formats. 387% 388% The format of the UnregisterRAWImage method is: 389% 390% UnregisterRAWImage(void) 391% 392*/ 393ModuleExport void UnregisterRAWImage(void) 394{ 395 (void) UnregisterMagickInfo("R"); 396 (void) UnregisterMagickInfo("C"); 397 (void) UnregisterMagickInfo("G"); 398 (void) UnregisterMagickInfo("M"); 399 (void) UnregisterMagickInfo("B"); 400 (void) UnregisterMagickInfo("Y"); 401 (void) UnregisterMagickInfo("A"); 402 (void) UnregisterMagickInfo("O"); 403 (void) UnregisterMagickInfo("K"); 404} 405 406/* 407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 408% % 409% % 410% % 411% W r i t e R A W I m a g e % 412% % 413% % 414% % 415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 416% 417% WriteRAWImage() writes an image to a file as raw intensity values. 418% 419% The format of the WriteRAWImage method is: 420% 421% MagickBooleanType WriteRAWImage(const ImageInfo *image_info, 422% Image *image,ExceptionInfo *exception) 423% 424% A description of each parameter follows. 425% 426% o image_info: the image info. 427% 428% o image: The image. 429% 430% o exception: return any errors or warnings in this structure. 431% 432*/ 433static MagickBooleanType WriteRAWImage(const ImageInfo *image_info,Image *image, 434 ExceptionInfo *exception) 435{ 436 MagickOffsetType 437 scene; 438 439 QuantumInfo 440 *quantum_info; 441 442 QuantumType 443 quantum_type; 444 445 MagickBooleanType 446 status; 447 448 register const Quantum 449 *p; 450 451 size_t 452 length; 453 454 ssize_t 455 count, 456 y; 457 458 unsigned char 459 *pixels; 460 461 /* 462 Open output image file. 463 */ 464 assert(image_info != (const ImageInfo *) NULL); 465 assert(image_info->signature == MagickCoreSignature); 466 assert(image != (Image *) NULL); 467 assert(image->signature == MagickCoreSignature); 468 if (image->debug != MagickFalse) 469 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 470 assert(exception != (ExceptionInfo *) NULL); 471 assert(exception->signature == MagickCoreSignature); 472 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 473 if (status == MagickFalse) 474 return(status); 475 switch (*image->magick) 476 { 477 case 'A': 478 case 'a': 479 { 480 quantum_type=AlphaQuantum; 481 break; 482 } 483 case 'B': 484 case 'b': 485 { 486 quantum_type=BlueQuantum; 487 break; 488 } 489 case 'C': 490 case 'c': 491 { 492 quantum_type=CyanQuantum; 493 if (image->colorspace == CMYKColorspace) 494 break; 495 ThrowWriterException(ImageError,"ColorSeparatedImageRequired"); 496 } 497 case 'g': 498 case 'G': 499 { 500 quantum_type=GreenQuantum; 501 break; 502 } 503 case 'I': 504 case 'i': 505 { 506 quantum_type=IndexQuantum; 507 break; 508 } 509 case 'K': 510 case 'k': 511 { 512 quantum_type=BlackQuantum; 513 if (image->colorspace == CMYKColorspace) 514 break; 515 ThrowWriterException(ImageError,"ColorSeparatedImageRequired"); 516 } 517 case 'M': 518 case 'm': 519 { 520 quantum_type=MagentaQuantum; 521 if (image->colorspace == CMYKColorspace) 522 break; 523 ThrowWriterException(ImageError,"ColorSeparatedImageRequired"); 524 } 525 case 'o': 526 case 'O': 527 { 528 quantum_type=OpacityQuantum; 529 break; 530 } 531 case 'R': 532 case 'r': 533 { 534 quantum_type=RedQuantum; 535 break; 536 } 537 case 'Y': 538 case 'y': 539 { 540 quantum_type=YellowQuantum; 541 if (image->colorspace == CMYKColorspace) 542 break; 543 ThrowWriterException(ImageError,"ColorSeparatedImageRequired"); 544 } 545 default: 546 { 547 quantum_type=GrayQuantum; 548 break; 549 } 550 } 551 scene=0; 552 do 553 { 554 /* 555 Convert image to RAW raster pixels. 556 */ 557 quantum_info=AcquireQuantumInfo(image_info,image); 558 if (quantum_info == (QuantumInfo *) NULL) 559 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 560 pixels=(unsigned char *) GetQuantumPixels(quantum_info); 561 for (y=0; y < (ssize_t) image->rows; y++) 562 { 563 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 564 if (p == (const Quantum *) NULL) 565 break; 566 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info, 567 quantum_type,pixels,exception); 568 count=WriteBlob(image,length,pixels); 569 if (count != (ssize_t) length) 570 break; 571 if (image->previous == (Image *) NULL) 572 { 573 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 574 image->rows); 575 if (status == MagickFalse) 576 break; 577 } 578 } 579 quantum_info=DestroyQuantumInfo(quantum_info); 580 if (GetNextImageInList(image) == (Image *) NULL) 581 break; 582 image=SyncNextImageInList(image); 583 status=SetImageProgress(image,SaveImagesTag,scene++, 584 GetImageListLength(image)); 585 if (status == MagickFalse) 586 break; 587 } while (image_info->adjoin != MagickFalse); 588 (void) CloseBlob(image); 589 return(MagickTrue); 590} 591