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