1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % GGGG RRRR AAA Y Y % 7 % G R R A A Y Y % 8 % G GG RRRR AAAAA Y % 9 % G G R R A A Y % 10 % GGG R R A A Y % 11 % % 12 % % 13 % Read/Write RAW Gray 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/attribute.h" 45 #include "MagickCore/blob.h" 46 #include "MagickCore/blob-private.h" 47 #include "MagickCore/cache.h" 48 #include "MagickCore/colorspace.h" 49 #include "MagickCore/colorspace-private.h" 50 #include "MagickCore/constitute.h" 51 #include "MagickCore/exception.h" 52 #include "MagickCore/exception-private.h" 53 #include "MagickCore/image.h" 54 #include "MagickCore/image-private.h" 55 #include "MagickCore/list.h" 56 #include "MagickCore/magick.h" 57 #include "MagickCore/memory_.h" 58 #include "MagickCore/monitor.h" 59 #include "MagickCore/monitor-private.h" 60 #include "MagickCore/pixel.h" 61 #include "MagickCore/pixel-accessor.h" 62 #include "MagickCore/quantum-private.h" 63 #include "MagickCore/static.h" 64 #include "MagickCore/statistic.h" 65 #include "MagickCore/string_.h" 66 #include "MagickCore/module.h" 67 68 /* 70 Forward declarations. 71 */ 72 static MagickBooleanType 73 WriteGRAYImage(const ImageInfo *,Image *,ExceptionInfo *); 74 75 /* 77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 78 % % 79 % % 80 % % 81 % R e a d G R A Y I m a g e % 82 % % 83 % % 84 % % 85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 86 % 87 % ReadGRAYImage() reads an image of raw grayscale samples and returns 88 % it. It allocates the memory necessary for the new Image structure and 89 % returns a pointer to the new image. 90 % 91 % The format of the ReadGRAYImage method is: 92 % 93 % Image *ReadGRAYImage(const ImageInfo *image_info, 94 % ExceptionInfo *exception) 95 % 96 % A description of each parameter follows: 97 % 98 % o image_info: the image info. 99 % 100 % o exception: return any errors or warnings in this structure. 101 % 102 */ 103 static Image *ReadGRAYImage(const ImageInfo *image_info, 104 ExceptionInfo *exception) 105 { 106 const unsigned char 107 *pixels; 108 109 Image 110 *canvas_image, 111 *image; 112 113 MagickBooleanType 114 status; 115 116 MagickOffsetType 117 scene; 118 119 QuantumInfo 120 *quantum_info; 121 122 QuantumType 123 quantum_type; 124 125 size_t 126 length; 127 128 ssize_t 129 count, 130 y; 131 132 /* 133 Open image file. 134 */ 135 assert(image_info != (const ImageInfo *) NULL); 136 assert(image_info->signature == MagickCoreSignature); 137 if (image_info->debug != MagickFalse) 138 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 139 image_info->filename); 140 assert(exception != (ExceptionInfo *) NULL); 141 assert(exception->signature == MagickCoreSignature); 142 image=AcquireImage(image_info,exception); 143 if ((image->columns == 0) || (image->rows == 0)) 144 ThrowReaderException(OptionError,"MustSpecifyImageSize"); 145 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 146 if (status == MagickFalse) 147 { 148 image=DestroyImageList(image); 149 return((Image *) NULL); 150 } 151 if (DiscardBlobBytes(image,(size_t) image->offset) == MagickFalse) 152 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 153 image->filename); 154 /* 155 Create virtual canvas to support cropping (i.e. image.gray[100x100+10+20]). 156 */ 157 SetImageColorspace(image,GRAYColorspace,exception); 158 canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse, 159 exception); 160 (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod, 161 exception); 162 quantum_type=GrayQuantum; 163 quantum_info=AcquireQuantumInfo(image_info,canvas_image); 164 if (quantum_info == (QuantumInfo *) NULL) 165 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 166 pixels=(const unsigned char *) NULL; 167 if (image_info->number_scenes != 0) 168 while (image->scene < image_info->scene) 169 { 170 /* 171 Skip to next image. 172 */ 173 image->scene++; 174 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type); 175 for (y=0; y < (ssize_t) image->rows; y++) 176 { 177 pixels=(const unsigned char *) ReadBlobStream(image,length, 178 GetQuantumPixels(quantum_info),&count); 179 if (count != (ssize_t) length) 180 break; 181 } 182 } 183 scene=0; 184 count=0; 185 length=0; 186 do 187 { 188 /* 189 Read pixels to virtual canvas image then push to image. 190 */ 191 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) 192 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 193 break; 194 status=SetImageExtent(image,image->columns,image->rows,exception); 195 if (status == MagickFalse) 196 return(DestroyImageList(image)); 197 SetImageColorspace(image,GRAYColorspace,exception); 198 if (scene == 0) 199 { 200 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type); 201 pixels=(const unsigned char *) ReadBlobStream(image,length, 202 GetQuantumPixels(quantum_info),&count); 203 } 204 for (y=0; y < (ssize_t) image->extract_info.height; y++) 205 { 206 register const Quantum 207 *magick_restrict p; 208 209 register ssize_t 210 x; 211 212 register Quantum 213 *magick_restrict q; 214 215 if (count != (ssize_t) length) 216 { 217 ThrowFileException(exception,CorruptImageError, 218 "UnexpectedEndOfFile",image->filename); 219 break; 220 } 221 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,exception); 222 if (q == (Quantum *) NULL) 223 break; 224 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,quantum_info, 225 quantum_type,pixels,exception); 226 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) 227 break; 228 if (((y-image->extract_info.y) >= 0) && 229 ((y-image->extract_info.y) < (ssize_t) image->rows)) 230 { 231 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, 232 image->columns,1,exception); 233 q=QueueAuthenticPixels(image,0,y-image->extract_info.y,image->columns, 234 1,exception); 235 if ((p == (const Quantum *) NULL) || 236 (q == (Quantum *) NULL)) 237 break; 238 for (x=0; x < (ssize_t) image->columns; x++) 239 { 240 SetPixelGray(image,GetPixelGray(canvas_image,p),q); 241 p+=GetPixelChannels(canvas_image); 242 q+=GetPixelChannels(image); 243 } 244 if (SyncAuthenticPixels(image,exception) == MagickFalse) 245 break; 246 } 247 if (image->previous == (Image *) NULL) 248 { 249 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 250 image->rows); 251 if (status == MagickFalse) 252 break; 253 } 254 pixels=(const unsigned char *) ReadBlobStream(image,length, 255 GetQuantumPixels(quantum_info),&count); 256 } 257 SetQuantumImageType(image,quantum_type); 258 /* 259 Proceed to next image. 260 */ 261 if (image_info->number_scenes != 0) 262 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 263 break; 264 if (count == (ssize_t) length) 265 { 266 /* 267 Allocate next image structure. 268 */ 269 AcquireNextImage(image_info,image,exception); 270 if (GetNextImageInList(image) == (Image *) NULL) 271 { 272 image=DestroyImageList(image); 273 return((Image *) NULL); 274 } 275 image=SyncNextImageInList(image); 276 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 277 GetBlobSize(image)); 278 if (status == MagickFalse) 279 break; 280 } 281 scene++; 282 } while (count == (ssize_t) length); 283 quantum_info=DestroyQuantumInfo(quantum_info); 284 canvas_image=DestroyImage(canvas_image); 285 (void) CloseBlob(image); 286 return(GetFirstImageInList(image)); 287 } 288 289 /* 291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 292 % % 293 % % 294 % % 295 % R e g i s t e r G R A Y I m a g e % 296 % % 297 % % 298 % % 299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 300 % 301 % RegisterGRAYImage() adds attributes for the GRAY image format to 302 % the list of supported formats. The attributes include the image format 303 % tag, a method to read and/or write the format, whether the format 304 % supports the saving of more than one frame to the same file or blob, 305 % whether the format supports native in-memory I/O, and a brief 306 % description of the format. 307 % 308 % The format of the RegisterGRAYImage method is: 309 % 310 % size_t RegisterGRAYImage(void) 311 % 312 */ 313 ModuleExport size_t RegisterGRAYImage(void) 314 { 315 MagickInfo 316 *entry; 317 318 entry=AcquireMagickInfo("GRAY","GRAY","Raw gray samples"); 319 entry->decoder=(DecodeImageHandler *) ReadGRAYImage; 320 entry->encoder=(EncodeImageHandler *) WriteGRAYImage; 321 entry->flags|=CoderRawSupportFlag; 322 entry->flags|=CoderEndianSupportFlag; 323 (void) RegisterMagickInfo(entry); 324 return(MagickImageCoderSignature); 325 } 326 327 /* 329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 330 % % 331 % % 332 % % 333 % U n r e g i s t e r G R A Y I m a g e % 334 % % 335 % % 336 % % 337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 338 % 339 % UnregisterGRAYImage() removes format registrations made by the 340 % GRAY module from the list of supported formats. 341 % 342 % The format of the UnregisterGRAYImage method is: 343 % 344 % UnregisterGRAYImage(void) 345 % 346 */ 347 ModuleExport void UnregisterGRAYImage(void) 348 { 349 (void) UnregisterMagickInfo("GRAY"); 350 } 351 352 /* 354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 355 % % 356 % % 357 % % 358 % W r i t e G R A Y I m a g e % 359 % % 360 % % 361 % % 362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 363 % 364 % WriteGRAYImage() writes an image to a file as gray scale intensity 365 % values. 366 % 367 % The format of the WriteGRAYImage method is: 368 % 369 % MagickBooleanType WriteGRAYImage(const ImageInfo *image_info, 370 % Image *image,ExceptionInfo *exception) 371 % 372 % A description of each parameter follows. 373 % 374 % o image_info: the image info. 375 % 376 % o image: The image. 377 % 378 % o exception: return any errors or warnings in this structure. 379 % 380 */ 381 static MagickBooleanType WriteGRAYImage(const ImageInfo *image_info, 382 Image *image,ExceptionInfo *exception) 383 { 384 MagickBooleanType 385 status; 386 387 MagickOffsetType 388 scene; 389 390 QuantumInfo 391 *quantum_info; 392 393 QuantumType 394 quantum_type; 395 396 size_t 397 length; 398 399 ssize_t 400 count, 401 y; 402 403 unsigned char 404 *pixels; 405 406 /* 407 Open output image file. 408 */ 409 assert(image_info != (const ImageInfo *) NULL); 410 assert(image_info->signature == MagickCoreSignature); 411 assert(image != (Image *) NULL); 412 assert(image->signature == MagickCoreSignature); 413 if (image->debug != MagickFalse) 414 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 415 assert(exception != (ExceptionInfo *) NULL); 416 assert(exception->signature == MagickCoreSignature); 417 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 418 if (status == MagickFalse) 419 return(status); 420 scene=0; 421 do 422 { 423 /* 424 Write grayscale pixels. 425 */ 426 (void) TransformImageColorspace(image,sRGBColorspace,exception); 427 quantum_type=GrayQuantum; 428 quantum_info=AcquireQuantumInfo(image_info,image); 429 if (quantum_info == (QuantumInfo *) NULL) 430 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 431 pixels=(unsigned char *) GetQuantumPixels(quantum_info); 432 for (y=0; y < (ssize_t) image->rows; y++) 433 { 434 register const Quantum 435 *magick_restrict p; 436 437 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 438 if (p == (const Quantum *) NULL) 439 break; 440 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info, 441 quantum_type,pixels,exception); 442 count=WriteBlob(image,length,pixels); 443 if (count != (ssize_t) length) 444 break; 445 if (image->previous == (Image *) NULL) 446 { 447 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 448 image->rows); 449 if (status == MagickFalse) 450 break; 451 } 452 } 453 quantum_info=DestroyQuantumInfo(quantum_info); 454 if (GetNextImageInList(image) == (Image *) NULL) 455 break; 456 image=SyncNextImageInList(image); 457 status=SetImageProgress(image,SaveImagesTag,scene++, 458 GetImageListLength(image)); 459 if (status == MagickFalse) 460 break; 461 } while (image_info->adjoin != MagickFalse); 462 (void) CloseBlob(image); 463 return(MagickTrue); 464 } 465