From VisualWorks®, 7.6 of February 1, 2008 on February 1, 2008 at 1:01:08 pm (Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned. Choose terminate or close.'] <class> <name>ImageReader</name> <environment>Graphics</environment> <super>Core.Object</super> <private>false</private> none ioStream image palette imageData width height bitsPerPixel bytesPerRow rowEndOffset <imports></imports> <category>Graphics-ImageReaders</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.ImageReader
Class ImageReader is an abstract class representing a reader of images stored in external formats such as Windows BMP, GIFF, TIFF, etc. Subclasses implement readers for specific formats. Instance Variables: ioStream <PositionableStream> stream from which to read the image image <Image> imported image palette <Palette> palette for the imported image imageData <ByteArray> bits containing the imported bitmap, in canonical format width <Integer> width of image in pixels height <Integer> height of image in pixels bitsPerPixel <Integer> number of bits per image pixel bytesPerRow <Integer> number of bytes per row in imageData rowEndOffset <Integer> zero-based offset of the last pixel in an imageData row, measured from the beginning of the row Class Variables InvalidFormatSignal <Signal> signal raised during image importing to indicate an invalid image format Subclasses must implement the following messages: initialize-release readImage attributes format Object Reference: ImageReader is an abstract class that provides support for reading graphic images stored in file formats such as Windows BMP. An image reader is created by sending #fromFile: to this class -- information in the file will be used to select the appropriate class of reader. The image can then be obtained by sending #image to the reader. Information about the image can also be accessed, via methods in the attributes protocol.
</comment> <class> <name>PNGImageReader</name> <environment>Graphics</environment> <super>Graphics.ImageReader</super> <private>false</private> none chunk depth bitsPerChannel colorType interlaceMethod bytesPerScanline thisScanline prevScanline rowSize globalDataChunk unknownChunks filtersSeen backgroundColor transparentPixelValues <imports> OS.ZLib.PNGInflateStream </imports> <category>Graphics-ImageReaders</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.PNGImageReader
I am a subclass of ImageReader that decodes Portable Network Graphics (PNG) images. This image reader properly reads (or properly fails to read) 148 of the 158 images in the PNG Image suite (avalable at: ftp://swrinde.nde.swri.edu/pub/png/images/suite/PngSuite.zip) The images it fails on are as follows: Image Name Description Failure ========= ======== ======= x00n0g01.png 0x0 image We seem to think a 0x0 image is ok, but the PNG suite says we should reject it pp0n0g08.png six-cube palette-chunk in grayscale image Fails to display (VW thinks it is an invalid display format) pp0n2c16.png six-cube palette-chunk in true-color image Fails to display (VW thinks it is an invalid display format) tbbn1g04.png transparent, black background chunk Wrong background color s01i3p01.png 1x1 paletted file, interlaced Unable to display 1x1 image s02i3p01.png 2x2 paletted file, interlaced Unable to display 2x2 image s01n3p01.png 1x1 paletted file, interlaced Unable to display 1x1 image s02n3p01.png 2x2 paletted file, interlaced Unable to display 2x2 image Instance Variables: bitsPerChannel <Integer> The number of bits used in each color channel bytesPerScanline <Integer> The number of bytes in a packedRow scan line chunk <SequenceableCollection> The current working piece of the stream from the image colorType <Integer> PNG code for color type depth <SmallInteger> Bit depth of the image filtersSeen <Collection> Helpful debugging variable that notes which PNG filters were seen in the image. globalDataChunk <SequenceableCollection> When finally getting to the body of the image, this holds the whole untranslated image bytes. interlaceMethod <1 | 0> If 0, then non interlaced, otherwise, interlaced prevScanline <(ByteArray of: (Integer))> When looking up above and above left colors for certain filters, we need to keep around the previous scan line. rowSize <Integer> Calculated scanline row size thisScanline <(ByteArray of: Integer)> The uncompressed byte array representing the an image scan line. transparentPixelValues <Collection> When using transparancy, this holds the values of the transparency color values. unknownChunks <Collection> We ignore some chunks... after reading, they are held onto here. Below is a set of do-its for testing the image reader with the PNG Image Suite. (ImageReader fromFile: 'png\basn0g01.png') image inspect. (ImageReader fromFile: 'png\basn0g02.png') image inspect. (ImageReader fromFile: 'png\basn0g04.png') image inspect. (ImageReader fromFile: 'png\basn0g08.png') image inspect. (ImageReader fromFile: 'png\basn0g16.png') image inspect. (ImageReader fromFile: 'png\basn2c08.png') image inspect. (ImageReader fromFile: 'png\basn2c16.png') image inspect. (ImageReader fromFile: 'png\basn3p01.png') image inspect. (ImageReader fromFile: 'png\basn3p02.png') image inspect. (ImageReader fromFile: 'png\basn3p04.png') image inspect. (ImageReader fromFile: 'png\basn3p08.png') image inspect. (ImageReader fromFile: 'png\basn4a08.png') image inspect. (ImageReader fromFile: 'png\basn4a16.png') image inspect. (ImageReader fromFile: 'png\basn6a08.png') image inspect. (ImageReader fromFile: 'png\basn6a16.png') image inspect. (ImageReader fromFile: 'png\basi0g01.png') image inspect. (ImageReader fromFile: 'png\basi0g02.png') image inspect. (ImageReader fromFile: 'png\basi0g04.png') image inspect. (ImageReader fromFile: 'png\basi0g08.png') image inspect. (ImageReader fromFile: 'png\basi0g16.png') image inspect. (ImageReader fromFile: 'png\basi2c08.png') image inspect. (ImageReader fromFile: 'png\basi2c16.png') image inspect. (ImageReader fromFile: 'png\basi3p01.png') image inspect. (ImageReader fromFile: 'png\basi3p02.png') image inspect. (ImageReader fromFile: 'png\basi3p04.png') image inspect. (ImageReader fromFile: 'png\basi3p08.png') image inspect. (ImageReader fromFile: 'png\basi4a08.png') image inspect. (ImageReader fromFile: 'png\basi4a16.png') image inspect. (ImageReader fromFile: 'png\basi6a08.png') image inspect. (ImageReader fromFile: 'png\basi6a16.png') image inspect. (ImageReader fromFile: 'png\s01n3p01.png') image inspect. (ImageReader fromFile: 'png\s02n3p01.png') image inspect. (ImageReader fromFile: 'png\s03n3p01.png') image inspect. (ImageReader fromFile: 'png\s04n3p01.png') image inspect. (ImageReader fromFile: 'png\s05n3p02.png') image inspect. (ImageReader fromFile: 'png\s06n3p02.png') image inspect. (ImageReader fromFile: 'png\s07n3p02.png') image inspect. (ImageReader fromFile: 'png\s08n3p02.png') image inspect. (ImageReader fromFile: 'png\s09n3p02.png') image inspect. (ImageReader fromFile: 'png\s32n3p04.png') image inspect. (ImageReader fromFile: 'png\s33n3p04.png') image inspect. (ImageReader fromFile: 'png\s34n3p04.png') image inspect. (ImageReader fromFile: 'png\s35n3p04.png') image inspect. (ImageReader fromFile: 'png\s36n3p04.png') image inspect. (ImageReader fromFile: 'png\s37n3p04.png') image inspect. (ImageReader fromFile: 'png\s38n3p04.png') image inspect. (ImageReader fromFile: 'png\s39n3p04.png') image inspect. (ImageReader fromFile: 'png\s40n3p04.png') image inspect. (ImageReader fromFile: 'png\s01i3p01.png') image inspect. (ImageReader fromFile: 'png\s02i3p01.png') image inspect. (ImageReader fromFile: 'png\s03i3p01.png') image inspect. (ImageReader fromFile: 'png\s04i3p01.png') image inspect. (ImageReader fromFile: 'png\s05i3p02.png') image inspect. (ImageReader fromFile: 'png\s06i3p02.png') image inspect. (ImageReader fromFile: 'png\s07i3p02.png') image inspect. (ImageReader fromFile: 'png\s08i3p02.png') image inspect. (ImageReader fromFile: 'png\s09i3p02.png') image inspect. (ImageReader fromFile: 'png\s32i3p04.png') image inspect. (ImageReader fromFile: 'png\s33i3p04.png') image inspect. (ImageReader fromFile: 'png\s34i3p04.png') image inspect. (ImageReader fromFile: 'png\s35i3p04.png') image inspect. (ImageReader fromFile: 'png\s36i3p04.png') image inspect. (ImageReader fromFile: 'png\s37i3p04.png') image inspect. (ImageReader fromFile: 'png\s38i3p04.png') image inspect. (ImageReader fromFile: 'png\s39i3p04.png') image inspect. (ImageReader fromFile: 'png\s40i3p04.png') image inspect. (ImageReader fromFile: 'png\bgai4a08.png') image inspect. (ImageReader fromFile: 'png\bgai4a16.png') image inspect. (ImageReader fromFile: 'png\bgan6a08.png') image inspect. (ImageReader fromFile: 'png\bgan6a16.png') image inspect. (ImageReader fromFile: 'png\bgbn4a08.png') image inspect. (ImageReader fromFile: 'png\bggn4a16.png') image inspect. (ImageReader fromFile: 'png\bgwn6a08.png') image inspect. (ImageReader fromFile: 'png\bgyn6a16.png') image inspect. (ImageReader fromFile: 'png\tp0n1g08.png') image inspect. (ImageReader fromFile: 'png\tbbn1g04.png') image inspect. (ImageReader fromFile: 'png\tbwn1g16.png') image inspect. (ImageReader fromFile: 'png\tp0n2c08.png') image inspect. (ImageReader fromFile: 'png\tbrn2c08.png') image inspect. (ImageReader fromFile: 'png\tbgn2c16.png') image inspect. (ImageReader fromFile: 'png\tbbn2c16.png') image inspect. (ImageReader fromFile: 'png\tp0n3p08.png') image inspect. (ImageReader fromFile: 'png\tp1n3p08.png') image inspect. (ImageReader fromFile: 'png\tbbn3p08.png') image inspect. (ImageReader fromFile: 'png\tbgn3p08.png') image inspect. (ImageReader fromFile: 'png\tbwn3p08.png') image inspect. (ImageReader fromFile: 'png\tbyn3p08.png') image inspect. (ImageReader fromFile: 'png\g03n0g16.png') image inspect. (ImageReader fromFile: 'png\g04n0g16.png') image inspect. (ImageReader fromFile: 'png\g05n0g16.png') image inspect. (ImageReader fromFile: 'png\g07n0g16.png') image inspect. (ImageReader fromFile: 'png\g10n0g16.png') image inspect. (ImageReader fromFile: 'png\g25n0g16.png') image inspect. (ImageReader fromFile: 'png\g03n2c08.png') image inspect. (ImageReader fromFile: 'png\g04n2c08.png') image inspect. (ImageReader fromFile: 'png\g05n2c08.png') image inspect. (ImageReader fromFile: 'png\g07n2c08.png') image inspect. (ImageReader fromFile: 'png\g10n2c08.png') image inspect. (ImageReader fromFile: 'png\g25n2c08.png') image inspect. (ImageReader fromFile: 'png\g03n3p04.png') image inspect. (ImageReader fromFile: 'png\g04n3p04.png') image inspect. (ImageReader fromFile: 'png\g05n3p04.png') image inspect. (ImageReader fromFile: 'png\g07n3p04.png') image inspect. (ImageReader fromFile: 'png\g10n3p04.png') image inspect. (ImageReader fromFile: 'png\g25n3p04.png') image inspect. (ImageReader fromFile: 'png\f00n0g08.png') image inspect. (ImageReader fromFile: 'png\f01n0g08.png') image inspect. (ImageReader fromFile: 'png\f02n0g08.png') image inspect. (ImageReader fromFile: 'png\f03n0g08.png') image inspect. (ImageReader fromFile: 'png\f04n0g08.png') image inspect. (ImageReader fromFile: 'png\f00n2c08.png') image inspect. (ImageReader fromFile: 'png\f01n2c08.png') image inspect. (ImageReader fromFile: 'png\f02n2c08.png') image inspect. (ImageReader fromFile: 'png\f03n2c08.png') image inspect. (ImageReader fromFile: 'png\f04n2c08.png') image inspect. (ImageReader fromFile: 'png\pp0n0g08.png') image inspect. "fail" (ImageReader fromFile: 'png\pp0n2c16.png') image inspect. "fail" (ImageReader fromFile: 'png\ps1n0g08.png') image inspect. (ImageReader fromFile: 'png\ps1n2c16.png') image inspect. (ImageReader fromFile: 'png\ps2n0g08.png') image inspect. (ImageReader fromFile: 'png\ps2n2c16.png') image inspect. (ImageReader fromFile: 'png\cs5n2c08.png') image inspect. (ImageReader fromFile: 'png\cs8n2c08.png') image inspect. (ImageReader fromFile: 'png\cs3n2c16.png') image inspect. (ImageReader fromFile: 'png\cs3n3p08.png') image inspect. (ImageReader fromFile: 'png\cs5n3p08.png') image inspect. (ImageReader fromFile: 'png\cs8n3p08.png') image inspect. (ImageReader fromFile: 'png\cdfn2c08.png') image inspect. (ImageReader fromFile: 'png\cdhn2c08.png') image inspect. (ImageReader fromFile: 'png\cdsn2c08.png') image inspect. (ImageReader fromFile: 'png\cdun2c08.png') image inspect. (ImageReader fromFile: 'png\ccwn2c08.png') image inspect. (ImageReader fromFile: 'png\ccwn3p08.png') image inspect. (ImageReader fromFile: 'png\ch1n3p04.png') image inspect. (ImageReader fromFile: 'png\ch2n3p08.png') image inspect. (ImageReader fromFile: 'png\cm7n0g04.png') image inspect. (ImageReader fromFile: 'png\cm9n0g04.png') image inspect. (ImageReader fromFile: 'png\cm0n0g04.png') image inspect. (ImageReader fromFile: 'png\ct0n0g04.png') image inspect. (ImageReader fromFile: 'png\ct1n0g04.png') image inspect. (ImageReader fromFile: 'png\ctzn0g04.png') image inspect. (ImageReader fromFile: 'png\oi1n0g16.png') image inspect. (ImageReader fromFile: 'png\oi2n0g16.png') image inspect. (ImageReader fromFile: 'png\oi4n0g16.png') image inspect. (ImageReader fromFile: 'png\oi9n0g16.png') image inspect. (ImageReader fromFile: 'png\oi1n2c16.png') image inspect. (ImageReader fromFile: 'png\oi2n2c16.png') image inspect. (ImageReader fromFile: 'png\oi4n2c16.png') image inspect. (ImageReader fromFile: 'png\oi9n2c16.png') image inspect. (ImageReader fromFile: 'png\z00n2c08.png') image inspect. (ImageReader fromFile: 'png\z03n2c08.png') image inspect. (ImageReader fromFile: 'png\z06n2c08.png') image inspect. (ImageReader fromFile: 'png\z09n2c08.png') image inspect. (ImageReader fromFile: 'pngtests\x00n0g01.png') image inspect. "Doesn't fail, but should" (ImageReader fromFile: 'png\xcrn0g04.png') image inspect. "Properly Fails" (ImageReader fromFile: 'png\xlfn0g04.png') image inspect. "Properly Fails"
</comment> <class> <name>GIFImageReader</name> <environment>Graphics</environment> <super>Graphics.ImageReader</super> <private>false</private> none xpos ypos pass interlace codeSize clearCode eoiCode freeCode maxCode remainBitCount bufStream transparentIndex <imports></imports> <category>Graphics-ImageReaders</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.GIFImageReader
Class GIFImageReader represents a reader for GIF87a and GIF89a images Adapted from Squeak 2.7 Instance Variables: bufStream <PeekableStream> private variable used for local streaming of bits clearCode <ArithmeticValue> private variable used in decoding image codeSize <ArithmeticValue> private variable used in decoding image eoiCode <Object> private variable used in decoding image freeCode <ArithmeticValue> private variable used in decoding image interlace <Boolean> private variable used in decoding image maxCode <Object> private variable used in decoding image pass <ArithmeticValue> private variable used in decoding image remainBitCount <ArithmeticValue> private variable used in decoding image transparentIndex <ArithmeticValue> private variable used in decoding image xpos <ArithmeticValue> private variable used in decoding image ypos <ArithmeticValue> private variable used in decoding image
</comment> <class> <name>PNGInflateStream</name> <environment>Graphics</environment> <super>OS.ZLib.InflateStream</super> <private>false</private> none <imports></imports> <category>Graphics-ImageReaders</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.PNGInflateStream
PNGInflateStream is an InflateStream that knows how to decompress picture data for a PNG data structure. RFC-1950 describes the ZLIB data format. This class can only decompress data that has a compression method of 8, a LZ77 window size no larger than 32K and the absence of a preset dictionary in the header. Any stream that does not meet these criteria will cause an error to be raised from #checkHeader. In practice, this limitiation appears to allow VisualWorks to be able to read most PNG images.
</comment> <class> <name>XBMImageReader</name> <environment>Graphics</environment> <super>Graphics.ImageReader</super> <private>false</private> none <imports></imports> <category>Graphics-ImageReaders</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.XBMImageReader
Class XBMImageReader represents a reader for X Monochrome Bitmap files Adapted from Squeak 2.7
</comment> <class> <name>JPEGHuffmanTable</name> <environment>Graphics</environment> <super>Core.Object</super> <private>false</private> none bits values mincode maxcode valptr lookaheadBits lookaheadSymbol <imports></imports> <category>Graphics-ImageReaders</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.JPEGHuffmanTable
I represent the table of values used to decode Huffman entropy-encoded bitstreams. From the JFIF file header entropy values, I build a derived table of codes and values for faster decoding. Adapted from Squeak 2.7 Instance Variables: bits <ByteArray> current bits used to decode Huffman entropy-encoded bitstreams lookaheadBits <ByteArray> current lookahead bits used to decode Huffman entropy-encoded bitstreams lookaheadSymbol <ByteArray> current bits that translate to value used to decode Huffman entropy-encoded bitstreams maxcode <ByteArray> private variable used to create Huffman tables mincode <ByteArray> private variable used to create Huffman tables valptr <(Array of: ArithmeticValue)> private variable used to create Huffman tables values <ByteArray> current values used to decode Huffman entropy-encoded bitstreams
</comment> <class> <name>BMPImageReader</name> <environment>Graphics</environment> <super>Graphics.ImageReader</super> <private>false</private> none win3 fileSize imageByteOffset headerSize bottomToTop planes compression compressedImageByteSize hRes vRes numColors numImportantColors dataPosition rowEnd nextRow inHighNibble partialByte <imports></imports> <category>Graphics-ImageReaders</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.BMPImageReader
Class BMPReader represents a reader for Windows 3.x and OS/2 BMP-format image files. Restriction: doesn't understand extended Windows BMP formats such as embedded JPEG. Instance Variables: win3 <Boolean> whether the image is in Windows format, rather than OS/2 fileSize <Integer> size of the image file in bytes imageByteOffset <Integer> offset of the image data headerSize <Integer> number of bytes in the BITMAPINFOHEADER bottomToTop <Boolean> whether image data is stored in bottom-to-top scanline order planes <Integer> number of planes in image data compression <Integer> code for the type of image compression compressedImageBytes <Integer> number of bytes in the compressed image data hRes <Integer> horizontal resolution, in pixels per meter vRes <Integer> vertical resolution, in pixels per meter numColors <Integer> number of colors used in image; zero means (2 raisedTo: bitsPerPixel) numImportantColors <Integer> number of colors regarded as important; zero means that all colors are important dataPosition <Integer> current offset into imageData rowEnd <Integer> absolute position of the end of the current row in imageData nextRow <Integer> absolute position of the beginning of the next row in imageData inHighNibble <Boolean> whether the current position is the high (vs. the low) nibble (4-bit pixel) at the current byte position (dataPosition) partialByte <Integer> partial byte built up during nibble reading
</comment> <class> <name>JPEGColorComponent</name> <environment>Graphics</environment> <super>Core.Object</super> <private>false</private> none id hSampleFactor vSampleFactor dctSize qTableIndex dcTableIndex acTableIndex widthInBlocks heightInBlocks mcuWidth mcuHeight mcuBlocks currentX currentY priorDCValue <imports></imports> <category>Graphics-ImageReaders</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.JPEGColorComponent
I represent a single component of color in JPEG YCbCr color space. I can accept a list of blocks in my component from the current MCU, then stream the samples from this block for use in color conversion. I also store the running DC sample value for my component, used by the Huffman decoder. Adapted from Squeak 2.7 Instance Variables: acTableIndex <Object> private variable used to translate YCbCr space currentX <Number> private variable used to translate YCbCr space currentY <Number> private variable used to translate YCbCr space dcTableIndex <Object> private variable used to translate YCbCr space dctSize <Object> private variable used to translate YCbCr space heightInBlocks <ArithmeticValue> private variable used to translate YCbCr space hSampleFactor <Object> private variable used to translate YCbCr space id <Object> private variable used to translate YCbCr space mcuBlocks <Object> private variable used to translate YCbCr space mcuHeight <Number | Point> private variable used to translate YCbCr space mcuWidth <Number | Point> private variable used to translate YCbCr space priorDCValue <ArithmeticValue> private variable used to translate YCbCr space qTableIndex <Object> private variable used to translate YCbCr space vSampleFactor <Object> private variable used to translate YCbCr space widthInBlocks <Object> private variable used to translate YCbCr space
</comment> <class> <name>InvalidFormatError</name> <environment>Graphics</environment> <super>Core.Error</super> <private>false</private> none <imports></imports> <category>Graphics-Images</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.InvalidFormatError
Raised when the image stream is in an invalid format. Instance Variables:
</comment> <class> <name>JPEGImageReader</name> <environment>Graphics</environment> <super>Graphics.ImageReader</super> <private>false</private> none components currentComponents qTable hACTable hDCTable bitBuffer bitsInBuffer lookahead restartInterval restartsToGo mcuWidth mcuHeight mcusPerRow mcuRowsInScan mcuMembership mcuSampleBuffer mcuImageBuffer majorVersion minorVersion dataPrecision densityUnit xDensity yDensity sosSeen redResidual greenResidual blueResidual ditherMask comment <imports></imports> <category>Graphics-ImageReaders</category> <attributes> <package>ImageReaders</package> </attributes> </class> <comment> Graphics.JPEGImageReader
Class JPEGImageReader represents a reader for JPEG images Note: By default the SharedVariable UseFloatingPoint is false. This makes the reader faster, but not totally accurate in its rendition of JPEG files. The user can set this value to true by sending the JPEGImageReader class useFloatingPoint: method. This makes the reader somewhat slower, but fully accurate in its rendering of JPEG files. Not using floating point is about 20% faster. Adapted from Squeak 2.7 Instance Variables: bitBuffer <Integer> private variable used in decoding image bitsInBuffer <ArithmeticValue> private variable used in decoding image blueResidual <SmallInteger> private variable used in decoding image components <(Collection of: JPEGColorComponent)> private variable used in decoding image comment <ByteString | nil> comment from the file or nil if none currentComponents <(SequenceableCollection of: JPEGColorComponent)> description of components dataPrecision <Integer> Value describing the JPEG data precision used in the encoded image (We only support 8bit precision) densityUnit <Integer> Value describing the JPEG density unit used in the encoded image ditherMask <Object> private variable used in decoding image greenResidual <SmallInteger> private variable used in decoding image hACTable <Array of: JPEGHuffmanTable> private variable used in decoding image hDCTable <Array of: JPEGHuffmanTable> private variable used in decoding image lookahead <JPEGHuffmanTable> private variable used in decoding image majorVersion <Integer> JPEG major version number used in the original image mcuHeight <ArithmeticValue> private variable used in decoding image mcuImageBuffer <Image> private variable used in decoding image mcuMembership <SequenceableCollection> private variable used in decoding image mcuRowsInScan <Object> private variable used in decoding image mcuSampleBuffer <Object> private variable used in decoding image mcusPerRow <Object> private variable used in decoding image mcuWidth <Number> private variable used in decoding image minorVersion <Integer> JPEG minor version number used in the original image qTable <Array of: JPEGHuffmanTable> private variable used in decoding image redResidual <SmallInteger> private variable used in decoding image restartInterval <SmallInteger> private variable used in decoding image restartsToGo <ArithmeticValue | Set> private variable used in decoding image sosSeen <Boolean> private variable used in decoding image xDensity <SmallInteger> JPEG X axis density of the original image yDensity <SmallInteger> JPEG Y axis density of the original image
</comment> <name>BlockWidth</name> <environment>Graphics.PNGImageReader</environment> <private>false</private> <constant>false</constant> <category>PNGImageReader</category> <attributes> <package>ImageReaders</package> </attributes> <name>BPP</name> <environment>Graphics.PNGImageReader</environment> <private>false</private> <constant>false</constant> <category>PNGImageReader</category> <attributes> <package>ImageReaders</package> </attributes> <name>BlockHeight</name> <environment>Graphics.PNGImageReader</environment> <private>false</private> <constant>false</constant> <category>PNGImageReader</category> <attributes> <package>ImageReaders</package> </attributes> <name>BI_RLE8</name> <environment>Graphics.BMPImageReader</environment> <private>false</private> <constant>false</constant> <category>As yet unclassified</category> <attributes> <package>ImageReaders</package> </attributes> <name>BI_RLE4</name> <environment>Graphics.BMPImageReader</environment> <private>false</private> <constant>false</constant> <category>As yet unclassified</category> <attributes> <package>ImageReaders</package> </attributes> <name>BI_RGB</name> <environment>Graphics.BMPImageReader</environment> <private>false</private> <constant>false</constant> <category>As yet unclassified</category> <attributes> <package>ImageReaders</package> </attributes> <name>BI_BITFIELDS</name> <environment>Graphics.BMPImageReader</environment> <private>false</private> <constant>false</constant> <category>As yet unclassified</category> <attributes> <package>ImageReaders</package> </attributes> <name>BitmapHeaderOffset</name> <environment>Graphics.BMPImageReader</environment> <private>false</private> <constant>false</constant> <category>As yet unclassified</category> <attributes> <package>ImageReaders</package> </attributes> <name>BMPDepth24Palette</name> <environment>Graphics.BMPImageReader</environment> <private>false</private> <constant>false</constant> <category>As yet unclassified</category> <attributes> <package>ImageReaders</package> </attributes> <name>Extension</name> <environment>Graphics.GIFImageReader</environment> <private>false</private> <constant>false</constant> <category>GIF Constants</category> <attributes> <package>ImageReaders</package> </attributes> <name>Terminator</name> <environment>Graphics.GIFImageReader</environment> <private>false</private> <constant>false</constant> <category>GIF Constants</category> <attributes> <package>ImageReaders</package> </attributes> <name>ImageSeparator</name> <environment>Graphics.GIFImageReader</environment> <private>false</private> <constant>false</constant> <category>GIF Constants</category> <attributes> <package>ImageReaders</package> </attributes> <name>Flipbits</name> <environment>Graphics.XBMImageReader</environment> <private>false</private> <constant>false</constant> <category>XBM Constants</category> <attributes> <package>ImageReaders</package> </attributes> <name>BitBufferSize</name> <environment>Graphics.JPEGHuffmanTable</environment> <private>false</private> <constant>false</constant> <category>Graphics-Images</category> <attributes> <package>ImageReaders</package> </attributes> <name>Lookahead</name> <environment>Graphics.JPEGHuffmanTable</environment> <private>false</private> <constant>true</constant> <category>Graphics-Images</category> <initializer>8</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>QTableScaleFactor</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>false</constant> <category>Graphics-Images</category> <attributes> <package>ImageReaders</package> </attributes> <name>Pass1Bits</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>floating-point IDCT constants</category> <initializer> 2 </initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn0n390180644Negated</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>3196 negated</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn1n175875602</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>9633</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>DCTSize</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>general constants</category> <initializer>8</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn3n072711026</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>25172</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn1n847759065Negated</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>15137 negated</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn0n899976223Negated</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>7373 negated</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>DCTSize2</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>general constants</category> <initializer> 8 squared " DCTSize squared " </initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn0n541196100</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>4433</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>DCTK4</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>floating-point IDCT constants</category> <initializer> -2.613125930d </initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn2n562915447Negated</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>20995 negated</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>DCTK2</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>floating-point IDCT constants</category> <initializer> 1.847759065d </initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn1n961570560</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>16069</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>SampleOffset</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>general constants</category> <initializer> ((2 raisedTo: 8) - 1) // 2 "MaxSample // 2." </initializer> <attributes> <package>ImageReaders</package> </attributes> <name>UseFloatingPoint</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>false</constant> <category>Graphics-Images</category> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn1n40200</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point color conversion constants</category> <initializer>91881</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn1n961570560Negated</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>16069 negated</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>HuffmanTableSize</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>general constants</category> <initializer>4</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn0n765366865</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>6270</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn0n298631336</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>2446</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FloatSampleOffset</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>general constants</category> <initializer> (((2 raisedTo: 8) - 1) // 2) asFloat "SampleOffset asFloat." </initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn1n501321110</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>12299</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>DitherMasks</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>false</constant> <category>Graphics-Images</category> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn0n71414</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point color conversion constants</category> <initializer>46802</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>ConstBits</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>floating-point IDCT constants</category> <initializer>13</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>MaxSample</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>general constants</category> <initializer> (2 raisedTo: 8) - 1 "(2 raisedToInteger: DCTSize) - 1." </initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn0n34414</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point color conversion constants</category> <initializer>22554</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn2n053119869</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>16819</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>JFIFMarkerParser</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>false</constant> <category>Graphics-Images</category> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn1n847759065</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>15137</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn0n899976223</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>7373</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn2n562915447</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>20995</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn1n77200</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point color conversion constants</category> <initializer>116130</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>JPEGNaturalOrder</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>false</constant> <category>Graphics-Images</category> <attributes> <package>ImageReaders</package> </attributes> <name>FIXn0n390180644</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>fixed-point IDCT constants</category> <initializer>3196</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>DCTK3</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>floating-point IDCT constants</category> <initializer> 1.082392200d </initializer> <attributes> <package>ImageReaders</package> </attributes> <name>QuantizationTableSize</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>general constants</category> <initializer>4</initializer> <attributes> <package>ImageReaders</package> </attributes> <name>DCTK1</name> <environment>Graphics.JPEGImageReader</environment> <private>false</private> <constant>true</constant> <category>floating-point IDCT constants</category> <initializer> 2 sqrt </initializer> <attributes> <package>ImageReaders</package> </attributes> <methods> Graphics.ImageReader <category>attributes</category>
attributeKeysAndValuesDo: aBlock "Evaluate aBlock with the names and values of all the image attributes. The specific attributes enumerated vary by the external image format. Typical attributes include #format name of the image format #extent point specifying the width and height of the image in pixels #depth logical depth of the image #bitsPerPixel number of bits used to represent each pixel #planes number of planes used to store the image #resolution point specifying horizontal and vertical resolution in pixels per inch #compression string naming the type of compression used to store the image #numberOfColors number of colors actually used in the image #numberOfImportantColors number of colors considered 'important' for the image #description string describing the contents of the image." | resolution | aBlock value: #format value: self format. aBlock value: #extent value: image extent. aBlock value: #depth value: image depth. aBlock value: #bitsPerPixel value: image bitsPerPixel. resolution := self resolution. resolution = Point zero ifFalse: [aBlock value: #resolution value: resolution]
format "Answer a string naming the format used to store the image." ^self subclassResponsibility
resolution "Answer a point indicating the horizontal and vertical resolution of the image in pixels per inch. If not specified, answer 0@0." ^0@0
</methods> <methods> Graphics.ImageReader <category>private</category>
formatError: errorString "Raise a signal that indicates an invalid image stream format." ^self class invalidFormatSignal raiseErrorString: errorString
nextLSBLong "Answer the integer stored (least-significant-bit first) in the next four bytes of the input stream." | word highByte | "Minimize LargeInteger arithmetic." word := ioStream next + (ioStream next bitShift: 8) + (ioStream next bitShift: 16). ^(highByte := ioStream next) = 0 ifTrue: [word] ifFalse: [(((highByte bitAnd: 16r7F) - (highByte bitAnd: 16r80)) bitShift: 24) + word]
nextLSBShort "Answer the integer stored (least-significant-bit first) in the next two bytes of the input stream." | word | word := self nextLSBUnsignedShort. ^(word bitAnd: 16r7FFF) - (word bitAnd: 16r8000)
nextLSBUnsignedLong "Answer the unsigned integer stored (least-significant-bit first) in the next four bytes of the input stream." ^ioStream next + (ioStream next bitShift: 8) + (ioStream next bitShift: 16) + (ioStream next bitShift: 24)
nextLSBUnsignedShort "Answer the unsigned integer stored (least-significant-bit first) in the next two bytes of the input stream." ^ioStream next + (ioStream next bitShift: 8)
</methods> <methods> Graphics.ImageReader <category>initialize-release</category>
from: binaryStream "Initialize from a binary stream containing the image data." ioStream := binaryStream. self readImage
readImage "Read the image stored the input stream." self subclassResponsibility
</methods> <methods> Graphics.ImageReader <category>accessing</category>
image "Answer the image read from the input stream." ^image
</methods> <methods> Graphics.ImageReader class <category>private</category>
canRead: imageStream "Answer whether the receiver can read the image data in the binary stream <imageStream>." "Subclasses may override." ^false
install: anImage inClass: aClass selector: targetSelector "Install the image as a resource method of the given class. Note that in order to install a method on the class side, a metaclass should be passed as the argument (i.e., for example 'IconLibrary class')." | s | s := WriteStream on: (String new: anImage bits size // 8). s nextPutAll: targetSelector. s cr. s tab. s nextPutAll: '"UIMaskEditor new openOnClass: self andSelector: #'. s nextPutAll: targetSelector; nextPut: $"; cr. s crtab; nextPutAll: '<resource: #image>'. s crtab; nextPut: $^. s nextPutAll: 'CachedImage on: '. s nextPutAll: anImage minimalStorageString. aClass compile: s contents classified: #resources. Transcript cr; show: ((#x1s2sDefined << #dialogs >> '<1s>%><2s> defined') expandMacrosWith: aClass name with: targetSelector)
readerClassFor: imageStream "Answer the image reader class appropriate for reading the image in the binary stream <imageStream>." self allSubclassesDo: [:class | (class canRead: imageStream) ifTrue: [^class]]. ^self error: (#errDetermineImageFile << #dialogs >> 'Unable to determine type of image file.')
</methods> <methods> Graphics.ImageReader class <category>examples</category>
displayFromFile: aFilenameOrString "Display the image stored in the named file." self displayFromFile: aFilenameOrString renderedBy: Screen default defaultColorPolicy imageRenderer
displayFromFile: aFilenameOrString renderedBy: anImageRenderer "Display the image stored in the named file." | window reader image | reader := self fromFile: aFilenameOrString. image := reader image. reader attributeKeysAndValuesDo: [:attribute :value | Transcript cr; nextPutAll: attribute; nextPutAll: ': '; print: value]. Transcript flush. window := ScheduledWindow model: image label: (#Image << #examples >> 'Image') minimumSize: image bounds extent. window component: (WidgetWrapper on: (image convertForGraphicsDevice: Screen default renderedBy: anImageRenderer)). window open
</methods> <methods> Graphics.ImageReader class <category>resource method creation</category>
iconFromFile: aFilenameOrString toClass: aClass selector: targetSelector "Similar to imageFromFile, but the file is expected to contain transparency. As of VW 7.3, the reliably supported file format for that is GIF. Two resource methods are generated, one for and OpaqueImage's figure, the other for the mask. The figure is installed into the class under targetSelector, the mark under the targetSelector with 'mask' appended." | reader image mask metaClass | metaClass := aClass isMeta ifTrue: [aClass] ifFalse: [aClass class]. reader := ImageReader fromFile: aFilenameOrString. image := reader image. mask := reader mask. self install: image inClass: metaClass selector: targetSelector; install: mask inClass: metaClass selector: (targetSelector, 'mask') asSymbol "ImageReader iconFromFile: '/Users/vb/Desktop/step.gif' toClass: ToolbarIconLibrary selector: #step20x20"
imageFromFile: aFilenameOrString toClass: aClass selector: targetSelector "Read the image from aFilenameOrString and convert it into a Smalltalk graphic image. Store the specification for the Smalltalk graphic image in a resource method named targetSelector (aSymbol) on the class side of aClass. This method can be used in a workspace to import an image that was constructed with an external painting program and install it into an ApplicationModel subclass image resource method. See ImageReader subclasses for the supported image formats." | image metaClass | metaClass := aClass isMeta ifTrue: [aClass] ifFalse: [aClass class]. image := (ImageReader fromFile: aFilenameOrString) image. self install: image inClass: metaClass selector: targetSelector "ImageReader imageFromFile: 'c:\windows\Solstice.bmp' toClass: Foo selector: #buttonBar"
</methods> <methods> Graphics.ImageReader class <category>class initialization</category>
initialize " ImageReader initialize. " InvalidFormatError notifierString: (#errImageFormat << #dialogs >> 'Invalid image format: '); nameClass: self message: #invalidFormatSignal
</methods> <methods> Graphics.ImageReader class <category>Signal constants</category>
invalidFormatSignal "Answer the Signal raised when the image stream is in an invalid format." ^InvalidFormatError
</methods> <methods> Graphics.ImageReader class <category>instance creation</category>
fromFile: aFilenameOrString "Answer an instance initialized from the file named aFilenameOrString." | readerClass imageStream reader | [imageStream := (aFilenameOrString asFilename withEncoding: #binary) readStream. readerClass := self readerClassFor: imageStream. reader := readerClass new from: imageStream] ensure: [imageStream ifNotNil: [:stream | stream close]]. ^reader
</methods> <methods> Graphics.PNGImageReader <category>pixel copies</category>
copyPixels: y "Handle non-interlaced pixels of supported colorTypes" | selector | selector := #(#copyPixelsGray: nil #copyPixelsRGB: #copyPixelsIndexed: #copyPixelsGrayAlpha: nil #copyPixelsRGBA:) at: colorType + 1. self perform: selector asSymbol with: y
copyPixels: y at: startX by: incX "Handle interlaced pixels of supported colorTypes" | selector | selector := #(#copyPixelsGray:at:by: nil #copyPixelsRGB:at:by: #copyPixelsIndexed:at:by: #copyPixelsGrayAlpha:at:by: nil #copyPixelsRGBA:at:by:) at: colorType + 1. self perform: selector asSymbol with: y with: startX with: incX
copyPixelsGray: y "Handle non-interlaced grayscale color mode (colorType = 0)" | tempImage pixPerByte mask shifts pixelNumber rawByte pixel | tempImage := Image extent: width @ 1 depth: depth palette: palette. bitsPerChannel = 16 ifTrue: [0 to: width - 1 do: [:x | tempImage atPoint: x @ 0 put: (thisScanline at: (x bitShift: 1) + 1)]]. bitsPerChannel = 8 ifTrue: [1 to: width do: [:x | tempImage atPoint: (x - 1) @ 0 put: (thisScanline at: x)]]. bitsPerChannel < 8 ifTrue: [bitsPerChannel = 1 ifTrue: [pixPerByte := 8. mask := 1. shifts := #(7 6 5 4 3 2 1 0)]. bitsPerChannel = 2 ifTrue: [pixPerByte := 4. mask := 3. shifts := #(6 4 2 0)]. bitsPerChannel = 4 ifTrue: [pixPerByte := 2. mask := 15. shifts := #(4 0)]. pixelNumber := 0. 0 to: width - 1 do: [:index | rawByte := thisScanline at: pixelNumber // pixPerByte + 1. pixel := (rawByte bitShift: (shifts at: pixelNumber \\ pixPerByte + 1) negated) bitAnd: mask. tempImage atPoint: index @ 0 put: pixel. pixelNumber := pixelNumber + 1]]. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp over
copyPixelsGray: y at: startX by: incX "Handle interlaced grayscale color mode (colorType = 0)" | pixel mask pixelNumber pixPerByte rawByte shifts tempImage | tempImage := Image extent: width @ 1 depth: depth palette: palette. bitsPerChannel = 16 ifTrue: [startX to: width - 1 by: incX do: [:index | tempImage atPoint: index @ 0 put: (thisScanline at: (index // incX bitShift: 1) + 1)]]. bitsPerChannel = 8 ifTrue: [startX to: width - 1 by: incX do: [:index | tempImage atPoint: index @ 0 put: (thisScanline at: index // incX + 1)]]. bitsPerChannel < 8 ifTrue: [bitsPerChannel = 1 ifTrue: [pixPerByte := 8. mask := 1. shifts := #(7 6 5 4 3 2 1 0)]. bitsPerChannel = 2 ifTrue: [pixPerByte := 4. mask := 3. shifts := #(6 4 2 0)]. bitsPerChannel = 4 ifTrue: [pixPerByte := 2. mask := 15. shifts := #(4 0)]. pixelNumber := 0. startX to: width - 1 by: incX do: [:x | rawByte := thisScanline at: pixelNumber // pixPerByte + 1. pixel := (rawByte bitShift: (shifts at: (pixelNumber \\ pixPerByte) + 1) negated) bitAnd: mask. tempImage atPoint: x @ 0 put: pixel. pixelNumber := pixelNumber + 1]]. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp paint
copyPixelsGrayAlpha: y "Handle non-interlaced grayscale with alpha color mode (colorType = 4)" | scanlineIndex pixel gray tempImage | tempImage := Image extent: width @ 1 depth: depth palette: palette. bitsPerChannel = 8 ifTrue: [0 to: width - 1 do: [:index | scanlineIndex := (index bitShift: 1) + 1. gray := thisScanline at: scanlineIndex. pixel := ((thisScanline at: scanlineIndex + 1) bitShift: 24) + (gray bitShift: 16) + (gray bitShift: 8) + gray. tempImage atPoint: index @ 0 put: pixel]] ifFalse: [0 to: width - 1 do: [:index | scanlineIndex := (index bitShift: 2) + 1. gray := thisScanline at: scanlineIndex. pixel := ((thisScanline at: scanlineIndex + 2) bitShift: 24) + (gray bitShift: 16) + (gray bitShift: 8) + gray. tempImage atPoint: index @ 0 put: pixel]]. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp over
copyPixelsGrayAlpha: y at: startX by: incX "Handle interlaced grayscale with alpha color mode (colorType = 4)" | scanlineIndex pixel gray tempImage | tempImage := Image extent: width @ 1 depth: depth palette: palette. bitsPerChannel = 8 ifTrue: [startX to: width - 1 by: incX do: [:index | scanlineIndex := (index // incX bitShift: 1) + 1. gray := thisScanline at: scanlineIndex. pixel := ((thisScanline at: scanlineIndex + 1) bitShift: 24) + (gray bitShift: 16) + (gray bitShift: 8) + gray. tempImage atPoint: index @ 0 put: pixel]] ifFalse: [startX to: width - 1 by: incX do: [:index | scanlineIndex := (index // incX bitShift: 2) + 1. gray := thisScanline at: scanlineIndex. pixel := ((thisScanline at: scanlineIndex + 2) bitShift: 24) + (gray bitShift: 16) + (gray bitShift: 8) + gray. tempImage atPoint: index @ 0 put: pixel]]. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp paint
copyPixelsIndexed: y "Handle non-interlaced indexed color mode (colorType = 3)" | tempImage pixPerByte mask shifts pixelNumber rawByte pixel | tempImage := Image extent: width @ 1 depth: depth palette: palette. bitsPerChannel = 8 ifTrue: [1 to: width do: [:index | tempImage atPoint: (index - 1) @ 0 put: (thisScanline at: index)]]. bitsPerChannel = 1 ifTrue: [pixPerByte := 8. mask := 1. shifts := #(7 6 5 4 3 2 1 0)]. bitsPerChannel = 2 ifTrue: [pixPerByte := 4. mask := 3. shifts := #(6 4 2 0)]. bitsPerChannel = 4 ifTrue: [pixPerByte := 2. mask := 15. shifts := #(4 0)]. bitsPerChannel = 8 ifFalse: [pixelNumber := 0. 0 to: width - 1 do: [:index | rawByte := thisScanline at: pixelNumber // pixPerByte + 1. pixel := (rawByte bitShift: (shifts at: (pixelNumber \\ pixPerByte) + 1) negated) bitAnd: mask. tempImage atPoint: index @ 0 put: pixel. pixelNumber := pixelNumber + 1]]. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp over
copyPixelsIndexed: y at: startX by: incX "Handle interlaced indexed color mode (colorType = 3)" | pixPerByte shifts tempImage mask | tempImage := Image extent: width @ 1 depth: depth palette: palette. bitsPerChannel = 8 ifTrue: [startX to: width - 1 by: incX do: [:index | tempImage atPoint: index @ 0 put: (thisScanline at: index // incX + 1)]]. bitsPerChannel = 1 ifTrue: [pixPerByte := 8. mask := 1. shifts := #(7 6 5 4 3 2 1 0)]. bitsPerChannel = 2 ifTrue: [pixPerByte := 4. mask := 3. shifts := #(6 4 2 0)]. bitsPerChannel = 4 ifTrue: [pixPerByte := 2. mask := 15. shifts := #(4 0)]. bitsPerChannel = 8 ifFalse: [| pixelNumber | pixelNumber := 0. startX to: width - 1 by: incX do: [:index | | rawByte pixel | rawByte := thisScanline at: pixelNumber // pixPerByte + 1. pixel := (rawByte bitShift: (shifts at: (pixelNumber \\ pixPerByte) + 1) negated) bitAnd: mask. tempImage atPoint: index @ 0 put: pixel. pixelNumber := pixelNumber + 1]]. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp paint
copyPixelsRGB: y "Handle non-interlaced RGB color mode (colorType = 2)" | tempImage translatedScan scanIndex | translatedScan := ByteArray new: image packedRowSize. tempImage := Image extent: width @ 1 depth: 32 palette: palette. scanIndex := 1. bitsPerChannel = 8 ifTrue: [1 to: image packedRowSize by: 4 do: [:index | translatedScan at: index + 0 put: 0. translatedScan at: index + 1 put: (thisScanline at: scanIndex + 2). translatedScan at: index + 2 put: (thisScanline at: scanIndex + 1). translatedScan at: index + 3 put: (thisScanline at: scanIndex + 0). scanIndex := scanIndex + 3]] ifFalse: [1 to: image packedRowSize by: 4 do: [:index | translatedScan at: index + 0 put: 0. translatedScan at: index + 1 put: (thisScanline at: scanIndex + 4). translatedScan at: index + 2 put: (thisScanline at: scanIndex + 2). translatedScan at: index + 3 put: (thisScanline at: scanIndex + 0). scanIndex := scanIndex + 6]]. tempImage packedRowAt: 0 putAll: translatedScan. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp over
copyPixelsRGB: y at: startX by: incX "Handle interlaced RGB color mode (colorType = 2)" | translatedScan loopsToDo scanlineIndex translatedIndex tempImage | translatedScan := ByteArray new: image packedRowSize. tempImage := Image extent: width @ 1 depth: 32 palette: palette. loopsToDo := width - startX + incX - 1 // incX. bitsPerChannel = 8 ifTrue: [ scanlineIndex := 1. translatedIndex := 1. loopsToDo timesRepeat: [incX timesRepeat: [translatedIndex > translatedScan size ifFalse: [translatedScan at: translatedIndex + 0 put: 0. translatedScan at: translatedIndex + 1 put: (thisScanline at: scanlineIndex + 2). translatedScan at: translatedIndex + 2 put: (thisScanline at: scanlineIndex + 1). translatedScan at: translatedIndex + 3 put: (thisScanline at: scanlineIndex + 0)]. translatedIndex := translatedIndex + 4]. scanlineIndex := scanlineIndex + 3]]. bitsPerChannel = 8 ifFalse: [ scanlineIndex := 1. translatedIndex := 1. loopsToDo timesRepeat: [incX timesRepeat: [translatedIndex > translatedScan size ifFalse: [translatedScan at: translatedIndex + 0 put: 0. translatedScan at: translatedIndex + 1 put: (thisScanline at: scanlineIndex + 4). translatedScan at: translatedIndex + 2 put: (thisScanline at: scanlineIndex + 2). translatedScan at: translatedIndex + 3 put: (thisScanline at: scanlineIndex + 0)]. translatedIndex := translatedIndex + 4]. scanlineIndex := scanlineIndex + 6]]. tempImage packedRowAt: 0 putAll: translatedScan. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp paint
copyPixelsRGBA: y "Handle non-interlaced RGBA color modes (colorType = 6)" | tempImage translatedScan | translatedScan := ByteArray new: thisScanline size. tempImage := Image extent: width @ 1 depth: 32 palette: self class defaultPalette. bitsPerChannel = 8 ifTrue: [1 to: thisScanline size by: 4 do: [:index | translatedScan at: index + 0 put: (thisScanline at: index + 3). translatedScan at: index + 1 put: (thisScanline at: index + 2). translatedScan at: index + 2 put: (thisScanline at: index + 1). translatedScan at: index + 3 put: (thisScanline at: index + 0)]] ifFalse: [ | scanlineIndex | scanlineIndex := 1. 1 to: thisScanline size // 2 by: 4 do: [:index | translatedScan at: index + 0 put: (thisScanline at: scanlineIndex + 6). translatedScan at: index + 1 put: (thisScanline at: scanlineIndex + 4). translatedScan at: index + 2 put: (thisScanline at: scanlineIndex + 2). translatedScan at: index + 3 put: (thisScanline at: scanlineIndex + 0). scanlineIndex := scanlineIndex + 8]] . tempImage packedRowAt: 0 putAll: translatedScan. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp over
copyPixelsRGBA: y at: startX by: incX "Handle interlaced RGBA color modes (colorType = 6)" | tempImage translatedScan loopsToDo scanlineIndex translatedIndex | translatedScan := ByteArray new: image packedRowSize. tempImage := Image extent: width @ 1 depth: 32 palette: self class defaultPalette. loopsToDo := width - startX + incX - 1 // incX. scanlineIndex := translatedIndex := 1. bitsPerChannel = 8 ifTrue: [ loopsToDo timesRepeat: [incX timesRepeat: [translatedIndex > translatedScan size ifFalse: [translatedScan at: translatedIndex + 0 put: (thisScanline at: scanlineIndex + 3). translatedScan at: translatedIndex + 1 put: (thisScanline at: scanlineIndex + 2). translatedScan at: translatedIndex + 2 put: (thisScanline at: scanlineIndex + 1). translatedScan at: translatedIndex + 3 put: (thisScanline at: scanlineIndex + 0)]. translatedIndex := translatedIndex + 4]. scanlineIndex := scanlineIndex + 4]]. bitsPerChannel = 8 ifFalse: [ loopsToDo timesRepeat: [incX timesRepeat: [translatedIndex > translatedScan size ifFalse: [translatedScan at: translatedIndex + 0 put: (thisScanline at: scanlineIndex + 6). translatedScan at: translatedIndex + 1 put: (thisScanline at: scanlineIndex + 4). translatedScan at: translatedIndex + 2 put: (thisScanline at: scanlineIndex + 2). translatedScan at: translatedIndex + 3 put: (thisScanline at: scanlineIndex + 0)]. translatedIndex := translatedIndex + 4]. scanlineIndex := scanlineIndex + 8]]. tempImage packedRowAt: 0 putAll: translatedScan. image copy: (0 @ y extent: width @ 1) from: 0 @ 0 in: tempImage rule: RasterOp paint
</methods> <methods> Graphics.PNGImageReader <category>chunks</category>
processBackgroundChunk | val red green blue max worker colorValue | colorType = 3 ifTrue: [colorValue := palette at: chunk first]. max := (2 raisedTo: bitsPerChannel) - 1. (colorType = 0 or: [colorType = 4]) ifTrue: [val := (UninterpretedBytes from: chunk) unsignedShortAt: 1 bigEndian: true. colorValue := ColorValue brightness: val / max]. (colorType = 2 or: [colorType = 6]) ifTrue: [red := (UninterpretedBytes from: chunk) unsignedShortAt: 1 bigEndian: true. green := (UninterpretedBytes from: chunk) unsignedShortAt: 3 bigEndian: true. blue := (UninterpretedBytes from: chunk) unsignedShortAt: 5 bigEndian: true. colorValue := ColorValue red: red green: green blue: blue range: max]. worker := Image extent: 1@1 depth: image depth bitsPerPixel: image bitsPerPixel palette: image palette. worker atPoint: 0@0 put: (palette indexOfPaintNearest: colorValue). image tile: image preferredBounds from: 0@0 in: worker rule: RasterOp paint.
processIDATChunk interlaceMethod = 0 ifTrue: [self processNonInterlaced] ifFalse: [self processInterlaced]
processIHDRChunk | translatedBytes | translatedBytes := UninterpretedBytes from: chunk. width := translatedBytes longAt: 1 bigEndian: true. height := translatedBytes longAt: 5 bigEndian: true. bitsPerChannel := chunk at: 9. colorType := chunk at: 10. interlaceMethod := chunk at: 13. (#(2 4 6) includes: colorType) ifTrue: [depth := 32. palette := self class defaultPalette. image := Image extent: width @ height depth: depth palette: palette]. (#(0 3) includes: colorType) ifTrue: [depth := bitsPerChannel min: 8. image := Image extent: width @ height depth: depth palette: (colorType = 0 ifTrue: [self grayColorsFor: depth] ifFalse: [palette := self class defaultPalette])]. bitsPerPixel := (BPP at: colorType + 1) at: bitsPerChannel highBit. bytesPerScanline := (width * bitsPerPixel + 7) // 8. rowSize := (image width * image depth) + 31 bitShift: 5 negated
processInterlaced | zlibReader filter bytesPerPass startingColumns columnIncrements rowIncrements startingRows currentColumnIncrement currentStartingColumn temp | startingColumns := #(0 4 0 2 0 1 0). columnIncrements := #(8 8 4 4 2 2 1). rowIncrements := #(8 8 8 4 4 2 2). startingRows := #(0 0 4 0 2 0 1). zlibReader := PNGInflateStream on: chunk . 1 to: 7 do: [:pass | (self doPass: pass) ifTrue: [currentColumnIncrement := columnIncrements at: pass. currentStartingColumn := startingColumns at: pass. bytesPerPass := ((width - currentStartingColumn + currentColumnIncrement - 1) // currentColumnIncrement * bitsPerPixel + 7) // 8. prevScanline := ByteArray new: bytesPerPass. thisScanline := ByteArray new: bytesPerScanline. (startingRows at: pass) to: height - 1 by: (rowIncrements at: pass) do: [:index | filter := zlibReader next. filtersSeen add: filter. (filter isNil or: [(filter between: 0 and: 4) not]) ifTrue: [^self]. thisScanline := zlibReader next: bytesPerPass into: thisScanline startingAt: 1. self filterScanline: filter count: bytesPerPass. self copyPixels: index at: currentStartingColumn by: currentColumnIncrement. temp := prevScanline. prevScanline := thisScanline. thisScanline := temp]]]
processNextChunk | length asciiType | length := self nextLong. asciiType := (ioStream next: 4) asString. chunk := ioStream next: length. self nextLong. "crc" asciiType = 'IEND' ifTrue: [^[ioStream atEnd] whileFalse: [ioStream next]]. (#('sBIT' 'gAMA') includes: asciiType) ifTrue: [^self]. asciiType = 'bKGD' ifTrue: [^self processBackgroundChunk]. asciiType = 'pHYs' ifTrue: [^self processPhysicalPixelChunk]. asciiType = 'tRNS' ifTrue: [^self processTransparencyChunk]. asciiType = 'IHDR' ifTrue: [^self processIHDRChunk]. asciiType = 'PLTE' ifTrue: [^self processPLTEChunk]. asciiType = 'IDAT' ifTrue: [^globalDataChunk := globalDataChunk isNil ifTrue: [chunk] ifFalse: [globalDataChunk , chunk]]. unknownChunks add: asciiType
processNonInterlaced | zlibReader filter temp | zlibReader := PNGInflateStream on: chunk. prevScanline := ByteArray new: bytesPerScanline. thisScanline := ByteArray new: bytesPerScanline. 0 to: height - 1 do: [:index | filter := (zlibReader next: 1) first. filtersSeen add: filter. (filter isNil or: [(filter between: 0 and: 4) not]) ifTrue: [^self]. thisScanline := zlibReader next: bytesPerScanline into: thisScanline startingAt: 1. self filterScanline: filter count: bytesPerScanline. self copyPixels: index. temp := prevScanline. prevScanline := thisScanline. thisScanline := temp]
processPhysicalPixelChunk "Currently we do nothing"
processPLTEChunk | colorCount chunkIndex colorArray | colorCount := chunk size // 3. colorArray := Array new: colorCount. 0 to: colorCount - 1 do: [:index | chunkIndex := index * 3 + 1. colorArray at: index + 1 put: (ColorValue red: (chunk at: chunkIndex) green: (chunk at: chunkIndex + 1) blue: (chunk at: chunkIndex + 2) range: 255)]. palette := MappedPalette withColors: colorArray. image := Image extent: width @ height depth: depth palette: palette
processTransparencyChunk | red green blue | colorType = 0 ifTrue: [| intensity | intensity := (UninterpretedBytes from: chunk) unsignedShortAt: 1 bigEndian: true. transparentPixelValues := Array with: (palette indexOfPaintNearest: (ColorValue red: intensity green: intensity blue: intensity range: (2 raisedTo: bitsPerChannel) - 1)). ^self]. colorType = 2 ifTrue: [red := (UninterpretedBytes from: chunk) unsignedShortAt: 1 bigEndian: true. green := (UninterpretedBytes from: chunk) unsignedShortAt: 3 bigEndian: true. blue := (UninterpretedBytes from: chunk) unsignedShortAt: 5 bigEndian: true. transparentPixelValues := Array with: (self class defaultPalette indexOfPaintNearest: (ColorValue red: red green: green blue: blue range: (2 raisedTo: bitsPerChannel) - 1)). ^self]. colorType = 3 ifTrue: ["Until Alpha channel display is implemented for Image account for only full transparency (i.e. alpha = 0)" chunk keysAndValuesDo: [:index :alpha | alpha = 0 ifTrue: [| key | key := index - 1. (palette includesKey: key) ifTrue: [transparentPixelValues add: key]]]. ^self]
</methods> <methods> Graphics.PNGImageReader <category>filtering</category>
filterAverage: count "Use the average of the pixel to the left and the pixel above as a predictor" | delta | delta := bitsPerPixel // 8 max: 1. 1 to: delta do: [:index | thisScanline at: index put: ((thisScanline at: index) + ((prevScanline at: index) // 2) bitAnd: 255)]. delta + 1 to: count do: [:index | thisScanline at: index put: ((thisScanline at: index) + (((prevScanline at: index) + (thisScanline at: index - delta)) // 2) bitAnd: 255)]
filterHorizontal: count "Use the pixel to the left as a predictor" | delta | delta := bitsPerPixel // 8 max: 1. delta + 1 to: count do: [:index | thisScanline at: index put: ((thisScanline at: index) + (thisScanline at: index - delta) bitAnd: 255)]
filterNone: count
filterPaeth: count "Select one of (the pixel to the left, the pixel above and the pixel to above left) to predict the value of this pixel" | delta | delta := bitsPerPixel // 8 max: 1. 1 to: delta do: [:index | thisScanline at: index put: ((thisScanline at: index) + (prevScanline at: index) bitAnd: 255)]. delta + 1 to: count do: [:index | thisScanline at: index put: ((thisScanline at: index) + (self paethPredictLeft: (thisScanline at: index - delta) above: (prevScanline at: index) aboveLeft: (prevScanline at: index - delta)) bitAnd: 255)]
filterScanline: filterType count: count self perform: (#(#filterNone: #filterHorizontal: #filterVertical: #filterAverage: #filterPaeth:) at: filterType + 1) with: count
filterVertical: count "Use the pixel above as a predictor" 1 to: count do: [:index | thisScanline at: index put: ((thisScanline at: index) + (prevScanline at: index) bitAnd: 255)]
paethPredictLeft: leftValue above: aboveValue aboveLeft: aboveLeftValue "Predicts the value of a pixel based on nearby pixels, based on Paeth (GG II, 1991)" | predictedLeft predictedAbove predictedAboveLeft | predictedLeft := aboveValue > aboveLeftValue ifTrue: [aboveValue - aboveLeftValue] ifFalse: [aboveLeftValue - aboveValue]. predictedAbove := leftValue > aboveLeftValue ifTrue: [leftValue - aboveLeftValue] ifFalse: [aboveLeftValue - leftValue]. predictedAboveLeft := leftValue + aboveValue - aboveLeftValue - aboveLeftValue. predictedAboveLeft < 0 ifTrue: [predictedAboveLeft := predictedAboveLeft * -1]. (predictedLeft <= predictedAbove and: [predictedLeft <= predictedAboveLeft]) ifTrue: [^leftValue]. predictedAbove <= predictedAboveLeft ifTrue: [^aboveValue]. ^aboveLeftValue
</methods> <methods> Graphics.PNGImageReader <category>miscellaneous</category>
doPass: pass "Certain interlace passes are skipped with certain small image dimensions" pass = 1 ifTrue: [^true]. (width = 1 and: [height = 1]) ifTrue: [^false]. pass = 2 ifTrue: [^width >= 5]. pass = 3 ifTrue: [^height >= 5]. pass = 4 ifTrue: [^width >= 3 or: [height >= 5]]. pass = 5 ifTrue: [^height >= 3]. pass = 6 ifTrue: [^width >= 2]. pass = 7 ifTrue: [^height >= 2]. ^false
grayColorsFor: monoDepth "return a color palette for a gray image" | colorArray | colorArray := Array new: (1 bitShift: monoDepth). monoDepth = 1 ifTrue: [colorArray at: 1 put: ColorValue black. colorArray at: 2 put: ColorValue white]. monoDepth = 2 ifTrue: [colorArray at: 1 put: ColorValue black. colorArray at: 2 put: (ColorValue brightness: 0.3333). colorArray at: 3 put: (ColorValue brightness: 0.6667). colorArray at: 4 put: ColorValue white]. monoDepth = 4 ifTrue: [0 to: 15 do: [:index | colorArray at: index + 1 put: (ColorValue brightness: (index / 15) asFloat)]]. monoDepth = 8 ifTrue: [0 to: 255 do: [:index | colorArray at: index + 1 put: (ColorValue brightness: (index / 255) asFloat)]]. ^palette := MappedPalette withColors: colorArray
nextLong "Read a 32-bit quantity from the input stream." ^(ioStream next bitShift: 24) + (ioStream next bitShift: 16) + (ioStream next bitShift: 8) + ioStream next
</methods> <methods> Graphics.PNGImageReader <category>accessing</category>
format ^'Portable Network Graphics (PNG)'
mask "Answer a 1-bit image defining the opaque area of the current image based on the transparency chunk." ^colorType > 3 ifTrue:[self maskFromAlphaChannel] ifFalse:[self maskFromTransparencyChunk]
readImage filtersSeen := Bag new. globalDataChunk := nil. transparentPixelValues := OrderedCollection new. unknownChunks := Set new. ioStream reset. (ioStream respondsTo: #binary) ifTrue: [ioStream binary]. ioStream skip: 8. [ioStream atEnd] whileFalse: [self processNextChunk]. chunk := globalDataChunk. chunk notNil ifTrue: [self processIDATChunk].
transparentPixelValues ^transparentPixelValues
</methods> <methods> Graphics.PNGImageReader <category>private</category>
maskFromAlphaChannel "Answer a mask defining the opaque area of the current image where the 4th byte alpha channel value > 0 (colorType = 4 or 6)" | mask | mask := Image extent: image extent depth: 1 palette: CoveragePalette monoMaskPalette. image pixelsDo: [:x :y | ((image atX: x y: y) bitShift: -24) > 0 ifTrue: [mask atX: x y: y put: 1]]. ^mask
maskFromTransparencyChunk "Answer a mask defining the opaque area of the current image based on the transparency chunk definition." | mask | mask := Image extent: image extent depth: 1 palette: CoveragePalette monoMaskPalette. image pixelsDo: [:x :y | (transparentPixelValues includes: (image atX: x y: y)) ifFalse: [mask atX: x y: y put: 1]]. ^mask
</methods> <methods> Graphics.PNGImageReader class <category>defaults</category>
defaultPalette ^FixedPalette redShift: 0 redMask: 16rFF greenShift: 8 greenMask: 16rFF blueShift: 16 blueMask: 16rFF
</methods> <methods> Graphics.PNGImageReader class <category>private</category>
canRead: imageStream imageStream reset. ^#(137 80 78 71 13 10 26 10) allSatisfy: [:byte | imageStream next asInteger = byte].
</methods> <methods> Graphics.PNGImageReader class <category>initialize</category>
initialize "PNGImageReader initialize" BPP := Array new: 8. BPP at: 1 put: #(1 2 4 8 16); at: 2 put: #(0 0 0 0 0); at: 3 put: #(0 0 0 24 48); at: 4 put: #(1 2 4 8 0); at: 5 put: #(0 0 0 16 32); at: 6 put: #(0 0 0 0 0); at: 7 put: #(0 0 0 32 64); at: 8 put: #(0 0 0 0 0). BlockHeight := #(8 8 4 4 2 2 1). BlockWidth := #(8 4 4 2 2 1 1)
</methods> <methods> Graphics.GIFImageReader <category>private-decoding</category>
checkCodeSize (freeCode > maxCode and: [codeSize < 12]) ifTrue: [codeSize := codeSize + 1. maxCode := (1 bitShift: codeSize) - 1]
readBitData "Use modified Lempel-Ziv Welch algorithm." | outCodes outCount bitMask initCodeSize code curCode oldCode inCode finChar bytes suffixTable prefixTable rowByteSize packedBits localPalette localBitsPerPixel | ioStream skip: 4. "Skip stuff I don't care about" width := self readWord. height := self readWord. packedBits := ioStream next. interlace := (packedBits bitAnd: 64) ~= 0. (packedBits bitAnd: 128) ~= 0 ifTrue: ["Has local color table" localBitsPerPixel := (packedBits bitAnd: 7) + 1. localPalette := self readPalette: localBitsPerPixel] ifFalse: [localBitsPerPixel := bitsPerPixel. localPalette := palette]. outCount := remainBitCount := pass := xpos := ypos := 0. rowByteSize := (width + 3) // 4 * 4. bufStream := ReadStream on: ByteArray new. outCodes := ByteArray new: 4097. bitMask := (1 bitShift: localBitsPerPixel) - 1. prefixTable := Array new: 4096. suffixTable := Array new: 4096. initCodeSize := ioStream next. self setParameters: initCodeSize. bitsPerPixel > 8 ifTrue: [^self formatError: #BadDepthGIF << #dialogs >> 'never heard of a GIF that deep']. bytes := ByteArray new: rowByteSize * height. [(code := self nextBits) = eoiCode] whileFalse: [code = clearCode ifTrue: [self setParameters: initCodeSize. curCode := oldCode := code := self nextBits. finChar := curCode bitAnd: bitMask. xpos = 0 ifTrue: [ypos < height ifTrue: [bytes at: ypos * rowByteSize + xpos + 1 put: finChar]] ifFalse: [bytes at: ypos * rowByteSize + xpos + 1 put: finChar]. self updatePixelPosition] ifFalse: [curCode := inCode := code. curCode >= freeCode ifTrue: [curCode := oldCode. outCodes at: (outCount := outCount + 1) put: finChar]. [curCode > bitMask] whileTrue: [outCount > 4096 ifTrue: [^self formatError: #corruptGIFFileOutCount << #dialogs >> 'corrupt GIF file (OutCount)']. outCodes at: (outCount := outCount + 1) put: (suffixTable at: curCode + 1). curCode := prefixTable at: curCode + 1]. finChar := curCode bitAnd: bitMask. outCodes at: (outCount := outCount + 1) put: finChar. outCount to: 1 by: -1 do: [:index | ypos < height ifTrue: [bytes at: ypos * rowByteSize + xpos + 1 put: (outCodes at: index)]. self updatePixelPosition]. outCount := 0. prefixTable at: freeCode + 1 put: oldCode. suffixTable at: freeCode + 1 put: finChar. oldCode := inCode. freeCode := freeCode + 1. self checkCodeSize]]. prefixTable := suffixTable := nil. ^Image extent: width @ height depth: 8 palette: localPalette usingBits: bytes
readBody "Read the GIF blocks. Modified to return a form. " [ioStream atEnd] whileFalse: [| block | block := ioStream next. block = Terminator ifTrue: [^image]. block = ImageSeparator ifTrue: [image isNil ifTrue: [image := self readBitData] ifFalse: [self skipBitData]] ifFalse: [| extensionType | block = Extension ifFalse: [^image]. extensionType := ioStream next. extensionType = 249 ifTrue: [ioStream next = 4 ifFalse: [^image]. ioStream skip: 3. transparentIndex := ioStream next. ioStream next = 0 ifFalse: [^image]] ifFalse: [| blocksize | [(blocksize := ioStream next) > 0] whileTrue: [ioStream skip: blocksize]]]]
readHeader | is89 byte hasColorMap | (self hasMagicNumber: 'GIF87a' asByteArray) ifTrue: [is89 := false] ifFalse: [(self hasMagicNumber: 'GIF89a' asByteArray) ifTrue: [is89 := true] ifFalse: [^self formatError: #NotGIFFile << #dialogs >> 'This does not appear to be a GIF file']]. ioStream skip: 4. byte := ioStream next. hasColorMap := (byte bitAnd: 16r80) ~= 0. bitsPerPixel := (byte bitAnd: 7) + 1. byte := ioStream next. ioStream next isZero | is89 ifFalse: [^self formatError: #CorruptGIFFile << #dialogs >> 'corrupt GIF file (screen descriptor)']. palette := hasColorMap ifTrue: [self readPalette: bitsPerPixel] ifFalse: [Screen default colorPalette]
setParameters: initCodeSize clearCode := 1 bitShift: initCodeSize. eoiCode := clearCode + 1. freeCode := clearCode + 2. codeSize := initCodeSize + 1. maxCode := (1 bitShift: codeSize) - 1
updatePixelPosition "Answer nothing of value" (xpos := xpos + 1) >= width ifFalse: [^self]. xpos := 0. interlace ifFalse: [^ypos := ypos + 1]. pass = 0 ifTrue: [^(ypos := ypos + 8) >= height ifTrue: [pass := pass + 1. ypos := 4]]. pass = 1 ifTrue: [^(ypos := ypos + 8) >= height ifTrue: [pass := pass + 1. ypos := 2]]. pass = 2 ifTrue: [^(ypos := ypos + 4) >= height ifTrue: [pass := pass + 1. ypos := 1]]. pass = 3 ifTrue: [^ypos := ypos + 2]. ^self formatError: (#ImageIncompleteOrPartiallyCorrupted << #dialogs >> 'Image incomplete or partially corrupted. Too many interlace passes')
</methods> <methods> Graphics.GIFImageReader <category>private-reading</category>
fillBuffer | packSize | packSize := ioStream next. bufStream := ReadStream on: (ioStream next: packSize)
hasMagicNumber: aByteArray | position | position := ioStream position. ((ioStream size - position) >= aByteArray size and: [(ioStream next: aByteArray size) = aByteArray]) ifTrue: [^true]. ioStream position: position. ^false
nextBits | integer readBitCount shiftCount byte | integer := 0. shiftCount := remainBitCount = 0 ifTrue: [readBitCount := 8. 0] ifFalse: [readBitCount := remainBitCount. remainBitCount - 8]. [readBitCount < codeSize] whileTrue: [byte := self nextByte. byte isNil ifTrue: [^eoiCode]. integer := integer + (byte bitShift: shiftCount). shiftCount := shiftCount + 8. readBitCount := readBitCount + 8]. byte := (remainBitCount := readBitCount - codeSize) = 0 ifTrue: [self nextByte] ifFalse: [self peekByte]. byte isNil ifTrue: [^eoiCode]. ^(integer + (byte bitShift: shiftCount)) bitAnd: maxCode
nextByte bufStream atEnd ifTrue: [ioStream atEnd ifTrue: [^nil]. self fillBuffer]. ^bufStream next
peekByte bufStream atEnd ifTrue: [ioStream atEnd ifTrue: [^nil]. self fillBuffer]. ^bufStream peek
readPalette: bitsToPixel | colors numberOfPixels | numberOfPixels := 1 bitShift: bitsToPixel. colors := OrderedCollection new: numberOfPixels. numberOfPixels timesRepeat: [colors add: (ColorValue red: ioStream next green: ioStream next blue: ioStream next range: 255)]. ^MappedPalette withColors: colors
readWord ^ioStream next + (ioStream next bitShift: 8)
skipBitData | misc blocksize | ioStream skip: 8. misc := ioStream next. (misc bitAnd: 16r80) = 0 ifFalse: [(1 bitShift: (misc bitAnd: 7) + 1) timesRepeat: [ioStream skip: 3]]. ioStream next. [(blocksize := ioStream next) > 0] whileTrue: [ioStream skip: blocksize]
</methods> <methods> Graphics.GIFImageReader <category>attributes</category>
format ^'GIF'
</methods> <methods> Graphics.GIFImageReader <category>accessing</category>
mask "Answer a 1-bit image defining the opaque area of the current image." | mask point | mask := Image extent: image extent depth: 1 palette: CoveragePalette monoMaskPalette. point := 0@0. image pixelsDo: [:x :y | point x: x; y: y. mask atPoint: point put: ((image atPoint: point) = transparentIndex ifTrue: [0] ifFalse: [1])]. ^mask
</methods> <methods> Graphics.GIFImageReader <category>initialize-release</category>
readImage "Read in the next GIF image from the stream. Read it all into memory first for speed." self readHeader. image := self readBody. ioStream close. image isNil ifTrue: [^self formatError: (#corruptGIFFile << #dialogs >> 'corrupt GIF file')].
</methods> <methods> Graphics.GIFImageReader class <category>private</category>
canRead: imageStream | result | imageStream reset. result := (imageStream next: 3) = #[16r47 16r49 16r46]. " the string 'GIF'" imageStream reset. ^result
</methods> <methods> Graphics.GIFImageReader class <category>class initialization</category>
initialize "GIFImageReader initialize" ImageSeparator := $, asInteger. Extension := $! asInteger. Terminator := $; asInteger.
</methods> <methods> Graphics.PNGInflateStream <category>private</category>
checkHeader "The first 16 bits of the stream are header information. Currently, the receiver can only support a compression method of 8, window size of 32K and the absence of a preset dictionary. " |firstByte secondByte| firstByte := sourceStream next. (firstByte bitAnd: 16r08) ~= 16r08 ifTrue: [self error: #OnlyCompressionEight << #dialogs >> 'Only compression method of 8 is supported']. (firstByte bitShift: -4) + 8 > 15 ifTrue: [self error: #InvalidWindowSize << #dialogs >> 'Invalid LZ77 compression window size']. secondByte := sourceStream next. (firstByte bitShift: 8) + secondByte \\ 31 ~= 0 ifTrue: [self error: #InvalidPNGCompressionHeader << #dialogs >> 'Invalid PNG compression header']. (secondByte anyMask: 16r20) ifTrue: [self error: #PresetDictionaryNotSupported << #dialogs >> 'Preset dictionary is not supported']
</methods> <methods> Graphics.XBMImageReader <category>attributes</category>
format "Answer a string naming the format used to store the image." ^(#XMonochromeBitmapXBM << #dialogs >> 'X Monochrome Bitmap (XBM)') asString
</methods> <methods> Graphics.XBMImageReader <category>private</category>
parseByteValue "skip over separators and return next bytevalue parsed as a C language number: 0ddd is an octal digit. 0xddd is a hex digit. ddd is decimal." | source mybase | ioStream skipSeparators. [',};' includes: ioStream peek] whileTrue: [ioStream next]. source := ReadWriteStream on: String new. [ioStream atEnd or: [ioStream peek isSeparator or: [',};' includes: ioStream peek]]] whileFalse: [source nextPut: ioStream next asUppercase]. ioStream atEnd ifTrue: [^nil]. mybase := 10. source reset. source contents isEmpty ifTrue: [^nil]. source peek = $0 ifTrue: [mybase := 8. source next. source peek = $X ifTrue: [mybase := 16. source next]]. ^Integer readFrom: source radix: mybase
readHeader "Set width and height, and position stream at start of bytes" | number setwidth setheight fieldName stringStream | setwidth := setheight := false. [ioStream atEnd or: [setwidth and: [setheight]]] whileFalse: [ioStream skipSeparators. (ioStream skipToAll: '#define ') isNil ifTrue: [^false]. (ioStream skipThrough: $_) isNil ifTrue: [^false]. stringStream := String new writeStream. [ioStream atEnd or: [ioStream peek isSeparator]] whileFalse: [stringStream nextPut: ioStream next]. fieldName := stringStream contents. fieldName = 'width' ifTrue: [ioStream skipSeparators. number := Integer readFrom: ioStream. number > 0 ifTrue: [setwidth := true]. width := number]. fieldName = 'height' ifTrue: [ioStream skipSeparators. number := Integer readFrom: ioStream. number > 0 ifTrue: [setheight := true]. height := number]]. setwidth & setheight ifFalse: [^false]. ^ioStream skipThrough: ${
</methods> <methods> Graphics.XBMImageReader <category>initialize-release</category>
readImage | chunks packedRowCounter inNumber packedRowSize rowCount | ioStream reset. ioStream text. self readHeader. image := Image extent: width @ height depth: 1 palette: MappedPalette whiteBlack. packedRowCounter := rowCount := 0. packedRowSize := image packedRowSize. chunks := Array new: packedRowSize. bytesPerRow := (width + 7) // 8. [rowCount = height] whileFalse: [(inNumber := self parseByteValue) notNil ifTrue: [packedRowCounter := packedRowCounter + 1. chunks at: packedRowCounter put: (Flipbits at: inNumber + 1). packedRowCounter = bytesPerRow ifTrue: [packedRowCounter + 1 to: packedRowSize do: [:index | chunks at: index put: 0]. packedRowCounter := packedRowSize]. packedRowCounter = packedRowSize ifTrue: [image packedRowAt: rowCount putAll: chunks. packedRowCounter := 0. rowCount := rowCount + 1]]. ioStream atEnd ifTrue: [^nil]]
</methods> <methods> Graphics.XBMImageReader class <category>private</category>
canRead: imageStream | result | imageStream reset. result := (imageStream next: 7) = #[16r23 16r64 16r65 16r66 16r69 16r6E 16r65]. " the string '#define' " imageStream reset. ^result
</methods> <methods> Graphics.XBMImageReader class <category>class initialization</category>
initialize "XBMImageReader initialize" | flippedByte | Flipbits := (0 to: 255) collect: [:each | flippedByte := 0. 0 to: 7 do: [:index | flippedByte := flippedByte bitOr: (((each bitShift: index negated) bitAnd: 1) bitShift: (7 - index))]. flippedByte]
</methods> <methods> Graphics.JPEGHuffmanTable <category>accessing</category>
bits: anObject bits := anObject
lookaheadBits ^lookaheadBits
lookaheadSymbol ^lookaheadSymbol
maxcode ^maxcode
values: anObject values := anObject
</methods> <methods> Graphics.JPEGHuffmanTable <category>computation</category>
makeDerivedTables | huffSize huffCode code si index lookbits | mincode := Array new: 16. maxcode := Array new: 17. valptr := Array new: 17. huffSize := OrderedCollection new. 1 to: 16 do: [:l | 1 to: (bits at: l) do: [:i | huffSize add: l]]. huffSize add: 0. code := 0. huffCode := Array new: huffSize size. si := huffSize at: 1. index := 1. [(huffSize at: index) ~= 0] whileTrue: [[(huffSize at: index) = si] whileTrue: [huffCode at: index put: code. index := index + 1. code := code + 1]. code := code bitShift: 1. si := si + 1]. index := 1. 1 to: 16 do: [:l | (bits at: l) ~= 0 ifTrue: [valptr at: l put: index. mincode at: l put: (huffCode at: index). index := index + (bits at: l). maxcode at: l put: (huffCode at: index-1)] ifFalse: [maxcode at: l put: -1]]. maxcode at: 17 put: 16rFFFFF. lookaheadBits := (Array new: (1 bitShift: Lookahead)) atAllPut: 0. lookaheadSymbol := Array new: (1 bitShift: Lookahead). index := 1. 1 to: Lookahead do: [:l | 1 to: (bits at: l) do: [:i | lookbits := ((huffCode at: index) bitShift: (Lookahead - l)) + 1. ((1 bitShift: (Lookahead - l)) to: 1 by: -1) do: [:ctr | lookaheadBits at: lookbits put: l. lookaheadSymbol at: lookbits put: (values at: index). lookbits := lookbits + 1]. index := index + 1]]
valueForCode: code length: length ^ values at: ((valptr at: length) + code - (mincode at: length))
</methods> <methods> Graphics.JPEGHuffmanTable class <category>initialization</category>
initialize "JPEGHuffmanTable initialize" "Lookahead := 8." BitBufferSize := 16
</methods> <methods> Graphics.JPEGHuffmanTable class <category>constants</category>
lookahead ^Lookahead
</methods> <methods> Graphics.BMPImageReader <category>attributes</category>
attributeKeysAndValuesDo: aBlock super attributeKeysAndValuesDo: aBlock. aBlock value: #compression value: self compression. aBlock value: #planes value: planes. aBlock value: #numberOfColors value: numColors. aBlock value: #numberOfImportantColors value: numImportantColors
compression compression = BI_RGB ifTrue: [^'BMP_RGB']. compression = BI_RLE4 ifTrue: [^'BMP_RLE4']. compression = BI_RLE8 ifTrue: [^'BMP_RLE8']. compression = BI_BITFIELDS ifTrue: [^'BMP_BITFIELDS']. ^(#unknown << #dialogs >> 'unknown') asString
format ^(#WindowsDIBBMP << #dialogs >> 'Windows DIB (BMP)') asString
resolution ^(hRes * 0.0254) @ (vRes * 0.0254)
</methods> <methods> Graphics.BMPImageReader <category>private-image data</category>
deltaPixelPositionByX: xOffset y: yOffset "Move the data position by the specified unsigned pixel offsets. This method assumes that bitsPerPixel is either four or eight." | verticalBytes horizontalBytes | "vertical offset" verticalBytes := yOffset * bytesPerRow. bottomToTop ifTrue: [dataPosition := dataPosition - verticalBytes. rowEnd := rowEnd - verticalBytes. nextRow := nextRow - verticalBytes] ifFalse: [dataPosition := dataPosition + verticalBytes. rowEnd := rowEnd + verticalBytes. nextRow := nextRow + verticalBytes]. "horizontal offset" "assume that the horizontal offset shouldn't move past the end of the row" bitsPerPixel = 8 ifTrue: [horizontalBytes := xOffset] ifFalse: [horizontalBytes := xOffset // 2. (xOffset odd and: [inHighNibble := inHighNibble not]) ifTrue: [horizontalBytes := horizontalBytes + 1]]. dataPosition := dataPosition + horizontalBytes. partialByte := 0 "assume that we always move to new (zero) pixels"
depth4CopyNext: pixelCount "Copy the next pixelCount pixels from the input stream to the image data. Only valid for four-bit images." inHighNibble ifTrue: [pixelCount // 2 timesRepeat: [imageData at: dataPosition put: ioStream next. dataPosition := dataPosition + 1]. pixelCount odd ifTrue: [partialByte := ioStream bitAnd: 16rF0. imageData at: dataPosition put: partialByte. inHighNibble := false]] ifFalse: [pixelCount // 2 timesRepeat: [| byte | byte := ioStream next. imageData at: dataPosition put: (partialByte + (byte bitShift: -4)). dataPosition := dataPosition + 1. partialByte := (byte bitAnd: 16r0F) bitShift: 4]. pixelCount odd ifTrue: [partialByte := partialByte + (ioStream next bitShift: 4). inHighNibble := true]. imageData at: dataPosition put: partialByte. inHighNibble ifTrue: [dataPosition := dataPosition + 1. partialByte := 0]]
depth4StoreNext: pixelCount with: twoNibbles "Store the next pixelCount pixels, alternating between the high and low nibbles of twoNibbles. Only valid for four-bit images." | nibbles count | nibbles := twoNibbles. count := pixelCount. inHighNibble ifFalse: [imageData at: dataPosition put: partialByte + (nibbles bitShift: -4). nibbles := (nibbles bitShift: -4) + ((nibbles bitAnd: 16r0F) bitShift: 4). count := count - 1. inHighNibble := true. partialByte := 0. dataPosition := dataPosition + 1]. count // 2 timesRepeat: [imageData at: dataPosition put: nibbles. dataPosition := dataPosition + 1]. count odd ifTrue: [partialByte := nibbles bitAnd: 16rF0. imageData at: dataPosition put: partialByte. inHighNibble := false]
depth8CopyNext: pixelCount "Copy the next pixelCount pixels from the input stream to the image data. Only valid for eight-bit images." pixelCount timesRepeat: [imageData at: dataPosition put: ioStream next. dataPosition := dataPosition + 1]
depth8StoreNext: pixelCount with: pixel "Store the next pixelCount pixels. Only valid for eight-bit images." pixelCount timesRepeat: [imageData at: dataPosition put: pixel. dataPosition := dataPosition + 1]
resetDataPosition "Reset the data position to the beginning of the bitmap." bottomToTop ifTrue: [dataPosition := height - 1 * bytesPerRow + 1. nextRow := dataPosition - bytesPerRow] ifFalse: [dataPosition := 1. nextRow := dataPosition + bytesPerRow]. rowEnd := dataPosition + rowEndOffset. inHighNibble := true. partialByte := 0
setDataPositionToNextRow "Set the data position to the beginning of the next row." dataPosition := nextRow. rowEnd := dataPosition + rowEndOffset. inHighNibble := true. partialByte := 0. nextRow := bottomToTop ifTrue: [nextRow - bytesPerRow] ifFalse: [nextRow + bytesPerRow]
</methods> <methods> Graphics.BMPImageReader <category>initialize-release</category>
initializeImage "Allocate the image." image := Image extent: width@height depth: bitsPerPixel bitsPerPixel: bitsPerPixel palette: palette. imageData := image bitsInstVar
readImage self readFileHeader. self readBitmapHeader. self readColormap. self initializeImage. self readImageData
width: w height: h bitsPerPixel: bpp width := w. height := h. bitsPerPixel := bpp. bytesPerRow := (width * bitsPerPixel + 31 bitShift: -5) bitShift: 2. rowEndOffset := (width * bitsPerPixel bitShift: -3) - 1
</methods> <methods> Graphics.BMPImageReader <category>private</category>
readBitmapHeader "Read the bitmap header." | w h bitCount | ioStream position: BitmapHeaderOffset. headerSize := self nextLSBUnsignedLong. win3 := true. win3 := headerSize >= 40. (win3 not and: [headerSize ~= 12 "OS/2 1.2"]) ifTrue: [^self formatError: (#errBMPUnknownFormat << #dialogs >> 'Unknown type of BMP format.')]. win3 ifTrue: [w := self nextLSBLong. h := self nextLSBLong] ifFalse: [w := self nextLSBShort. h := self nextLSBShort]. w := w abs. bottomToTop := true. h < 0 ifTrue: [bottomToTop := false. h := h negated]. planes := self nextLSBUnsignedShort. bitCount := self nextLSBUnsignedShort. self width: w height: h bitsPerPixel: bitCount. win3 ifTrue: [compression := self nextLSBUnsignedLong. compressedImageByteSize := self nextLSBUnsignedLong. hRes := self nextLSBLong. vRes := self nextLSBLong. numColors := self nextLSBUnsignedLong. numImportantColors := self nextLSBUnsignedLong] ifFalse: [compression := BI_RGB. compressedImageByteSize := hRes := vRes := numColors := numImportantColors := 0]. "check if we understand the compression" (compression = BI_RGB or: [compression = BI_RLE4 or: [compression = BI_RLE8 or: [compression = BI_BITFIELDS]]]) ifFalse: [^self formatError: ((#errUnknownCompression << #dialogs >> 'Unknown compression type ( <1p> ).' ) expandMacrosWith: compression)]
readColormap "Read the colormap." bitsPerPixel = 24 ifTrue: [palette := BMPDepth24Palette. ^self]. ioStream position: BitmapHeaderOffset + headerSize. compression = BI_BITFIELDS ifTrue: [self readFixedPalette] ifFalse: [self readMappedPalette]
readFileHeader "Read the file header." ioStream reset. (ioStream next: 2) = #[16r42 16r4D] " the string 'BM'" ifFalse: [^self formatError: (#errNotBMP << #dialogs >> 'Not in BMP format.')]. fileSize := self nextLSBUnsignedLong. ioStream position: 10. imageByteOffset := self nextLSBUnsignedLong
readFixedPalette "Read a fixed palette, stored in three consecutive DWORDs." | redBitMask greenBitMask blueBitMask redShift greenShift blueShift | redBitMask := self nextLSBUnsignedLong. greenBitMask := self nextLSBUnsignedLong. blueBitMask := self nextLSBUnsignedLong. (redBitMask = 0 or: [greenBitMask = 0 or: [blueBitMask = 0]]) ifTrue: [^self formatError: (#errBMPMask << #dialogs >> 'Invalid BMP bitfield mask.')]. redShift := redBitMask lowBit -1. greenShift := greenBitMask lowBit - 1. blueShift := blueBitMask lowBit - 1. palette := FixedPalette redShift: redShift redMask: (redBitMask bitShift: redShift negated) greenShift: greenShift greenMask: (greenBitMask bitShift: greenShift negated) blueShift: blueShift blueMask: (blueBitMask bitShift: blueShift negated)
readImageData "Read the image data." ioStream position: imageByteOffset. self resetDataPosition. [compression = BI_RLE8 ifTrue: [^self readRLE8ImageData]. compression = BI_RLE4 ifTrue: [^self readRLE4ImageData]. (compression = BI_RGB or: [compression = BI_BITFIELDS]) ifTrue: [^self readUncompressedImageData]] on: Stream endOfStreamSignal do: [:ex | ex retryUsing: [self formatError: (#errImageEnd << #dialogs >> 'Image data ended prematurely.') ]]. self formatError: ((#errUnknownCompression << #dialogs >> 'Unknown compression type ( <1p> ).' ) expandMacrosWith: compression)
readMappedPalette "Read a mapped palette." | paletteSize colors | paletteSize := 1 bitShift: bitsPerPixel. (win3 and: [numColors > 0]) ifTrue: [paletteSize := numColors]. colors := (1 to: paletteSize) collect: [:index | | red green blue | blue := ioStream next. green := ioStream next. red := ioStream next. win3 ifTrue: [ioStream skip: 1]. ColorValue red: red green: green blue: blue range: 255]. palette := MappedPalette withColors: colors
readRLE4ImageData "Read the image data." [| byte1 byte2 | byte1 := ioStream next. byte2 := ioStream next. byte1 > 0 ifTrue: [self depth4StoreNext: byte1 with: byte2] ifFalse: [byte2 = 1 "end of bitmap" ifTrue: [^self]. byte2 = 0 "end of line" ifTrue: [self setDataPositionToNextRow] ifFalse: [byte2 = 2 "delta" ifTrue: [self deltaPixelPositionByX: ioStream next y: ioStream next] ifFalse: ["else: byte2 > 2" self depth4CopyNext: byte2. ioStream skip: (4 - byte2 \\ 4 // 2)]]]] repeat
readRLE8ImageData "Read the image data." [| byte1 byte2 | byte1 := ioStream next. byte2 := ioStream next. byte1 > 0 ifTrue: [self depth8StoreNext: byte1 with: byte2] ifFalse: [byte2 = 1 "end of bitmap" ifTrue: [^self]. byte2 = 0 "end of line" ifTrue: [self setDataPositionToNextRow] ifFalse: [byte2 = 2 "delta" ifTrue: [self deltaPixelPositionByX: ioStream next y: ioStream next] ifFalse: ["else: byte2 > 2" self depth8CopyNext: byte2. byte2 odd ifTrue: [ioStream skip: 1]]]]] repeat
readUncompressedDepth16ImageData "Read the image data." height timesRepeat: [0 to: bytesPerRow - 1 by: 2 do: [:i | | byte1 byte2 | byte1 := ioStream next. byte2 := ioStream next. imageData at: dataPosition + i put: byte2; at: dataPosition + i + 1 put: byte1]. self setDataPositionToNextRow]
readUncompressedDepth24ImageData "Read the image data." | dataBytesPerRow skipCount | dataBytesPerRow := 3 * width. skipCount := bytesPerRow - dataBytesPerRow. height timesRepeat: [0 to: dataBytesPerRow - 1 by: 3 do: [:i | | byte1 byte2 byte3 | byte1 := ioStream next. byte2 := ioStream next. byte3 := ioStream next. imageData at: dataPosition + i put: byte3; at: dataPosition + i + 1 put: byte2; at: dataPosition + i + 2 put: byte1]. ioStream skip: skipCount. self setDataPositionToNextRow]
readUncompressedDepth32ImageData "Read the image data." | dataBytesPerRow skipCount | dataBytesPerRow := 4 * width. skipCount := bytesPerRow - dataBytesPerRow. height timesRepeat: [0 to: dataBytesPerRow - 1 by: 4 do: [:i | | byte1 byte2 byte3 byte4 | byte1 := ioStream next. byte2 := ioStream next. byte3 := ioStream next. byte4 := ioStream next. imageData at: dataPosition + i put: byte4; at: dataPosition + i + 1 put: byte3; at: dataPosition + i + 2 put: byte2; at: dataPosition + i + 3 put: byte1]. ioStream skip: skipCount. self setDataPositionToNextRow]
readUncompressedDepthLE8ImageData "Read the image data." height timesRepeat: [0 to: bytesPerRow - 1 do: [:i | imageData at: dataPosition + i put: ioStream next]. self setDataPositionToNextRow]
readUncompressedImageData "Read the image data." (#(1 4 8) includes: bitsPerPixel) ifTrue: [^self readUncompressedDepthLE8ImageData]. bitsPerPixel = 16 ifTrue: [^self readUncompressedDepth16ImageData]. bitsPerPixel = 24 ifTrue: [^self readUncompressedDepth24ImageData]. bitsPerPixel = 32 ifTrue: [^self readUncompressedDepth32ImageData]. self formatError: (#errInvalidBitsPerPixel << #dialogs >> 'Invalid number of bits per pixel.')
</methods> <methods> Graphics.BMPImageReader class <category>private</category>
canRead: imageStream | result | imageStream reset. result := (imageStream next: 2) = #[16r42 16r4D]. " the string 'BM'" imageStream reset. ^result
</methods> <methods> Graphics.BMPImageReader class <category>class initialization</category>
initialize "BMPImageReader initialize." BI_RGB := 0. BI_RLE8 := 1. BI_RLE4 := 2. BI_BITFIELDS := 3. BitmapHeaderOffset := 14. BMPDepth24Palette := FixedPalette redShift: 16 redMask: 16rFF greenShift: 8 greenMask: 16rFF blueShift: 0 blueMask: 16rFF
</methods> <methods> Graphics.JPEGColorComponent <category>accessing</category>
acTableIndex ^acTableIndex
acTableIndex: anInteger acTableIndex := anInteger
dcTableIndex ^dcTableIndex
dcTableIndex: anInteger dcTableIndex := anInteger
heightInBlocks ^heightInBlocks
heightInBlocks: anInteger heightInBlocks := anInteger
id ^id
id: anObject id := anObject
mcuWidth: mw mcuHeight: mh dctSize: ds mcuWidth := mw. mcuHeight := mh. dctSize := ds. hSampleFactor := mcuWidth // widthInBlocks. vSampleFactor := mcuHeight // heightInBlocks
priorDCValue: aNumber priorDCValue := aNumber
qTableIndex ^qTableIndex
qTableIndex: anInteger qTableIndex := anInteger
totalMcuBlocks ^ heightInBlocks * widthInBlocks
updateDCValue: aNumber priorDCValue := priorDCValue + aNumber. ^priorDCValue
widthInBlocks ^widthInBlocks
widthInBlocks: anInteger widthInBlocks := anInteger
</methods> <methods> Graphics.JPEGColorComponent <category>sample streaming</category>
initializeSampleStreamBlocks: aCollection mcuBlocks := aCollection. self resetSampleStream
nextSample | dx dy blockIndex sampleIndex sample | dx := currentX // hSampleFactor. dy := currentY // vSampleFactor. blockIndex := dy // dctSize * widthInBlocks + (dx // dctSize) + 1. sampleIndex := dy \\ dctSize * dctSize + (dx \\ dctSize) + 1. sample := (mcuBlocks at: blockIndex) at: sampleIndex. currentX := currentX + 1. currentX < (mcuWidth * dctSize) ifFalse: [currentX := 0. currentY := currentY + 1]. ^ sample
resetSampleStream currentX := 0. currentY := 0
</methods> <methods> Graphics.JPEGImageReader <category>colorspace conversion</category>
colorConvertFloatYCbCrMCU | ySampleStream crSampleStream cbSampleStream y cb cr red green blue | ySampleStream := currentComponents first. cbSampleStream := currentComponents at: 2. crSampleStream := currentComponents at: 3. ySampleStream resetSampleStream. cbSampleStream resetSampleStream. crSampleStream resetSampleStream. 0 to: mcuImageBuffer height - 1 do: [:row | 0 to: mcuImageBuffer width - 1 do: [:col | y := ySampleStream nextSample. cb := cbSampleStream nextSample - FloatSampleOffset. cr := crSampleStream nextSample - FloatSampleOffset. red := self sampleRangeLimit: y + (1.402 * cr). green := self sampleRangeLimit: y - (0.34414 * cb) - (0.71414 * cr). blue := self sampleRangeLimit: y + (1.772 * cb). mcuImageBuffer atPoint: col @ row put: (red bitShift: 16) + (green bitShift: 8) + blue]]
colorConvertGrayscaleMCU | ySampleStream y | ySampleStream := currentComponents first. ySampleStream resetSampleStream. 0 to: mcuImageBuffer height - 1 do: [:row | 0 to: mcuImageBuffer width - 1 do: [:col | y := ySampleStream nextSample + greenResidual. y := y min: MaxSample. greenResidual := y bitAnd: ditherMask. y := y bitAnd: MaxSample - ditherMask. y := y max: 1. mcuImageBuffer atPoint: col @ row put: (y bitShift: 16) + (y bitShift: 8) + y]]
colorConvertIntYCbCrMCU | ySampleStream crSampleStream cbSampleStream y cb cr red green blue | ySampleStream := currentComponents first. cbSampleStream := currentComponents at: 2. crSampleStream := currentComponents at: 3. ySampleStream resetSampleStream. cbSampleStream resetSampleStream. crSampleStream resetSampleStream. 0 to: mcuImageBuffer height - 1 do: [:row | 0 to: mcuImageBuffer width - 1 do: [:col | y := ySampleStream nextSample. cb := cbSampleStream nextSample - SampleOffset. cr := crSampleStream nextSample - SampleOffset. red := self sampleRangeLimit: y + (FIXn1n40200 * cr bitShift: -16) + redResidual. green := self sampleRangeLimit: y - (FIXn0n34414 * cb bitShift: -16) - (FIXn0n71414 * cr bitShift: -16) + greenResidual. blue := self sampleRangeLimit: y + (FIXn1n77200 * cb bitShift: -16) + blueResidual. redResidual := red bitAnd: ditherMask. greenResidual := green bitAnd: ditherMask. blueResidual := blue bitAnd: ditherMask. red := (red bitAnd: MaxSample - ditherMask) max: 1. green := (green bitAnd: MaxSample - ditherMask) max: 1. blue := (blue bitAnd: MaxSample - ditherMask) max: 1. mcuImageBuffer atPoint: col @ row put: (red bitShift: 16) + (green bitShift: 8) + blue]]
colorConvertMCU ^currentComponents size = 3 ifTrue: [self class useFloatingPoint ifTrue: [self colorConvertFloatYCbCrMCU] ifFalse: [self colorConvertIntYCbCrMCU]] ifFalse: [self colorConvertGrayscaleMCU]
sampleFloatRangeLimit: aNumber ^(aNumber rounded max: 0) min: MaxSample
sampleRangeLimit: aNumber ^(aNumber max: 0) min: MaxSample
</methods> <methods> Graphics.JPEGImageReader <category>dct</category>
dctFloatRangeLimit: value ^value / 8.0 + FloatSampleOffset
idctBlockFloat: anArray component: aColorComponent "Two passes: Pass 1: process columns from input, store into work array Pass 2: process rows from the workspace" | t0 t1 t2 t3 t4 t5 t6 t7 t10 t11 t12 t13 z5 z10 z11 z12 z13 qt ws | qt := self qTable at: aColorComponent qTableIndex. ws := Array new: DCTSize2. 1 to: DCTSize do: [:i | t0 := (anArray at: i) * (qt at: i). t1 := (anArray at: DCTSize * 2 + i) * (qt at: DCTSize * 2 + i). t2 := (anArray at: DCTSize * 4 + i) * (qt at: DCTSize * 4 + i). t3 := (anArray at: DCTSize * 6 + i) * (qt at: DCTSize * 6 + i). t10 := t0 + t2. t11 := t0 - t2. t13 := t1 + t3. t12 := (t1 - t3) * DCTK1 - t13. t0 := t10 + t13. t3 := t10 - t13. t1 := t11 + t12. t2 := t11 - t12. t4 := (anArray at: DCTSize + i) * (qt at: DCTSize + i). t5 := (anArray at: DCTSize * 3 + i) * (qt at: DCTSize * 3 + i). t6 := (anArray at: DCTSize * 5 + i) * (qt at: DCTSize * 5 + i). t7 := (anArray at: DCTSize * 7 + i) * (qt at: DCTSize * 7 + i). z13 := t6 + t5. z10 := t6 - t5. z11 := t4 + t7. z12 := t4 - t7. t7 := z11 + z13. t11 := (z11 - z13) * DCTK1. z5 := (z10 + z12) * DCTK2. t10 := DCTK3 * z12 - z5. t12 := DCTK4 * z10 + z5. t6 := t12 - t7. t5 := t11 - t6. t4 := t10 + t5. ws at: i put: t0 + t7. ws at: DCTSize * 7 + i put: t0 - t7. ws at: DCTSize + i put: t1 + t6. ws at: DCTSize * 6 + i put: t1 - t6. ws at: DCTSize * 2 + i put: t2 + t5. ws at: DCTSize * 5 + i put: t2 - t5. ws at: DCTSize * 4 + i put: t3 + t4. ws at: DCTSize * 3 + i put: t3 - t4]. 0 to: DCTSize2 - DCTSize by: DCTSize do: [:i | t10 := (ws at: i + 1) + (ws at: i + 5). t11 := (ws at: i + 1) - (ws at: i + 5). t13 := (ws at: i + 3) + (ws at: i + 7). t12 := ((ws at: i + 3) - (ws at: i + 7)) * DCTK1 - t13. t0 := t10 + t13. t3 := t10 - t13. t1 := t11 + t12. t2 := t11 - t12. z13 := (ws at: i + 6) + (ws at: i + 4). z10 := (ws at: i + 6) - (ws at: i + 4). z11 := (ws at: i + 2) + (ws at: i + 8). z12 := (ws at: i + 2) - (ws at: i + 8). t7 := z11 + z13. t11 := (z11 - z13) * DCTK1. z5 := (z10 + z12) * DCTK2. t10 := DCTK3 * z12 - z5. t12 := DCTK4 * z10 + z5. t6 := t12 - t7. t5 := t11 - t6. t4 := t10 + t5. anArray at: i + 1 put: (self dctFloatRangeLimit: t0 + t7). anArray at: i + 8 put: (self dctFloatRangeLimit: t0 - t7). anArray at: i + 2 put: (self dctFloatRangeLimit: t1 + t6). anArray at: i + 7 put: (self dctFloatRangeLimit: t1 - t6). anArray at: i + 3 put: (self dctFloatRangeLimit: t2 + t5). anArray at: i + 6 put: (self dctFloatRangeLimit: t2 - t5). anArray at: i + 5 put: (self dctFloatRangeLimit: t3 + t4). anArray at: i + 4 put: (self dctFloatRangeLimit: t3 - t4)]
idctBlockInt: anArray component: aColorComponent "Two passes Pass 1: process columns from anArray, store into work array Pass 2: process rows from work array, store back into anArray" | qt ws anACTerm dcval z1 z2 z3 z4 z5 t0 t1 t2 t3 t10 t11 t12 t13 shift | qt := self qTable at: aColorComponent qTableIndex. ws := Array new: DCTSize2. shift := 1 bitShift: ConstBits - Pass1Bits. 1 to: DCTSize do: [:i | anACTerm := (1 to: DCTSize - 1) detect: [:each | (anArray at: each * DCTSize + i) ~= 0] ifNone: [nil]. anACTerm isNil ifTrue: [dcval := (anArray at: i) * (qt first) bitShift: Pass1Bits. 0 to: DCTSize - 1 do: [:j | ws at: j * DCTSize + i put: dcval]] ifFalse: [z2 := (anArray at: DCTSize * 2 + i) * (qt at: DCTSize * 2 + i). z3 := (anArray at: DCTSize * 6 + i) * (qt at: DCTSize * 6 + i). z1 := (z2 + z3) * FIXn0n541196100. t2 := z1 + (z3 * FIXn1n847759065Negated). t3 := z1 + (z2 * FIXn0n765366865). z2 := (anArray at: i) * (qt at: i). z3 := (anArray at: DCTSize * 4 + i) * (qt at: DCTSize * 4 + i). t0 := z2 + z3 bitShift: ConstBits. t1 := z2 - z3 bitShift: ConstBits. t10 := t0 + t3. t13 := t0 - t3. t11 := t1 + t2. t12 := t1 - t2. t0 := (anArray at: DCTSize * 7 + i) * (qt at: DCTSize * 7 + i). t1 := (anArray at: DCTSize * 5 + i) * (qt at: DCTSize * 5 + i). t2 := (anArray at: DCTSize * 3 + i) * (qt at: DCTSize * 3 + i). t3 := (anArray at: DCTSize + i) * (qt at: DCTSize + i). z1 := t0 + t3. z2 := t1 + t2. z3 := t0 + t2. z4 := t1 + t3. z5 := (z3 + z4) * FIXn1n175875602. t0 := t0 * FIXn0n298631336. t1 := t1 * FIXn2n053119869. t2 := t2 * FIXn3n072711026. t3 := t3 * FIXn1n501321110. z1 := z1 * FIXn0n899976223Negated. z2 := z2 * FIXn2n562915447Negated. z3 := z3 * FIXn1n961570560Negated. z4 := z4 * FIXn0n390180644Negated. z3 := z3 + z5. z4 := z4 + z5. t0 := t0 + z1 + z3. t1 := t1 + z2 + z4. t2 := t2 + z2 + z3. t3 := t3 + z1 + z4. ws at: i put: ((t10 + t3) bitShift: (ConstBits - Pass1Bits) negated). ws at: DCTSize * 7 + i put: (t10 - t3) // shift. ws at: DCTSize * 1 + i put: (t11 + t2) // shift. ws at: DCTSize * 6 + i put: (t11 - t2) // shift. ws at: DCTSize * 2 + i put: (t12 + t1) // shift. ws at: DCTSize * 5 + i put: (t12 - t1) // shift. ws at: DCTSize * 3 + i put: (t13 + t0) // shift. ws at: DCTSize * 4 + i put: (t13 - t0) // shift]]. shift := 1 bitShift: ConstBits + Pass1Bits + 3. 0 to: DCTSize2 - DCTSize by: DCTSize do: [:i | z2 := ws at: i + 3. z3 := ws at: i + 7. z1 := (z2 + z3) * FIXn0n541196100. t2 := z1 + (z3 * FIXn1n847759065Negated). t3 := z1 + (z2 * FIXn0n765366865). t0 := (ws at: i + 1) + (ws at: i + 5) bitShift: ConstBits. t1 := (ws at: i + 1) - (ws at: i + 5) bitShift: ConstBits. t10 := t0 + t3. t13 := t0 - t3. t11 := t1 + t2. t12 := t1 - t2. t0 := ws at: i + 8. t1 := ws at: i + 6. t2 := ws at: i + 4. t3 := ws at: i + 2. z1 := t0 + t3. z2 := t1 + t2. z3 := t0 + t2. z4 := t1 + t3. z5 := (z3 + z4) * FIXn1n175875602. t0 := t0 * FIXn0n298631336. t1 := t1 * FIXn2n053119869. t2 := t2 * FIXn3n072711026. t3 := t3 * FIXn1n501321110. z1 := z1 * FIXn0n899976223Negated. z2 := z2 * FIXn2n562915447Negated. z3 := z3 * FIXn1n961570560Negated. z4 := z4 * FIXn0n390180644Negated. z3 := z3 + z5. z4 := z4 + z5. t0 := t0 + z1 + z3. t1 := t1 + z2 + z4. t2 := t2 + z2 + z3. t3 := t3 + z1 + z4. anArray at: i + 1 put: (self sampleRangeLimit: (t10 + t3) // shift + SampleOffset). anArray at: i + 8 put: (self sampleRangeLimit: (t10 - t3) // shift + SampleOffset). anArray at: i + 2 put: (self sampleRangeLimit: (t11 + t2) // shift + SampleOffset). anArray at: i + 7 put: (self sampleRangeLimit: (t11 - t2) // shift + SampleOffset). anArray at: i + 3 put: (self sampleRangeLimit: (t12 + t1) // shift + SampleOffset). anArray at: i + 6 put: (self sampleRangeLimit: (t12 - t1) // shift + SampleOffset). anArray at: i + 4 put: (self sampleRangeLimit: (t13 + t0) // shift + SampleOffset). anArray at: i + 5 put: (self sampleRangeLimit: (t13 - t0) // shift + SampleOffset)]
idctMCU | component | self class useFloatingPoint ifTrue: [mcuMembership keysAndValuesDo: [:index :each | component := currentComponents at: each. self idctBlockFloat: (mcuSampleBuffer at: index) component: component]] ifFalse: [mcuMembership keysAndValuesDo: [:index :each | component := currentComponents at: each. self idctBlockInt: (mcuSampleBuffer at: index) component: component]]
scaleQuantizationTable: table | index | index := 1. 1 to: DCTSize do: [:row | 1 to: DCTSize do: [:col | | value | value := (table at: index) * (QTableScaleFactor at: row) * (QTableScaleFactor at: col). table at: index put: value rounded. index := index + 1]]. ^table
</methods> <methods> Graphics.JPEGImageReader <category>huffman encoding</category>
decodeBlockInto: anArray component: aColorComponent dcTable: huffmanDC acTable: huffmanAC | byte index zeroCount | byte := self decodeByteWithTable: huffmanDC. byte isZero ifFalse: [byte := self scaleAndSignExtend: (self getBits: byte) inFieldWidth: byte]. byte := aColorComponent updateDCValue: byte. anArray atAllPut: 0. anArray at: 1 put: byte. index := 2. [index <= DCTSize2] whileTrue: [byte := self decodeByteWithTable: huffmanAC. zeroCount := byte bitShift: -4. byte := byte bitAnd: 16r0F. byte isZero ifTrue: [zeroCount = 15 ifTrue: [index := index + zeroCount] ifFalse: [^self]] ifFalse: [index := index + zeroCount. byte := self scaleAndSignExtend: (self getBits: byte) inFieldWidth: byte. anArray at: (JPEGNaturalOrder at: index) put: byte]. index := index + 1]
decodeByteWithTable: aHuffmanTable | look newBits length code | look := self peekBits: lookahead. (look >= 0 and: [(newBits := aHuffmanTable lookaheadBits at: look + 1) ~= 0]) ifTrue: [self getBits: newBits. ^aHuffmanTable lookaheadSymbol at: look + 1]. length := 1. code := self getBits: length. [code > (aHuffmanTable maxcode at: length)] whileTrue: [code := (code bitShift: 1) + (self getBits: 1). length := length + 1]. length > 16 ifTrue: [self formatError: (#ImageCorruptBadEncoding << #dialogs >> 'Image incomplete or partially corrupted. Bad encoding value in bit stream')]. ^aHuffmanTable valueForCode: code length: length
decodeMCU | component | (restartInterval ~= 0 and: [restartsToGo = 0]) ifTrue: [self processRestart]. mcuMembership keysAndValuesDo: [:index :each | component := currentComponents at: each. self decodeBlockInto: (mcuSampleBuffer at: index) component: component dcTable: (hDCTable at: component dcTableIndex) acTable: (hACTable at: component acTableIndex)]. restartsToGo := restartsToGo - 1
fillBuffer | byte | [bitsInBuffer > 16] whileFalse: [byte := ioStream next. (byte = 16rFF and: [(ioStream peekFor: 0) not]) ifTrue: [ioStream skip: -1. ^0]. bitBuffer := (bitBuffer bitShift: 8) + byte. bitsInBuffer := bitsInBuffer + 8]. ^bitsInBuffer
getBits: requestedBits | value | requestedBits > bitsInBuffer ifTrue: [self fillBuffer. requestedBits > bitsInBuffer ifTrue: [self formatError: (#ImageCorrupt << #dialogs >> 'Image is incomplete or partially corrupted. Unable to correct.')]]. value := bitBuffer bitShift: (bitsInBuffer - requestedBits) negated. bitBuffer := bitBuffer bitAnd: (1 bitShift: (bitsInBuffer - requestedBits)) - 1. bitsInBuffer := bitsInBuffer - requestedBits. ^value
peekBits: requestedBits requestedBits > bitsInBuffer ifTrue: [self fillBuffer. requestedBits > bitsInBuffer ifTrue: [^ -1]]. ^bitBuffer bitShift: (bitsInBuffer - requestedBits) negated
processRestart self resetBitBuffer. self parseNextMarker. currentComponents do: [:each | each priorDCValue: 0]. restartsToGo := restartInterval
scaleAndSignExtend: aNumber inFieldWidth: widthNumber ^aNumber < (1 bitShift: (widthNumber - 1)) ifTrue: [aNumber + (1 bitShift: widthNumber) negated + 1] ifFalse: [aNumber]
</methods> <methods> Graphics.JPEGImageReader <category>attributes</category>
format "Answer a string naming the format used to store the image." ^'JPEG'
resolution "Answer a point indicating the horizontal and vertical resolution of the image in pixels per inch" ^xDensity @ yDensity
</methods> <methods> Graphics.JPEGImageReader <category>private</category>
hACTable hACTable isNil ifTrue: [hACTable := Array new: HuffmanTableSize]. ^hACTable
hDCTable hDCTable isNil ifTrue: [hDCTable := Array new: HuffmanTableSize]. ^hDCTable
newImageWithExtent: extent ^Image extent: extent depth: 32 palette: self class defaultPalette
qTable qTable isNil ifTrue: [qTable := Array new: QuantizationTableSize]. ^qTable
</methods> <methods> Graphics.JPEGImageReader <category>marker parsing</category>
initialSOSSetup mcuWidth := components inject: 0 into: [:sum :each | each widthInBlocks max: sum]. mcuHeight := components inject: 0 into: [:sum :each | each heightInBlocks max: sum]. components do: [:each | each mcuWidth: mcuWidth mcuHeight: mcuHeight dctSize: DCTSize]. hACTable , hDCTable do: [:each | each notNil ifTrue: [each makeDerivedTables]]. self resetBitBuffer. lookahead := JPEGHuffmanTable lookahead
okToIgnoreMarker: aMarker "Ok to ignore Unhandled APPn markers, DNL marker or COM marker" ^(16rE0 to: 16rEF) , #(16r99 16rDC 16rFE) includes: aMarker
parseAPPn | length buffer thumbnailLength markerStart | markerStart := ioStream position. length := self nextWord. buffer := ioStream next: 4. buffer asString = 'JFIF' ifFalse: [ioStream next: length - 6. ^self]. ioStream skip: 1. majorVersion := ioStream next. minorVersion := ioStream next. densityUnit := ioStream next. xDensity := self nextWord. yDensity := self nextWord. thumbnailLength := ioStream next * ioStream next * 3. length := length - (ioStream position - markerStart). length = thumbnailLength ifFalse: [self formatError: (#ImageCorruptAPP0 << #dialogs >> 'Image incomplete or partially corrupted. APP0 thumbnail length is incorrect.')]. ioStream skip: length
parseComment | length | length := self nextWord - 2. length > 0 ifTrue: [comment := (ioStream next: length) asByteString]
parseDecoderRestartInterval self nextWord = 4 ifFalse: [self formatError: (#ImageCorruptDRI << #dialogs >> 'Image incomplete or partially corrupted. DRI length incorrect')]. restartInterval := self nextWord
parseFirstMarker | marker | ioStream next = 16rFF ifFalse: [self formatError: (#ImageCorruptJFIF << #dialogs >> 'Image incomplete or partially corrupted. JFIF marker expected')]. (marker := ioStream next) = 16rD8 ifFalse: [self formatError: (#ImageCorruptSOI << #dialogs >> 'Image incomplete or partially corrupted. SOI marker expected')]. marker = 16rD9 ifTrue: [^self]. self parseStartOfInput
parseHuffmanTable | length markerStart | markerStart := ioStream position. length := self nextWord. [ioStream position - markerStart < length] whileTrue: [| index isACTable bits count hTable | index := ioStream next. isACTable := (index bitAnd: 16r10) ~= 0. index := (index bitAnd: 16rF) + 1. index > HuffmanTableSize ifTrue: [self formatError: (#ImageCorruptTableSize << #dialogs >> 'Image incomplete or partially corrupted. Image has more than <1s> quantization tables' expandMacrosWith: HuffmanTableSize printString)]. bits := ioStream next: 16. count := bits inject: 0 into: [:sum :each | sum + each]. (count > 256 or: [count > (length - (ioStream position - markerStart))]) ifTrue: [self formatError: (#ImageCorruptHuffmanCount << #dialogs >> 'Image incomplete or partially corrupted. Huffman Table count is incorrect')]. hTable := (JPEGHuffmanTable new) bits: bits; values: (ioStream next: count); yourself. (isACTable ifTrue: [self hACTable] ifFalse: [self hDCTable]) at: index put: hTable]
parseNextMarker | byte discardedBytes | discardedBytes := 0. [(byte := ioStream next) = 16rFF] whileFalse: [discardedBytes := discardedBytes + 1]. [[(byte := ioStream next) = 16rFF] whileTrue. byte = 0] whileTrue: [discardedBytes := discardedBytes + 2]. discardedBytes > 0 ifTrue: [Transcript cr; show: (#ImageCorruptExtraData << #dialogs >> 'JPEGImageReader Warning: extraneous data discarded')]. self perform: (JFIFMarkerParser at: byte ifAbsent: [(self okToIgnoreMarker: byte) ifTrue: [#skipMarker] ifFalse: [self formatError: ((#ImageCorruptBadMarker << #dialogs >> 'Incompatible image. Marker <1s> cannot be handled (possible unsupported progressive scan)') expandMacrosWith: (byte printStringRadix: 16))]])
parseNOP "NOP means No Operation"
parseQuantizationTable | length markerStart | markerStart := ioStream position. length := self nextWord. [ioStream position - markerStart < length] whileTrue: [| qTablePosition prec value table | value := ioStream next. prec := (value bitShift: -4) > 0. qTablePosition := (value bitAnd: 16r0F) + 1. qTablePosition > QuantizationTableSize ifTrue: [self formatError: (#ImageCorruptTableSize << #dialogs >> 'Image incomplete or partially corrupted. Image has more than <1s> quantization tables' expandMacrosWith: QuantizationTableSize printString)]. table := Array new: DCTSize2. 1 to: DCTSize2 do: [:i | value := prec ifTrue: [self nextWord] ifFalse: [ioStream next]. table at: (JPEGNaturalOrder at: i) put: value]. self class useFloatingPoint ifTrue: [self scaleQuantizationTable: table]. self qTable at: qTablePosition put: table]
parseStartOfFile | length markerStart componentLength | markerStart := ioStream position. length := self nextWord. dataPrecision := ioStream next. dataPrecision = 8 ifFalse: [self formatError: (#CannotHandle1sBits << #dialogs >> 'Cannot handle <1s>-bit components' expandMacrosWith: dataPrecision printString)]. height := self nextWord. width := self nextWord. componentLength := ioStream next. height = 0 | (width = 0) | (componentLength = 0) ifTrue: [self formatError: #ImageIncompleteOrEmpty << #dialogs >> 'Image incomplete or empty']. length - (ioStream position - markerStart) = (componentLength * 3) ifFalse: [self formatError: #ImageCorruptComponentLength << #dialogs >> 'Image incomplete or partially corrupted. Component length is incorrect']. components := (1 to: componentLength) collect: [:each | |value| (JPEGColorComponent new) id: ioStream next; widthInBlocks: (((value := ioStream next) bitShift: -4) bitAnd: 16r0F); heightInBlocks: (value bitAnd: 16r0F); qTableIndex: ioStream next + 1]
parseStartOfInput restartInterval := 0. densityUnit := 0. xDensity := 1. yDensity := 1
parseStartOfScan | length componentSize | length := self nextWord. componentSize := ioStream next. length ~= (componentSize * 2 + 6) | (componentSize < 1) ifTrue: [self formatError: #ImageCorruptSOS << #dialogs >> 'Image incomplete or partially corrupted. SOS length is incorrect']. currentComponents := (1 to: componentSize) collect: [:each | | componentID value dcNum acNum targetComponent | componentID := ioStream next. value := ioStream next. dcNum := (value bitShift: -4) bitAnd: 16r0F. acNum := value bitAnd: 16r0F. targetComponent := components detect: [:eachComponent | eachComponent id = componentID]. targetComponent dcTableIndex: dcNum + 1; acTableIndex: acNum + 1. targetComponent]. ioStream skip: 3. self initialSOSSetup. self perScanSetup. sosSeen := true
perScanSetup mcusPerRow := (width / (mcuWidth * DCTSize)) ceiling. mcuRowsInScan := (height / (mcuHeight * DCTSize)) ceiling. (#(1 3) includes: currentComponents size) ifFalse: [self formatError: #BadJPEGColorSpace << #dialogs >> 'JPEG color space not recognized']. mcuMembership := OrderedCollection new. currentComponents keysAndValuesDo: [:index :each | each priorDCValue: 0. each totalMcuBlocks timesRepeat: [mcuMembership add: index]]. mcuSampleBuffer := (1 to: mcuMembership size) collect: [:unused | Array new: DCTSize2]. currentComponents keysAndValuesDo: [:index :each | | membership | membership := (1 to: mcuMembership size) select: [:localIndex | index = (mcuMembership at: localIndex)]. each initializeSampleStreamBlocks: (membership collect: [:localIndex | mcuSampleBuffer at: localIndex])]. mcuImageBuffer := self newImageWithExtent: mcuWidth @ mcuHeight * DCTSize. restartsToGo := restartInterval
resetBitBuffer bitBuffer := 0. bitsInBuffer := 0
skipMarker | length | length := self nextWord - 2. ioStream skip: length
</methods> <methods> Graphics.JPEGImageReader <category>stream access</category>
nextWord "Read a 16-bit quantity from the input stream." ^(ioStream next bitShift: 8) + ioStream next
</methods> <methods> Graphics.JPEGImageReader <category>accessing</category>
readImage "Read in the next JPEG image from the stream, assume depth=32" self readImageDitheredToDepth: 32
readImageDitheredToDepth: depth | xStep yStep rectangleLeft rectangleTop | ditherMask := DitherMasks at: depth ifAbsent: [self formatError: #IncompatibleImageDepth << #dialogs >> 'Incompatible Image. Can only dither to display depths']. redResidual := greenResidual := blueResidual := 0. sosSeen := false. self parseFirstMarker. [sosSeen] whileFalse: [self parseNextMarker]. image := self newImageWithExtent: width @ height. xStep := mcuWidth * DCTSize. yStep := mcuHeight * DCTSize. rectangleTop := 0. 1 to: mcuRowsInScan do: [:row | rectangleLeft := 0. 1 to: mcusPerRow do: [:col | | rect | self decodeMCU. self idctMCU. self colorConvertMCU. rect := rectangleLeft @ rectangleTop extent: mcuImageBuffer extent. image copy: rect from: 0 @ 0 in: mcuImageBuffer rule: RasterOp over. rectangleLeft := rectangleLeft + xStep]. rectangleTop := rectangleTop + yStep]
</methods> <methods> Graphics.JPEGImageReader class <category>private</category>
canRead: imageStream | result | imageStream reset. result := (imageStream next: 2) = #[16rFF 16rD8]. " jpg magic " imageStream reset. ^result
</methods> <methods> Graphics.JPEGImageReader class <category>defaults</category>
defaultPalette ^FixedPalette redShift: 16 redMask: 16rFF greenShift: 8 greenMask: 16rFF blueShift: 0 blueMask: 16rFF
</methods> <methods> Graphics.JPEGImageReader class <category>initialization</category>
initialize "JPEGImageReader initialize" "general constants" "The following are now handled by initializers" "DCTSize := 8. MaxSample := (2 raisedToInteger: DCTSize) - 1. SampleOffset := MaxSample // 2. FloatSampleOffset := SampleOffset asFloat. DCTSize2 := DCTSize squared. QuantizationTableSize := 4. HuffmanTableSize := 4." UseFloatingPoint := false. "floating-point Inverse Discrete Cosine Transform (IDCT) constants" "The following are now handled by initializers" "ConstBits := 13. Pass1Bits := 2. DCTK1 := 2 sqrt. DCTK2 := 1.847759065. DCTK3 := 1.082392200. DCTK4 := -2.613125930." "fixed-point Inverse Discrete Cosine Transform (IDCT) constants" "The following are now handled by initializers" "FIXn0n298631336 := 2446. FIXn0n390180644 := 3196. FIXn0n541196100 := 4433. FIXn0n765366865 := 6270. FIXn0n899976223 := 7373. FIXn1n175875602 := 9633. FIXn1n501321110 := 12299. FIXn1n847759065 := 15137. FIXn1n961570560 := 16069. FIXn2n053119869 := 16819. FIXn2n562915447 := 20995. FIXn3n072711026 := 25172." "fixed-point color conversion constants" "The following are now handled by initializers" "FIXn0n34414 := 22554. FIXn0n71414 := 46802. FIXn1n40200 := 91881. FIXn1n77200 := 116130." "reordering table from JPEG zig-zag order" JPEGNaturalOrder := #( 1 2 9 17 10 3 4 11 18 25 33 26 19 12 5 6 13 20 27 34 41 49 42 35 28 21 14 7 8 15 22 29 36 43 50 57 58 51 44 37 30 23 16 24 31 38 45 52 59 60 53 46 39 32 40 47 54 61 62 55 48 56 63 64). "scale factors for the values in the Quantization Tables" QTableScaleFactor := (0 to: DCTSize-1) collect: [:k | k = 0 ifTrue: [1.0] ifFalse: [(k * Float pi / 16) cos * 2 sqrt]]. "dithering masks" (DitherMasks := Dictionary new) add: 0 -> 0; add: 1 -> 127; add: 2 -> 63; add: 4 -> 63; add: 8 -> 31; add: 16 -> 7; add: 24 -> 0; add: 32 -> 0. "dictionary of marker parsers" (JFIFMarkerParser := Dictionary new) add: (16r01 -> #parseNOP); add: (16rC0 -> #parseStartOfFile); add: (16rC4 -> #parseHuffmanTable); addAll: ((16rD0 to: 16rD7) collect: [:m | Association key: m value: #parseNOP]); add: (16rD8 -> #parseStartOfInput); add: (16rD9 -> #parseEndOfInput); add: (16rDA -> #parseStartOfScan); add: (16rDB -> #parseQuantizationTable); add: (16rDD -> #parseDecoderRestartInterval); add: (16rE0 -> #parseAPPn); add: (16rE1 -> #parseAPPn); add: (16rFE -> #parseComment)
</methods> <methods> Graphics.JPEGImageReader class <category>accessing</category>
useFloatingPoint UseFloatingPoint isNil ifTrue: [^false]. ^UseFloatingPoint
useFloatingPoint: aBoolean UseFloatingPoint := aBoolean
</methods> <initialize> Graphics.ImageReader </initialize> <initialize> Graphics.PNGImageReader </initialize> <initialize> Graphics.GIFImageReader </initialize> <initialize> Graphics.XBMImageReader </initialize> <initialize> Graphics.JPEGHuffmanTable </initialize> <initialize> Graphics.BMPImageReader </initialize> <initialize> Graphics.JPEGImageReader </initialize> "Imported Classes:" self error: 'Attempting to file-in parcel imports. Choose terminate or close' <class> <name>Object</name> <environment>Core</environment> <super></super> <private>false</private> none <imports></imports> <category>Kernel-Objects</category> <attributes> <package>Kernel-Objects</package> </attributes> </class> <class> <name>Error</name> <environment>Core</environment> <super>Core.Exception</super> <private>false</private> none <imports></imports> <category>Kernel-Exception Handling</category> <attributes> <package>Kernel-Exception Handling</package> </attributes> </class> <class> <name>InflateStream</name> <environment>OS.ZLib</environment> <super>Core.ReadStream</super> <private>false</private> none inputBuffer inputLimit interface sourceStream superPosition eof <imports></imports> <category>Compression-ZLib</category> <attributes> <package>Compression-ZLib</package> </attributes> </class>