'From Squeak3.7alpha of ''11 September 2003'' [latest update: #5566] on 18 February 2004 at 6:28:53 pm'! "Change Set: FasterBMPWriter Date: 18 February 2004 Author: Yoshiki Ohshima Version: 2 This changeset makes BMP writing faster. For a medium sized Form whose depth is less than 32, you'll get factor of 30 improvement. For a Form whose depth is 32, there is supposed to be a primitive in BMPReadWriterPlugin, even though it doesn't appear that no method uses it. Supposedly, this changeset factors out the case so that it is easier to modify BMPReadWriter>>nextPutImage: to take advantage of the primitive."! Object subclass: #SmalltalkImage instanceVariableNames: '' classVariableNames: 'EndianCache LastImageName LastQuitLogPosition LastStats SourceFileVersionString StartupStamp ' poolDictionaries: '' category: 'System-Support'! !BMPReadWriter methodsFor: 'writing' stamp: 'yo 2/18/2004 17:57'! nextPutImage: aForm | bhSize rowBytes rgb data colorValues depth image ppw scanLineLen | depth := aForm depth. [#(1 4 8 32) includes: depth] whileFalse:[depth := depth + 1 asLargerPowerOfTwo]. image := aForm asFormOfDepth: depth. image unhibernate. bhSize _ 14. "# bytes in file header" biSize _ 40. "info header size in bytes" biWidth := image width. biHeight := image height. biClrUsed _ depth = 32 ifTrue: [0] ifFalse:[1 << depth]. "No. color table entries" bfOffBits _ biSize + bhSize + (4*biClrUsed). rowBytes _ ((depth min: 24) * biWidth + 31 // 32) * 4. biSizeImage _ biHeight * rowBytes. "Write the file header" stream position: 0. stream nextLittleEndianNumber: 2 put: 19778. "bfType = BM" stream nextLittleEndianNumber: 4 put: bfOffBits + biSizeImage. "Entire file size in bytes" stream nextLittleEndianNumber: 4 put: 0. "bfReserved" stream nextLittleEndianNumber: 4 put: bfOffBits. "Offset of bitmap data from start of hdr (and file)" "Write the bitmap info header" stream position: bhSize. stream nextLittleEndianNumber: 4 put: biSize. "info header size in bytes" stream nextLittleEndianNumber: 4 put: image width. "biWidth" stream nextLittleEndianNumber: 4 put: image height. "biHeight" stream nextLittleEndianNumber: 2 put: 1. "biPlanes" stream nextLittleEndianNumber: 2 put: (depth min: 24). "biBitCount" stream nextLittleEndianNumber: 4 put: 0. "biCompression" stream nextLittleEndianNumber: 4 put: biSizeImage. "size of image section in bytes" stream nextLittleEndianNumber: 4 put: 2800. "biXPelsPerMeter" stream nextLittleEndianNumber: 4 put: 2800. "biYPelsPerMeter" stream nextLittleEndianNumber: 4 put: biClrUsed. stream nextLittleEndianNumber: 4 put: 0. "biClrImportant" biClrUsed > 0 ifTrue: [ "write color map; this works for ColorForms, too" colorValues _ image colormapIfNeededForDepth: 32. 1 to: biClrUsed do: [:i | rgb _ colorValues at: i. 0 to: 24 by: 8 do: [:j | stream nextPut: (rgb >> j bitAnd: 16rFF)]]]. depth < 32 ifTrue: [ "depth = 1, 4 or 8." data _ image bits asByteArray. ppw _ 32 // depth. scanLineLen _ biWidth + ppw - 1 // ppw * 4. "# of bytes in line" 1 to: biHeight do: [:i | stream next: scanLineLen putAll: data startingAt: (biHeight-i)*scanLineLen+1. ]. ] ifFalse: [ 1 to: biHeight do:[:i | data _ (image copy: (0@(biHeight-i) extent: biWidth@1)) bits. 1 to: data size do: [:j | stream nextLittleEndianNumber: 3 put: (data at: j)]. 1 to: (data size*3)+3//4*4-(data size*3) do: [:j | stream nextPut: 0 "pad to 32-bits"] ]. ]. stream position = (bfOffBits + biSizeImage) ifFalse: [self error:'Write failure']. stream close.! ! !Bitmap methodsFor: 'as yet unclassified' stamp: 'yo 2/18/2004 18:28'! asByteArray "Faster way to make a byte array from me. copyFromByteArray: makes equal Bitmap." | f bytes hack | f _ Form extent: 4@self size depth: 8 bits: self. bytes _ ByteArray new: self size * 4. hack _ Form new hackBits: bytes. SmalltalkImage current isLittleEndian ifTrue:[hack swapEndianness]. hack copyBits: f boundingBox from: f at: (0@0) clippingBox: hack boundingBox rule: Form over fillColor: nil map: nil. "f displayOn: hack." ^ bytes. ! ! !SmalltalkImage methodsFor: 'endian' stamp: 'yo 2/18/2004 18:24'! calcEndianness | bytes word blt | "What endian-ness is the current hardware? The String '1234' will be stored into a machine word. On BigEndian machines (the Mac), $1 will be the high byte if the word. On LittleEndian machines (the PC), $4 will be the high byte." "SmalltalkImage current endianness" bytes _ ByteArray withAll: #(0 0 0 0). "(1 2 3 4) or (4 3 2 1)" word _ WordArray with: 16r01020304. blt _ (BitBlt toForm: (Form new hackBits: bytes)) sourceForm: (Form new hackBits: word). blt combinationRule: Form over. "store" blt sourceY: 0; destY: 0; height: 1; width: 4. blt sourceX: 0; destX: 0. blt copyBits. "paste the word into the bytes" bytes first = 1 ifTrue: [^ #big]. bytes first = 4 ifTrue: [^ #little]. self error: 'Ted is confused'.! ! !SmalltalkImage methodsFor: 'endian' stamp: 'yo 2/18/2004 18:24'! endianness EndianCache ifNil: [EndianCache _ self calcEndianness]. ^ EndianCache. ! ! !SmalltalkImage class methodsFor: 'class initialization' stamp: 'yo 2/18/2004 18:26'! initialize " self initialize " Smalltalk addToStartUpList: SmalltalkImage. SmalltalkImage startUp. ! ! !SmalltalkImage class methodsFor: 'class initialization' stamp: 'yo 2/18/2004 18:25'! startUp EndianCache _ nil. ! ! SmalltalkImage initialize!