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