/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % X X BBBB M M % % X X B B MM MM % % X BBBB M M M % % X X B B M M % % X X BBBB M M % % % % % % Read/Write X Windows System Bitmap Format. % % % % Software Design % % John Cristy % % July 1992 % % % % % % Copyright 1999-2007 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % % obtain a copy of the License at % % % % http://www.imagemagick.org/script/license.php % % % % Unless required by applicable law or agreed to in writing, software % % distributed under the License is distributed on an "AS IS" BASIS, % % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % % See the License for the specific language governing permissions and % % limitations under the License. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % */ /* Include declarations. */ #include "magick/studio.h" #include "magick/blob.h" #include "magick/blob-private.h" #include "magick/color-private.h" #include "magick/colorspace.h" #include "magick/exception.h" #include "magick/exception-private.h" #include "magick/image.h" #include "magick/image-private.h" #include "magick/list.h" #include "magick/magick.h" #include "magick/memory_.h" #include "magick/monitor.h" #include "magick/quantum-private.h" #include "magick/static.h" #include "magick/string_.h" #include "magick/module.h" #include "magick/utility.h" /* Forward declarations. */ static MagickBooleanType WriteXBMImage(const ImageInfo *,Image *); /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % I s X B M % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % IsXBM() returns MagickTrue if the image format type, identified by the % magick string, is XBM. % % The format of the IsXBM method is: % % MagickBooleanType IsXBM(const unsigned char *magick,const size_t length) % % A description of each parameter follows: % % o magick: This string is generally the first few bytes of an image file % or blob. % % o length: Specifies the length of the magick string. % */ static MagickBooleanType IsXBM(const unsigned char *magick,const size_t length) { if (length < 7) return(MagickFalse); if (memcmp(magick,"#define",7) == 0) return(MagickTrue); return(MagickFalse); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d X B M I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadXBMImage() reads an X11 bitmap image file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadXBMImage method is: % % Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: The image info. % % o exception: return any errors or warnings in this structure. % */ static int XBMInteger(Image *image,short int *hex_digits) { int c, flag, value; value=0; flag=0; for ( ; ; ) { c=ReadBlobByte(image); if (c == EOF) { value=(-1); break; } c&=0xff; if (isxdigit(c) != MagickFalse) { value=(int) ((unsigned long) value << 4)+hex_digits[c]; flag++; continue; } if ((hex_digits[c]) < 0 && (flag != 0)) break; } return(value); } static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception) { char buffer[MaxTextExtent], name[MaxTextExtent]; Image *image; long y; MagickBooleanType status; register IndexPacket *indexes; register long i, x; register PixelPacket *q; register unsigned char *p; short int hex_digits[256]; size_t length; unsigned char *data; unsigned long bit, byte, bytes_per_line, padding, value, version; /* Open image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); image=AllocateImage(image_info); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } /* Read X bitmap header. */ while (ReadBlobString(image,buffer) != (char *) NULL) if (sscanf(buffer,"#define %s %lu",name,&image->columns) == 2) if ((strlen(name) >= 6) && (LocaleCompare(name+strlen(name)-6,"_width") == 0)) break; while (ReadBlobString(image,buffer) != (char *) NULL) if (sscanf(buffer,"#define %s %lu",name,&image->rows) == 2) if ((strlen(name) >= 7) && (LocaleCompare(name+strlen(name)-7,"_height") == 0)) break; image->depth=8; image->storage_class=PseudoClass; image->colors=2; /* Scan until hex digits. */ version=11; while (ReadBlobString(image,buffer) != (char *) NULL) { if (sscanf(buffer,"static short %s = {",name) == 1) version=10; else if (sscanf(buffer,"static unsigned char %s = {",name) == 1) version=11; else if (sscanf(buffer,"static char %s = {",name) == 1) version=11; else continue; p=(unsigned char *) strrchr(name,'_'); if (p == (unsigned char *) NULL) p=(unsigned char *) name; else p++; if (LocaleCompare("bits[]",(char *) p) == 0) break; } if ((image->columns == 0) || (image->rows == 0) || (EOFBlob(image) != MagickFalse)) ThrowReaderException(CorruptImageError,"ImproperImageHeader"); /* Initialize image structure. */ if (AllocateImageColormap(image,image->colors) == MagickFalse) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); /* Initialize colormap. */ image->colormap[0].red=(Quantum) QuantumRange; image->colormap[0].green=(Quantum) QuantumRange; image->colormap[0].blue=(Quantum) QuantumRange; image->colormap[1].red=(Quantum) 0; image->colormap[1].green=(Quantum) 0; image->colormap[1].blue=(Quantum) 0; if (image_info->ping != MagickFalse) { CloseBlob(image); return(GetFirstImageInList(image)); } if (SetImageExtent(image,0,0) == MagickFalse) { InheritException(exception,&image->exception); return(DestroyImageList(image)); } /* Initialize hex values. */ hex_digits[(int) '0']=0; hex_digits[(int) '1']=1; hex_digits[(int) '2']=2; hex_digits[(int) '3']=3; hex_digits[(int) '4']=4; hex_digits[(int) '5']=5; hex_digits[(int) '6']=6; hex_digits[(int) '7']=7; hex_digits[(int) '8']=8; hex_digits[(int) '9']=9; hex_digits[(int) 'A']=10; hex_digits[(int) 'B']=11; hex_digits[(int) 'C']=12; hex_digits[(int) 'D']=13; hex_digits[(int) 'E']=14; hex_digits[(int) 'F']=15; hex_digits[(int) 'a']=10; hex_digits[(int) 'b']=11; hex_digits[(int) 'c']=12; hex_digits[(int) 'd']=13; hex_digits[(int) 'e']=14; hex_digits[(int) 'f']=15; hex_digits[(int) 'x']=0; hex_digits[(int) ' ']=(-1); hex_digits[(int) ',']=(-1); hex_digits[(int) '}']=(-1); hex_digits[(int) '\n']=(-1); hex_digits[(int) '\t']=(-1); /* Read hex image data. */ padding=0; if (((image->columns % 16) != 0) && ((image->columns % 16) < 9) && (version == 10)) padding=1; bytes_per_line=(image->columns+7)/8+padding; length=(size_t) image->rows; data=(unsigned char *) AcquireQuantumMemory(length,bytes_per_line* sizeof(*data)); if (data == (unsigned char *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); p=data; if (version == 10) for (i=0; i < (long) (bytes_per_line*image->rows); (i+=2)) { value=(unsigned long) XBMInteger(image,hex_digits); *p++=(unsigned char) value; if ((padding == 0) || (((i+2) % bytes_per_line) != 0)) *p++=(unsigned char) (value >> 8); } else for (i=0; i < (long) (bytes_per_line*image->rows); i++) { value=(unsigned long) XBMInteger(image,hex_digits); *p++=(unsigned char) value; } /* Convert X bitmap image to pixel packets. */ p=data; for (y=0; y < (long) image->rows; y++) { q=SetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; indexes=GetIndexes(image); bit=0; byte=0; for (x=0; x < (long) image->columns; x++) { if (bit == 0) byte=(unsigned long) (*p++); indexes[x]=(IndexPacket) ((byte & 0x01) != 0 ? 0x01 : 0x00); bit++; byte>>=1; if (bit == 8) bit=0; } if (SyncImagePixels(image) == MagickFalse) break; if (QuantumTick(y,image->rows) != MagickFalse) if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(LoadImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } data=(unsigned char *) RelinquishMagickMemory(data); (void) SyncImage(image); CloseBlob(image); return(GetFirstImageInList(image)); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e g i s t e r X B M I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % RegisterXBMImage() adds attributes for the XBM image format to % the list of supported formats. The attributes include the image format % tag, a method to read and/or write the format, whether the format % supports the saving of more than one frame to the same file or blob, % whether the format supports native in-memory I/O, and a brief % description of the format. % % The format of the RegisterXBMImage method is: % % unsigned long RegisterXBMImage(void) % */ ModuleExport unsigned long RegisterXBMImage(void) { MagickInfo *entry; entry=SetMagickInfo("XBM"); entry->decoder=(DecodeImageHandler *) ReadXBMImage; entry->encoder=(EncodeImageHandler *) WriteXBMImage; entry->magick=(IsImageFormatHandler *) IsXBM; entry->adjoin=MagickFalse; entry->description=ConstantString( "X Windows system bitmap (black and white)"); entry->module=ConstantString("XBM"); (void) RegisterMagickInfo(entry); return(MagickImageCoderSignature); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % U n r e g i s t e r X B M I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % UnregisterXBMImage() removes format registrations made by the % XBM module from the list of supported formats. % % The format of the UnregisterXBMImage method is: % % UnregisterXBMImage(void) % */ ModuleExport void UnregisterXBMImage(void) { (void) UnregisterMagickInfo("XBM"); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e X B M I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Procedure WriteXBMImage() writes an image to a file in the X bitmap format. % % The format of the WriteXBMImage method is: % % MagickBooleanType WriteXBMImage(const ImageInfo *image_info,Image *image) % % A description of each parameter follows. % % o image_info: The image info. % % o image: The image. % % */ static MagickBooleanType WriteXBMImage(const ImageInfo *image_info,Image *image) { char basename[MaxTextExtent], buffer[MaxTextExtent]; long y; MagickBooleanType status; register const PixelPacket *p; register long x; register IndexPacket *indexes; ssize_t count; unsigned long bit, byte; /* Open output image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); if (status == MagickFalse) return(status); if (image_info->colorspace == UndefinedColorspace) (void) SetImageColorspace(image,RGBColorspace); /* Write X bitmap header. */ GetPathComponent(image->filename,BasePath,basename); (void) FormatMagickString(buffer,MaxTextExtent,"#define %s_width %lu\n", basename,image->columns); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); (void) FormatMagickString(buffer,MaxTextExtent,"#define %s_height %lu\n", basename,image->rows); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); (void) FormatMagickString(buffer,MaxTextExtent, "static char %s_bits[] = {\n",basename); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); (void) CopyMagickString(buffer," ",MaxTextExtent); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); /* Convert MIFF to X bitmap pixels. */ (void) SetImageType(image,BilevelType); bit=0; byte=0; count=0; x=0; y=0; (void) CopyMagickString(buffer," ",MaxTextExtent); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); for (y=0; y < (long) image->rows; y++) { p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); if (p == (const PixelPacket *) NULL) break; indexes=GetIndexes(image); for (x=0; x < (long) image->columns; x++) { byte>>=1; if (PixelIntensity(p) < ((MagickRealType) QuantumRange/2.0)) byte|=0x80; bit++; if (bit == 8) { /* Write a bitmap byte to the image file. */ (void) FormatMagickString(buffer,MaxTextExtent,"0x%02X, ", (unsigned int) (byte & 0xff)); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); count++; if (count == 12) { (void) CopyMagickString(buffer,"\n ",MaxTextExtent); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); count=0; }; bit=0; byte=0; } p++; } if (bit != 0) { /* Write a bitmap byte to the image file. */ byte>>=(8-bit); (void) FormatMagickString(buffer,MaxTextExtent,"0x%02X, ", (unsigned int) (byte & 0xff)); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); count++; if (count == 12) { (void) CopyMagickString(buffer,"\n ",MaxTextExtent); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); count=0; }; bit=0; byte=0; }; if (QuantumTick(y,image->rows) != MagickFalse) if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(SaveImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } (void) CopyMagickString(buffer,"};\n",MaxTextExtent); (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); CloseBlob(image); return(MagickTrue); }