1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % PPPP GGGG X X % 7 % P P G X X % 8 % PPPP G GG X % 9 % P G G X X % 10 % P GGG X X % 11 % % 12 % % 13 % PGX JPEG 2000 Format % 14 % % 15 % Software Design % 16 % Cristy % 17 % July 2016 % 18 % % 19 % % 20 % Copyright 1999-2019 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 % https://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/color-private.h" 49 #include "MagickCore/colormap.h" 50 #include "MagickCore/colorspace.h" 51 #include "MagickCore/colorspace-private.h" 52 #include "MagickCore/exception.h" 53 #include "MagickCore/exception-private.h" 54 #include "MagickCore/image.h" 55 #include "MagickCore/image-private.h" 56 #include "MagickCore/list.h" 57 #include "MagickCore/magick.h" 58 #include "MagickCore/memory_.h" 59 #include "MagickCore/monitor.h" 60 #include "MagickCore/monitor-private.h" 61 #include "MagickCore/quantum-private.h" 62 #include "MagickCore/static.h" 63 #include "MagickCore/string_.h" 64 #include "MagickCore/module.h" 65 66 /* 68 Forward declarations. 69 */ 70 static MagickBooleanType 71 WritePGXImage(const ImageInfo *,Image *,ExceptionInfo *); 72 73 /* 75 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 76 % % 77 % % 78 % % 79 % I s P G X % 80 % % 81 % % 82 % % 83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 84 % 85 % IsPGXreturns True if the image format type, identified by the magick 86 % string, is PGX. 87 % 88 % The format of the IsPGX method is: 89 % 90 % unsigned int IsPGX(const unsigned char *magick,const size_t length) 91 % 92 % A description of each parameter follows: 93 % 94 % o magick: compare image format pattern against these bytes. 95 % 96 % o length: Specifies the length of the magick string. 97 % 98 */ 99 static unsigned int IsPGX(const unsigned char *magick,const size_t length) 100 { 101 if (length < 5) 102 return(MagickFalse); 103 if ((memcmp(magick,"PG ML",5) == 0) || (memcmp(magick,"PG LM",5) == 0)) 104 return(MagickTrue); 105 return(MagickFalse); 106 } 107 108 /* 110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 111 % % 112 % % 113 % % 114 % R e a d P G X I m a g e % 115 % % 116 % % 117 % % 118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 119 % 120 % ReadPGXImage() reads an image of raw bits in LSB order and returns it. 121 % It allocates the memory necessary for the new Image structure and returns 122 % a pointer to the new image. 123 % 124 % The format of the ReadPGXImage method is: 125 % 126 % Image *ReadPGXImage(const ImageInfo *image_info, 127 % ExceptionInfo *exception) 128 % 129 % A description of each parameter follows: 130 % 131 % o image_info: the image info. 132 % 133 % o exception: return any errors or warnings in this structure. 134 % 135 */ 136 static Image *ReadPGXImage(const ImageInfo *image_info,ExceptionInfo *exception) 137 { 138 char 139 buffer[MagickPathExtent], 140 endian[MagickPathExtent], 141 sans[MagickPathExtent], 142 sign[MagickPathExtent]; 143 144 const unsigned char 145 *pixels; 146 147 Image 148 *image; 149 150 int 151 height, 152 precision, 153 width; 154 155 QuantumInfo 156 *quantum_info; 157 158 MagickBooleanType 159 status; 160 161 size_t 162 length; 163 164 ssize_t 165 count, 166 y; 167 168 /* 169 Open image file. 170 */ 171 assert(image_info != (const ImageInfo *) NULL); 172 assert(image_info->signature == MagickCoreSignature); 173 if (image_info->debug != MagickFalse) 174 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 175 image_info->filename); 176 assert(exception != (ExceptionInfo *) NULL); 177 assert(exception->signature == MagickCoreSignature); 178 image=AcquireImage(image_info,exception); 179 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 180 if (status == MagickFalse) 181 { 182 image=DestroyImageList(image); 183 return((Image *) NULL); 184 } 185 if (ReadBlobString(image,buffer) == (char *) NULL) 186 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 187 count=(ssize_t) sscanf(buffer,"PG%[ \t]%2s%[ \t+-]%d%[ \t]%d%[ \t]%d",sans, 188 endian,sign,&precision,sans,&width,sans,&height); 189 if (count != 8) 190 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 191 image->depth=(size_t) precision; 192 if (LocaleCompare(endian,"ML") == 0) 193 image->endian=MSBEndian; 194 image->columns=(size_t) width; 195 image->rows=(size_t) height; 196 if ((image->columns == 0) || (image->rows == 0)) 197 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 198 if (image_info->ping != MagickFalse) 199 { 200 (void) CloseBlob(image); 201 return(GetFirstImageInList(image)); 202 } 203 status=SetImageExtent(image,image->columns,image->rows,exception); 204 if (status == MagickFalse) 205 return(DestroyImageList(image)); 206 /* 207 Convert PGX image. 208 */ 209 (void) SetImageColorspace(image,GRAYColorspace,exception); 210 quantum_info=AcquireQuantumInfo(image_info,image); 211 if (quantum_info == (QuantumInfo *) NULL) 212 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 213 length=GetQuantumExtent(image,quantum_info,GrayQuantum); 214 for (y=0; y < (ssize_t) image->rows; y++) 215 { 216 register Quantum 217 *magick_restrict q; 218 219 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 220 if (q == (Quantum *) NULL) 221 break; 222 pixels=(const unsigned char *) ReadBlobStream(image,length, 223 GetQuantumPixels(quantum_info),&count); 224 if (count != (ssize_t) length) 225 break; 226 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 227 GrayQuantum,pixels,exception); 228 if (SyncAuthenticPixels(image,exception) == MagickFalse) 229 break; 230 if (SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,image->rows) == MagickFalse) 231 break; 232 } 233 SetQuantumImageType(image,GrayQuantum); 234 quantum_info=DestroyQuantumInfo(quantum_info); 235 if (EOFBlob(image) != MagickFalse) 236 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 237 image->filename); 238 (void) CloseBlob(image); 239 return(GetFirstImageInList(image)); 240 } 241 242 /* 244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 245 % % 246 % % 247 % % 248 % R e g i s t e r P G X I m a g e % 249 % % 250 % % 251 % % 252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 253 % 254 % RegisterPGXImage() adds attributes for the PGX image format to 255 % the list of supported formats. The attributes include the image format 256 % tag, a method to read and/or write the format, whether the format 257 % supports the saving of more than one frame to the same file or blob, 258 % whether the format supports native in-memory I/O, and a brief 259 % description of the format. 260 % 261 % The format of the RegisterPGXImage method is: 262 % 263 % size_t RegisterPGXImage(void) 264 % 265 */ 266 ModuleExport size_t RegisterPGXImage(void) 267 { 268 MagickInfo 269 *entry; 270 271 entry=AcquireMagickInfo("PGX","PGX","JPEG 2000 uncompressed format"); 272 entry->decoder=(DecodeImageHandler *) ReadPGXImage; 273 entry->encoder=(EncodeImageHandler *) WritePGXImage; 274 entry->magick=(IsImageFormatHandler *) IsPGX; 275 entry->flags^=CoderAdjoinFlag; 276 entry->flags^=CoderUseExtensionFlag; 277 (void) RegisterMagickInfo(entry); 278 return(MagickImageCoderSignature); 279 } 280 281 /* 283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 284 % % 285 % % 286 % % 287 % U n r e g i s t e r P G X I m a g e % 288 % % 289 % % 290 % % 291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 292 % 293 % UnregisterPGXImage() removes format registrations made by the 294 % PGX module from the list of supported formats. 295 % 296 % The format of the UnregisterPGXImage method is: 297 % 298 % UnregisterPGXImage(void) 299 % 300 */ 301 ModuleExport void UnregisterPGXImage(void) 302 { 303 (void) UnregisterMagickInfo("PGX"); 304 } 305 306 /* 308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 309 % % 310 % % 311 % % 312 % W r i t e P G X I m a g e % 313 % % 314 % % 315 % % 316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 317 % 318 % WritePGXImage() writes an image of raw bits in LSB order to a file. 319 % 320 % The format of the WritePGXImage method is: 321 % 322 % MagickBooleanType WritePGXImage(const ImageInfo *image_info, 323 % Image *image,ExceptionInfo *exception) 324 % 325 % A description of each parameter follows. 326 % 327 % o image_info: the image info. 328 % 329 % o image: The image. 330 % 331 % o exception: return any errors or warnings in this structure. 332 % 333 */ 334 static MagickBooleanType WritePGXImage(const ImageInfo *image_info,Image *image, 335 ExceptionInfo *exception) 336 { 337 char 338 buffer[MagickPathExtent]; 339 340 MagickBooleanType 341 status; 342 343 QuantumInfo 344 *quantum_info; 345 346 register const Quantum 347 *p; 348 349 size_t 350 length; 351 352 ssize_t 353 count, 354 y; 355 356 unsigned char 357 *pixels; 358 359 /* 360 Open output image file. 361 */ 362 assert(image_info != (const ImageInfo *) NULL); 363 assert(image_info->signature == MagickCoreSignature); 364 assert(image != (Image *) NULL); 365 assert(image->signature == MagickCoreSignature); 366 if (image->debug != MagickFalse) 367 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 368 assert(exception != (ExceptionInfo *) NULL); 369 assert(exception->signature == MagickCoreSignature); 370 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 371 if (status == MagickFalse) 372 return(status); 373 (void) FormatLocaleString(buffer,MagickPathExtent,"PG ML + %g %g %g\n", 374 (double) image->depth,(double) image->columns,(double) image->rows); 375 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); 376 (void) TransformImageColorspace(image,sRGBColorspace,exception); 377 quantum_info=AcquireQuantumInfo(image_info,image); 378 if (quantum_info == (QuantumInfo *) NULL) 379 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 380 pixels=(unsigned char *) GetQuantumPixels(quantum_info); 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 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info, 387 GrayQuantum,pixels,exception); 388 count=WriteBlob(image,length,pixels); 389 if (count != (ssize_t) length) 390 break; 391 count=WriteBlob(image,(size_t) (-(ssize_t) length) & 0x01,pixels); 392 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 393 image->rows); 394 if (status == MagickFalse) 395 break; 396 } 397 quantum_info=DestroyQuantumInfo(quantum_info); 398 if (y < (ssize_t) image->rows) 399 ThrowWriterException(CorruptImageError,"UnableToWriteImageData"); 400 (void) CloseBlob(image); 401 return(status); 402 } 403