[squeak-dev] The Inbox: Graphics-nice.285.mcz

commits at source.squeak.org commits at source.squeak.org
Wed Jan 1 19:56:18 UTC 2014


Nicolas Cellier uploaded a new version of Graphics to project The Inbox:
http://source.squeak.org/inbox/Graphics-nice.285.mcz

==================== Summary ====================

Name: Graphics-nice.285
Author: nice
Time: 1 January 2014, 8:53:32.416 pm
UUID: 04aee02d-83ae-4b4d-aed9-968a6a7487db
Ancestors: Graphics-nice.284

Change Color implementation from 10 bits per (rgb) component to 8 bits per component.
Several considerations motivate this change:
- no Graphic output is using 10 bits;
- alpha channel is already stored using 8 bits;
- 8 bits matches nowadays most used 32 bits depth Form - thus it's an optimization.
Note that the tolerance for testing Color components has to be increased to a value >= (1/255), I suggest 0.005.

=============== Diff against Graphics-nice.284 ===============

Item was added:
+ (PackageInfo named: 'Graphics') preamble: '"Change color components from 10 to 8 bits"
+ Color allSubInstancesDo:
+ 	[:c |
+ 	| rgb |
+ 	rgb := c instVarNamed: ''rgb''.
+ 	rgb := (rgb bitAnd: 16r3FC00000) >> 2 + (rgb bitAnd: 16rFF000) >> 2 + (rgb bitAnd: 16r3FC) >> 2.
+ 	c instVarNamed: ''rgb'' put: rgb; flushCache].'!

Item was changed:
  ----- Method: Color class>>initialize (in category 'class initialization') -----
  initialize
  	"Color initialize"
  
  	"Details: Externally, the red, green, and blue components of color
  	are floats in the range [0.0..1.0]. Internally, they are represented
  	as integers in the range [0..ComponentMask] packing into a
  	small integer to save space and to allow fast hashing and
  	equality testing.
  
  	For a general description of color representations for computer
  	graphics, including the relationship between the RGB and HSV
  	color models used here, see Chapter 17 of Foley and van Dam,
  	Fundamentals of Interactive Computer Graphics, Addison-Wesley,
  	1982."
  
+ 	ComponentMask := 255.
+ 	HalfComponentMask := 128.  "used to round up in integer calculations"
+ 	ComponentMax := 255.0.  "a Float used to normalize components"
+ 	RedShift := 16.
+ 	GreenShift := 8.
- 	ComponentMask := 1023.
- 	HalfComponentMask := 512.  "used to round up in integer calculations"
- 	ComponentMax := 1023.0.  "a Float used to normalize components"
- 	RedShift := 20.
- 	GreenShift := 10.
  	BlueShift := 0.
  
  	PureRed		 := self r: 1 g: 0 b: 0.
  	PureGreen	 := self r: 0 g: 1 b: 0.
  	PureBlue	 := self r: 0 g: 0 b: 1.
  	PureYellow	 := self r: 1 g: 1 b: 0.
  	PureCyan	 := self r: 0 g: 1 b: 1.
  	PureMagenta := self r: 1 g: 0 b: 1.
  
  	RandomStream := Random new.
  
  	self initializeIndexedColors.
  	self initializeGrayToIndexMap.
  	self initializeNames.
  	self initializeHighLights.
  !

Item was changed:
  ----- Method: Color class>>initializeGrayToIndexMap (in category 'class initialization') -----
  initializeGrayToIndexMap
  	"Build an array of gray values available in the 8-bit colormap. This array is indexed by a gray level between black (1) and white (256) and returns the pixel value for the corresponding gray level."
  	"Note: This method must be called after initializeIndexedColors, since it uses IndexedColors."
  	"Color initializeGrayToIndexMap"
  
  	| grayLevels grayIndices c distToClosest dist indexOfClosest |
  	"record the level and index of each gray in the 8-bit color table"
  	grayLevels := OrderedCollection new.
  	grayIndices := OrderedCollection new.
  	"Note: skip the first entry, which is reserved for transparent"
  	2 to: IndexedColors size do: [:i |
  		c := IndexedColors at: i.
  		c saturation = 0.0 ifTrue: [  "c is a gray"
+ 			grayLevels add: c privateBlue.  "top 8 bits; R, G, and B are the same"
- 			grayLevels add: (c privateBlue) >> 2.  "top 8 bits; R, G, and B are the same"
  			grayIndices add: i - 1]].  "pixel values are zero-based"
  	grayLevels := grayLevels asArray.
  	grayIndices := grayIndices asArray.
  
  	"for each gray level in [0..255], select the closest match"
  	GrayToIndexMap := ByteArray new: 256.
  	0 to: 255 do: [:level |
  		distToClosest := 10000.  "greater than distance to any real gray"
  		1 to: grayLevels size do: [:i |
  			dist := (level - (grayLevels at: i)) abs.
  			dist < distToClosest ifTrue: [
  				distToClosest := dist.
  				indexOfClosest := grayIndices at: i]].
  		GrayToIndexMap at: (level + 1) put: indexOfClosest].
  !

Item was changed:
  ----- Method: Color>>asHTMLColor (in category 'conversions') -----
  asHTMLColor
+ 	^'#' , (rgb printStringBase: 16 length: 6 padded: true)!
- 	| s |
- 	s := '#000000' copy.
- 	s at: 2 put: (Character digitValue: ((rgb bitShift: -6 - RedShift) bitAnd: 15)).
- 	s at: 3 put: (Character digitValue: ((rgb bitShift: -2 - RedShift) bitAnd: 15)).
- 	s at: 4 put: (Character digitValue: ((rgb bitShift: -6 - GreenShift) bitAnd: 15)).
- 	s at: 5 put: (Character digitValue: ((rgb bitShift: -2 - GreenShift) bitAnd: 15)).
- 	s at: 6 put: (Character digitValue: ((rgb bitShift: -6 - BlueShift) bitAnd: 15)).
- 	s at: 7 put: (Character digitValue: ((rgb bitShift: -2 - BlueShift) bitAnd: 15)).
- 	^ s!

Item was changed:
  ----- Method: Color>>closestPixelValue1 (in category 'conversions') -----
  closestPixelValue1
  	"Return the nearest approximation to this color for a monochrome Form."
  
  	"fast special cases"
  	rgb = 0 ifTrue: [^ 1].  "black"
+ 	rgb = 16rFFFFFFF ifTrue: [^ 0].  "white"
- 	rgb = 16r3FFFFFFF ifTrue: [^ 0].  "white"
  
  	self luminance > 0.5
  		ifTrue: [^ 0]  "white"
  		ifFalse: [^ 1].  "black"
  !

Item was changed:
  ----- Method: Color>>closestPixelValue2 (in category 'conversions') -----
  closestPixelValue2
  	"Return the nearest approximation to this color for a 2-bit deep Form."
  
  	| lum |
  	"fast special cases"
  	rgb = 0 ifTrue: [^ 1].  "black"
+ 	rgb = 16rFFFFFFF ifTrue: [^ 2].  "opaque white"
- 	rgb = 16r3FFFFFFF ifTrue: [^ 2].  "opaque white"
  
  	lum := self luminance.
  	lum < 0.2 ifTrue: [^ 1].  "black"
  	lum > 0.6 ifTrue: [^ 2].  "opaque white"
  	^ 3  "50% gray"
  !

Item was changed:
  ----- Method: Color>>closestPixelValue4 (in category 'conversions') -----
  closestPixelValue4
  	"Return the nearest approximation to this color for a 4-bit deep Form."
  
  	| bIndex |
  	"fast special cases"
  	rgb = 0 ifTrue: [^ 1].  "black"
+ 	rgb = 16rFFFFFFF ifTrue: [^ 2].  "opaque white"
- 	rgb = 16r3FFFFFFF ifTrue: [^ 2].  "opaque white"
  
  	rgb = PureRed privateRGB ifTrue: [^ 4].
  	rgb = PureGreen privateRGB ifTrue: [^ 5].
  	rgb = PureBlue privateRGB ifTrue: [^ 6].
  	rgb = PureCyan privateRGB ifTrue: [^ 7].
  	rgb = PureYellow privateRGB ifTrue: [^ 8].
  	rgb = PureMagenta privateRGB ifTrue: [^ 9].
  
  	bIndex := (self luminance * 8.0) rounded.  "bIndex in [0..8]"
  	^ #(
  		1	"black"
  		10	"1/8 gray"
  		11	"2/8 gray"
  		12	"3/8 gray"
  		3	"4/8 gray"
  		13	"5/8 gray"
  		14	"6/8 gray"
  		15	"7/8 gray"
  		2	"opaque white"
  	) at: bIndex + 1.
  !

Item was changed:
  ----- Method: Color>>closestPixelValue8 (in category 'conversions') -----
  closestPixelValue8
  	"Return the nearest approximation to this color for an 8-bit deep Form."
  
  	"fast special cases"
  	rgb = 0 ifTrue: [^ 1].  "black"
+ 	rgb = 16rFFFFFFF ifTrue: [^ 255].  "white"
- 	rgb = 16r3FFFFFFF ifTrue: [^ 255].  "white"
  
  	self saturation < 0.2 ifTrue: [
+ 		^ GrayToIndexMap at: self privateGreen + 1.  "nearest gray"
- 		^ GrayToIndexMap at: (self privateGreen >> 2) + 1.  "nearest gray"
  	] ifFalse: [
  		"compute nearest entry in the color cube"
  		^ 40 +
  		  ((((self privateRed * 5) + HalfComponentMask) // ComponentMask) * 36) +
  		  ((((self privateBlue * 5) + HalfComponentMask) // ComponentMask) * 6) +
  		  (((self privateGreen * 5) + HalfComponentMask) // ComponentMask)].
  !

Item was changed:
  ----- Method: Color>>pixelValueForDepth: (in category 'conversions') -----
  pixelValueForDepth: d
  	"Returns an integer representing the bits that appear in a single pixel of this color in a Form of the given depth. The depth must be one of 1, 2, 4, 8, 16, or 32. Contrast with pixelWordForDepth: and bitPatternForDepth:, which return either a 32-bit word packed with the given pixel value or a multiple-word Bitmap containing a pattern. The inverse is the class message colorFromPixelValue:depth:"
  	"Details: For depths of 8 or less, the result is a colorMap index. For depths of 16 and 32, it is a direct color value with 5 or 8 bits per color component."
  	"Transparency: The pixel value zero is reserved for transparent. For depths greater than 8, black maps to the darkest possible blue."
  
  	| val |
  	d > 8 "most common case"
  		ifTrue: 
  			[d = 32 ifTrue: [
  				"eight bits per component; top 8 bits set to all ones (opaque alpha)"
+ 				^rgb = 0 ifTrue: [16rFF000001] ifFalse: [rgb bitOr: 16rFF000000]].
- 				val := (LargePositiveInteger new: 4)
- 					at: 4 put: 16rFF;
- 					at: 3 put: ((rgb bitShift: -22) bitAnd: 16rFF);
- 					at: 2 put: ((rgb bitShift: -12) bitAnd: 16rFF);
- 					at: 1 put: ((rgb bitShift: -2) bitAnd: 16rFF);
- 					normalize. "normalize is not necessary as long as SmallInteger maxVal highBit < 32, but let's be future proof"
- 				^val < 16rFF000001 ifTrue: [16rFF000001] ifFalse: [val]].
  				
  			d = 16 ifTrue: [
  				"five bits per component; top bits ignored"
+ 				val := (((rgb bitShift: -9) bitAnd: 16r7C00) bitOr:
+ 					 ((rgb bitShift: -6) bitAnd: 16r03E0)) bitOr:
+ 					 ((rgb bitShift: -3) bitAnd: 16r001F).
- 				val := (((rgb bitShift: -15) bitAnd: 16r7C00) bitOr:
- 					 ((rgb bitShift: -10) bitAnd: 16r03E0)) bitOr:
- 					 ((rgb bitShift: -5) bitAnd: 16r001F).
  				^val < 1 ifTrue: [1] ifFalse: [val]].
  
  			d = 12 ifTrue: [  "for indexing a color map with 4 bits per color component"
+ 				val := (((rgb bitShift: -12) bitAnd: 16r0F00) bitOr:
+ 					 ((rgb bitShift: -8) bitAnd: 16r00F0)) bitOr:
+ 					 ((rgb bitShift: -4) bitAnd: 16r000F).
- 				val := (((rgb bitShift: -18) bitAnd: 16r0F00) bitOr:
- 					 ((rgb bitShift: -12) bitAnd: 16r00F0)) bitOr:
- 					 ((rgb bitShift: -6) bitAnd: 16r000F).
  				^val < 1 ifTrue: [1] ifFalse: [val]].
  
  			d = 9 ifTrue: [  "for indexing a color map with 3 bits per color component"
+ 				val := (((rgb bitShift: -15) bitAnd: 16r01C0) bitOr:
+ 					 ((rgb bitShift: -10) bitAnd: 16r0038)) bitOr:
+ 					 ((rgb bitShift: -5) bitAnd: 16r0007).
- 				val := (((rgb bitShift: -21) bitAnd: 16r01C0) bitOr:
- 					 ((rgb bitShift: -14) bitAnd: 16r0038)) bitOr:
- 					 ((rgb bitShift: -7) bitAnd: 16r0007).
  				^val < 1 ifTrue: [1] ifFalse: [val]]].
  	d = 8 ifTrue: [^ self closestPixelValue8].
  	d = 4 ifTrue: [^ self closestPixelValue4].
  	d = 2 ifTrue: [^ self closestPixelValue2]..
  	d = 1 ifTrue: [^ self closestPixelValue1].
  
  	self error: 'unknown pixel depth: ', d printString
  !

Item was added:
+ (PackageInfo named: 'Graphics') postscript: '"The cache might hold incorrect values during 10->8 bits per component transition"
+ Color allSubInstancesDo: [:c | c flushCache].'!



More information about the Squeak-dev mailing list