1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % W W BBBB M M PPPP % 7 % W W B B MM MM P P % 8 % W W W BBBB M M M PPPP % 9 % WW WW B B M M P % 10 % W W BBBB M M P % 11 % % 12 % % 13 % Read/Write Wireless Bitmap (level 0) Image Format % 14 % % 15 % Software Design % 16 % Cristy % 17 % January 2000 % 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 Include declarations. 40 */ 41 #include "MagickCore/studio.h" 42 #include "MagickCore/attribute.h" 43 #include "MagickCore/blob.h" 44 #include "MagickCore/blob-private.h" 45 #include "MagickCore/cache.h" 46 #include "MagickCore/color-private.h" 47 #include "MagickCore/colormap.h" 48 #include "MagickCore/colorspace.h" 49 #include "MagickCore/colorspace-private.h" 50 #include "MagickCore/exception.h" 51 #include "MagickCore/exception-private.h" 52 #include "MagickCore/image.h" 53 #include "MagickCore/image-private.h" 54 #include "MagickCore/list.h" 55 #include "MagickCore/magick.h" 56 #include "MagickCore/memory_.h" 57 #include "MagickCore/monitor.h" 58 #include "MagickCore/monitor-private.h" 59 #include "MagickCore/pixel-accessor.h" 60 #include "MagickCore/quantum-private.h" 61 #include "MagickCore/static.h" 62 #include "MagickCore/string_.h" 63 #include "MagickCore/module.h" 64 65 /* 67 Forward declarations. 68 */ 69 static MagickBooleanType 70 WriteWBMPImage(const ImageInfo *,Image *,ExceptionInfo *); 71 72 /* 74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 75 % % 76 % % 77 % % 78 % R e a d W B M P I m a g e % 79 % % 80 % % 81 % % 82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 83 % 84 % ReadWBMPImage() reads a WBMP (level 0) image file and returns it. It 85 % allocates the memory necessary for the new Image structure and returns a 86 % pointer to the new image. 87 % 88 % ReadWBMPImage was contributed by Milan Votava <votava (at) mageo.cz>. 89 % 90 % The format of the ReadWBMPImage method is: 91 % 92 % Image *ReadWBMPImage(const ImageInfo *image_info, 93 % ExceptionInfo *exception) 94 % 95 % A description of each parameter follows: 96 % 97 % o image_info: the image info. 98 % 99 % o exception: return any errors or warnings in this structure. 100 % 101 */ 102 103 static MagickBooleanType WBMPReadInteger(Image *image,size_t *value) 104 { 105 int 106 byte; 107 108 *value=0; 109 do 110 { 111 byte=ReadBlobByte(image); 112 if (byte == EOF) 113 return(MagickFalse); 114 *value<<=7; 115 *value|=(unsigned int) (byte & 0x7f); 116 } while (byte & 0x80); 117 return(MagickTrue); 118 } 119 120 static Image *ReadWBMPImage(const ImageInfo *image_info, 121 ExceptionInfo *exception) 122 { 123 Image 124 *image; 125 126 int 127 byte; 128 129 MagickBooleanType 130 status; 131 132 register ssize_t 133 x; 134 135 register Quantum 136 *q; 137 138 ssize_t 139 y; 140 141 unsigned char 142 bit; 143 144 unsigned short 145 header; 146 147 /* 148 Open image file. 149 */ 150 assert(image_info != (const ImageInfo *) NULL); 151 assert(image_info->signature == MagickCoreSignature); 152 if (image_info->debug != MagickFalse) 153 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 154 image_info->filename); 155 assert(exception != (ExceptionInfo *) NULL); 156 assert(exception->signature == MagickCoreSignature); 157 image=AcquireImage(image_info,exception); 158 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 159 if (status == MagickFalse) 160 { 161 image=DestroyImageList(image); 162 return((Image *) NULL); 163 } 164 if (ReadBlob(image,2,(unsigned char *) &header) == 0) 165 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 166 if (header != 0) 167 ThrowReaderException(CoderError,"OnlyLevelZerofilesSupported"); 168 /* 169 Initialize image structure. 170 */ 171 if (WBMPReadInteger(image,&image->columns) == MagickFalse) 172 ThrowReaderException(CorruptImageError,"CorruptWBMPimage"); 173 if (WBMPReadInteger(image,&image->rows) == MagickFalse) 174 ThrowReaderException(CorruptImageError,"CorruptWBMPimage"); 175 if ((image->columns == 0) || (image->rows == 0)) 176 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 177 if (DiscardBlobBytes(image,image->offset) == MagickFalse) 178 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 179 image->filename); 180 if (AcquireImageColormap(image,2,exception) == MagickFalse) 181 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 182 if (image_info->ping != MagickFalse) 183 { 184 (void) CloseBlob(image); 185 return(GetFirstImageInList(image)); 186 } 187 status=SetImageExtent(image,image->columns,image->rows,exception); 188 if (status == MagickFalse) 189 return(DestroyImageList(image)); 190 /* 191 Convert bi-level image to pixel packets. 192 */ 193 for (y=0; y < (ssize_t) image->rows; y++) 194 { 195 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 196 if (q == (Quantum *) NULL) 197 break; 198 bit=0; 199 byte=0; 200 for (x=0; x < (ssize_t) image->columns; x++) 201 { 202 if (bit == 0) 203 { 204 byte=ReadBlobByte(image); 205 if (byte == EOF) 206 ThrowReaderException(CorruptImageError,"CorruptImage"); 207 } 208 SetPixelIndex(image,(byte & (0x01 << (7-bit))) ? 1 : 0,q); 209 bit++; 210 if (bit == 8) 211 bit=0; 212 q+=GetPixelChannels(image); 213 } 214 if (SyncAuthenticPixels(image,exception) == MagickFalse) 215 break; 216 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 217 image->rows); 218 if (status == MagickFalse) 219 break; 220 } 221 (void) SyncImage(image,exception); 222 if (EOFBlob(image) != MagickFalse) 223 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 224 image->filename); 225 (void) CloseBlob(image); 226 return(GetFirstImageInList(image)); 227 } 228 229 /* 231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 232 % % 233 % % 234 % % 235 % R e g i s t e r W B M P I m a g e % 236 % % 237 % % 238 % % 239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 240 % 241 % RegisterWBMPImage() adds attributes for the WBMP image format to 242 % the list of supported formats. The attributes include the image format 243 % tag, a method to read and/or write the format, whether the format 244 % supports the saving of more than one frame to the same file or blob, 245 % whether the format supports native in-memory I/O, and a brief 246 % description of the format. 247 % 248 % The format of the RegisterWBMPImage method is: 249 % 250 % size_t RegisterWBMPImage(void) 251 % 252 */ 253 ModuleExport size_t RegisterWBMPImage(void) 254 { 255 MagickInfo 256 *entry; 257 258 entry=AcquireMagickInfo("WBMP","WBMP","Wireless Bitmap (level 0) image"); 259 entry->decoder=(DecodeImageHandler *) ReadWBMPImage; 260 entry->encoder=(EncodeImageHandler *) WriteWBMPImage; 261 entry->flags^=CoderAdjoinFlag; 262 (void) RegisterMagickInfo(entry); 263 return(MagickImageCoderSignature); 264 } 265 266 /* 268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 269 % % 270 % % 271 % % 272 % U n r e g i s t e r W B M P I m a g e % 273 % % 274 % % 275 % % 276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 277 % 278 % UnregisterWBMPImage() removes format registrations made by the 279 % WBMP module from the list of supported formats. 280 % 281 % The format of the UnregisterWBMPImage method is: 282 % 283 % UnregisterWBMPImage(void) 284 % 285 */ 286 ModuleExport void UnregisterWBMPImage(void) 287 { 288 (void) UnregisterMagickInfo("WBMP"); 289 } 290 291 /* 293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 294 % % 295 % % 296 % % 297 % W r i t e W B M P I m a g e % 298 % % 299 % % 300 % % 301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 302 % 303 % WriteWBMPImage() writes an image to a file in the Wireless Bitmap 304 % (level 0) image format. 305 % 306 % WriteWBMPImage was contributed by Milan Votava <votava (at) mageo.cz>. 307 % 308 % The format of the WriteWBMPImage method is: 309 % 310 % MagickBooleanType WriteWBMPImage(const ImageInfo *image_info, 311 % Image *image,ExceptionInfo *exception) 312 % 313 % A description of each parameter follows. 314 % 315 % o image_info: the image info. 316 % 317 % o image: The image. 318 % 319 % o exception: return any errors or warnings in this structure. 320 % 321 */ 322 323 static void WBMPWriteInteger(Image *image,const size_t value) 324 { 325 int 326 bits, 327 flag, 328 n; 329 330 register ssize_t 331 i; 332 333 unsigned char 334 buffer[5], 335 octet; 336 337 n=1; 338 bits=28; 339 flag=MagickFalse; 340 for (i=4; i >= 0; i--) 341 { 342 octet=(unsigned char) ((value >> bits) & 0x7f); 343 if ((flag == 0) && (octet != 0)) 344 { 345 flag=MagickTrue; 346 n=i+1; 347 } 348 buffer[4-i]=octet | (i && (flag || octet))*(0x01 << 7); 349 bits-=7; 350 } 351 (void) WriteBlob(image,(size_t) n,buffer+5-n); 352 } 353 354 static MagickBooleanType WriteWBMPImage(const ImageInfo *image_info, 355 Image *image,ExceptionInfo *exception) 356 { 357 MagickBooleanType 358 status; 359 360 register const Quantum 361 *p; 362 363 register ssize_t 364 x; 365 366 ssize_t 367 y; 368 369 unsigned char 370 bit, 371 byte; 372 373 /* 374 Open output image file. 375 */ 376 assert(image_info != (const ImageInfo *) NULL); 377 assert(image_info->signature == MagickCoreSignature); 378 assert(image != (Image *) NULL); 379 assert(image->signature == MagickCoreSignature); 380 if (image->debug != MagickFalse) 381 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 382 assert(exception != (ExceptionInfo *) NULL); 383 assert(exception->signature == MagickCoreSignature); 384 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 385 if (status == MagickFalse) 386 return(status); 387 (void) TransformImageColorspace(image,sRGBColorspace,exception); 388 /* 389 Convert image to a bi-level image. 390 */ 391 (void) SetImageType(image,BilevelType,exception); 392 (void) WriteBlobMSBShort(image,0); 393 WBMPWriteInteger(image,image->columns); 394 WBMPWriteInteger(image,image->rows); 395 for (y=0; y < (ssize_t) image->rows; y++) 396 { 397 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 398 if (p == (const Quantum *) NULL) 399 break; 400 bit=0; 401 byte=0; 402 for (x=0; x < (ssize_t) image->columns; x++) 403 { 404 if (GetPixelLuma(image,p) >= (QuantumRange/2.0)) 405 byte|=0x1 << (7-bit); 406 bit++; 407 if (bit == 8) 408 { 409 (void) WriteBlobByte(image,byte); 410 bit=0; 411 byte=0; 412 } 413 p+=GetPixelChannels(image); 414 } 415 if (bit != 0) 416 (void) WriteBlobByte(image,byte); 417 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 418 image->rows); 419 if (status == MagickFalse) 420 break; 421 } 422 (void) CloseBlob(image); 423 return(MagickTrue); 424 } 425