1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % OOO TTTTT BBBB % 7 % O O T B B % 8 % O O T BBBB % 9 % O O T B B % 10 % OOO T BBBB % 11 % % 12 % % 13 % Read/Write On-The-Air 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 WriteOTBImage(const ImageInfo *,Image *,ExceptionInfo *); 71 72 /* 74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 75 % % 76 % % 77 % % 78 % R e a d O T B I m a g e % 79 % % 80 % % 81 % % 82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 83 % 84 % ReadOTBImage() reads a on-the-air (level 0) bitmap 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 % The format of the ReadOTBImage method is: 89 % 90 % Image *ReadOTBImage(const ImageInfo *image_info,ExceptionInfo *exception) 91 % 92 % A description of each parameter follows: 93 % 94 % o image_info: the image info. 95 % 96 % o exception: return any errors or warnings in this structure. 97 % 98 % 99 */ 100 static Image *ReadOTBImage(const ImageInfo *image_info,ExceptionInfo *exception) 101 { 102 #define GetBit(a,i) (((a) >> (i)) & 1L) 103 104 Image 105 *image; 106 107 int 108 byte; 109 110 MagickBooleanType 111 status; 112 113 register ssize_t 114 x; 115 116 register Quantum 117 *q; 118 119 ssize_t 120 y; 121 122 unsigned char 123 bit, 124 info, 125 depth; 126 127 /* 128 Open image file. 129 */ 130 assert(image_info != (const ImageInfo *) NULL); 131 assert(image_info->signature == MagickCoreSignature); 132 if (image_info->debug != MagickFalse) 133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 134 image_info->filename); 135 assert(exception != (ExceptionInfo *) NULL); 136 assert(exception->signature == MagickCoreSignature); 137 image=AcquireImage(image_info,exception); 138 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 139 if (status == MagickFalse) 140 { 141 image=DestroyImageList(image); 142 return((Image *) NULL); 143 } 144 /* 145 Initialize image structure. 146 */ 147 info=(unsigned char) ReadBlobByte(image); 148 if (GetBit(info,4) == 0) 149 { 150 image->columns=(size_t) ReadBlobByte(image); 151 image->rows=(size_t) ReadBlobByte(image); 152 } 153 else 154 { 155 image->columns=(size_t) ReadBlobMSBShort(image); 156 image->rows=(size_t) ReadBlobMSBShort(image); 157 } 158 if ((image->columns == 0) || (image->rows == 0)) 159 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 160 depth=(unsigned char) ReadBlobByte(image); 161 if (depth != 1) 162 ThrowReaderException(CoderError,"OnlyLevelZerofilesSupported"); 163 if (AcquireImageColormap(image,2,exception) == MagickFalse) 164 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 165 if (image_info->ping != MagickFalse) 166 { 167 (void) CloseBlob(image); 168 return(GetFirstImageInList(image)); 169 } 170 status=SetImageExtent(image,image->columns,image->rows,exception); 171 if (status == MagickFalse) 172 return(DestroyImageList(image)); 173 /* 174 Convert bi-level image to pixel packets. 175 */ 176 for (y=0; y < (ssize_t) image->rows; y++) 177 { 178 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 179 if (q == (Quantum *) NULL) 180 break; 181 bit=0; 182 byte=0; 183 for (x=0; x < (ssize_t) image->columns; x++) 184 { 185 if (bit == 0) 186 { 187 byte=ReadBlobByte(image); 188 if (byte == EOF) 189 ThrowReaderException(CorruptImageError,"CorruptImage"); 190 } 191 SetPixelIndex(image,(byte & (0x01 << (7-bit))) ? 0x00 : 0x01,q); 192 bit++; 193 if (bit == 8) 194 bit=0; 195 q+=GetPixelChannels(image); 196 } 197 if (SyncAuthenticPixels(image,exception) == MagickFalse) 198 break; 199 if (image->previous == (Image *) NULL) 200 { 201 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 202 image->rows); 203 if (status == MagickFalse) 204 break; 205 } 206 } 207 (void) SyncImage(image,exception); 208 if (EOFBlob(image) != MagickFalse) 209 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 210 image->filename); 211 (void) CloseBlob(image); 212 return(GetFirstImageInList(image)); 213 } 214 215 /* 217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 218 % % 219 % % 220 % % 221 % R e g i s t e r O T B I m a g e % 222 % % 223 % % 224 % % 225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 226 % 227 % RegisterOTBImage() adds attributes for the OTB image format to 228 % the list of supported formats. The attributes include the image format 229 % tag, a method to read and/or write the format, whether the format 230 % supports the saving of more than one frame to the same file or blob, 231 % whether the format supports native in-memory I/O, and a brief 232 % description of the format. 233 % 234 % The format of the RegisterOTBImage method is: 235 % 236 % size_t RegisterOTBImage(void) 237 % 238 */ 239 ModuleExport size_t RegisterOTBImage(void) 240 { 241 MagickInfo 242 *entry; 243 244 entry=AcquireMagickInfo("OTB","OTB","On-the-air bitmap"); 245 entry->decoder=(DecodeImageHandler *) ReadOTBImage; 246 entry->encoder=(EncodeImageHandler *) WriteOTBImage; 247 entry->flags^=CoderAdjoinFlag; 248 (void) RegisterMagickInfo(entry); 249 return(MagickImageCoderSignature); 250 } 251 252 /* 254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 255 % % 256 % % 257 % % 258 % U n r e g i s t e r O T B I m a g e % 259 % % 260 % % 261 % % 262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 263 % 264 % UnregisterOTBImage() removes format registrations made by the 265 % OTB module from the list of supported formats. 266 % 267 % The format of the UnregisterOTBImage method is: 268 % 269 % UnregisterOTBImage(void) 270 % 271 */ 272 ModuleExport void UnregisterOTBImage(void) 273 { 274 (void) UnregisterMagickInfo("OTB"); 275 } 276 277 /* 279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 280 % % 281 % % 282 % % 283 % W r i t e O T B I m a g e % 284 % % 285 % % 286 % % 287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 288 % 289 % WriteOTBImage() writes an image to a file in the On-the-air Bitmap 290 % (level 0) image format. 291 % 292 % The format of the WriteOTBImage method is: 293 % 294 % MagickBooleanType WriteOTBImage(const ImageInfo *image_info, 295 % Image *image,ExceptionInfo *exception) 296 % 297 % A description of each parameter follows. 298 % 299 % o image_info: the image info. 300 % 301 % o image: The image. 302 % 303 % o exception: return any errors or warnings in this structure. 304 % 305 */ 306 static MagickBooleanType WriteOTBImage(const ImageInfo *image_info,Image *image, 307 ExceptionInfo *exception) 308 { 309 #define SetBit(a,i,set) \ 310 a=(unsigned char) ((set) ? (a) | (1L << (i)) : (a) & ~(1L << (i))) 311 312 MagickBooleanType 313 status; 314 315 register const Quantum 316 *p; 317 318 register ssize_t 319 x; 320 321 ssize_t 322 y; 323 324 unsigned char 325 bit, 326 byte, 327 info; 328 329 /* 330 Open output image file. 331 */ 332 assert(image_info != (const ImageInfo *) NULL); 333 assert(image_info->signature == MagickCoreSignature); 334 assert(image != (Image *) NULL); 335 assert(image->signature == MagickCoreSignature); 336 if (image->debug != MagickFalse) 337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 338 assert(exception != (ExceptionInfo *) NULL); 339 assert(exception->signature == MagickCoreSignature); 340 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 341 if (status == MagickFalse) 342 return(status); 343 (void) TransformImageColorspace(image,sRGBColorspace,exception); 344 /* 345 Convert image to a bi-level image. 346 */ 347 (void) SetImageType(image,BilevelType,exception); 348 info=0; 349 if ((image->columns >= 256) || (image->rows >= 256)) 350 SetBit(info,4,1); 351 (void) WriteBlobByte(image,info); 352 if ((image->columns >= 256) || (image->rows >= 256)) 353 { 354 (void) WriteBlobMSBShort(image,(unsigned short) image->columns); 355 (void) WriteBlobMSBShort(image,(unsigned short) image->rows); 356 } 357 else 358 { 359 (void) WriteBlobByte(image,(unsigned char) image->columns); 360 (void) WriteBlobByte(image,(unsigned char) image->rows); 361 } 362 (void) WriteBlobByte(image,1); /* depth */ 363 for (y=0; y < (ssize_t) image->rows; y++) 364 { 365 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 366 if (p == (const Quantum *) NULL) 367 break; 368 bit=0; 369 byte=0; 370 for (x=0; x < (ssize_t) image->columns; x++) 371 { 372 if (GetPixelLuma(image,p) < (QuantumRange/2.0)) 373 byte|=0x1 << (7-bit); 374 bit++; 375 if (bit == 8) 376 { 377 (void) WriteBlobByte(image,byte); 378 bit=0; 379 byte=0; 380 } 381 p+=GetPixelChannels(image); 382 } 383 if (bit != 0) 384 (void) WriteBlobByte(image,byte); 385 if (image->previous == (Image *) NULL) 386 { 387 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 388 image->rows); 389 if (status == MagickFalse) 390 break; 391 } 392 } 393 (void) CloseBlob(image); 394 return(MagickTrue); 395 } 396