<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">2014/1/1 Tobias Pape <span dir="ltr"><<a href="mailto:Das.Linux@gmx.de" target="_blank">Das.Linux@gmx.de</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><br>
On 01.01.2014, at 19:55, <a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a> wrote:<br>
<br>
> Nicolas Cellier uploaded a new version of Graphics to project The Inbox:<br>
> <a href="http://source.squeak.org/inbox/Graphics-nice.285.mcz" target="_blank">http://source.squeak.org/inbox/Graphics-nice.285.mcz</a><br>
><br>
> ==================== Summary ====================<br>
><br>
> Name: Graphics-nice.285<br>
> Author: nice<br>
> Time: 1 January 2014, 8:53:32.416 pm<br>
> UUID: 04aee02d-83ae-4b4d-aed9-968a6a7487db<br>
> Ancestors: Graphics-nice.284<br>
><br>
> Change Color implementation from 10 bits per (rgb) component to 8 bits per component.<br>
> Several considerations motivate this change:<br>
> - no Graphic output is using 10 bits;<br>
<br>
</div>Au contraire!<br>
<a href="http://lmgtfy.com/?q=10+bit+graphics" target="_blank">http://lmgtfy.com/?q=10+bit+graphics</a><br>
<a href="https://nvidia.custhelp.com/app/answers/detail/a_id/3011/~/10-bit-per-color-support-on-nvidia-geforce-gpus" target="_blank">https://nvidia.custhelp.com/app/answers/detail/a_id/3011/~/10-bit-per-color-support-on-nvidia-geforce-gpus</a><br>
<a href="http://www.luminous-landscape.com/reviews/accessories/10bit.shtml" target="_blank">http://www.luminous-landscape.com/reviews/accessories/10bit.shtml</a><br>
<a href="http://www.amd.com/us/Documents/10-Bit.pdf" target="_blank">http://www.amd.com/us/Documents/10-Bit.pdf</a><br>
<br>
Best<br>
<span><font color="#888888"> -Tobias<br></font></span></blockquote><div><br></div><div>Thanks for the links Tobias, that's interesting.<br></div><div>Well, no graphics output in Squeak was what I meaned.<br></div>
<div>Squeak is far from being able to exploit those 10 bits, because it would require<br></div><div>- BitBlt support with a new format (30 bits depth)<br></div><div>- per device gamma correction<br></div><div>It's also unclear for me how the alpha channel is represented/processed (pre-processed?)<br>
<br></div><div>Do you have plans for such support?<br><br></div><div>Nicolas<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<span><font color="#888888">
</font></span><div><div><br>
> - alpha channel is already stored using 8 bits;<br>
> - 8 bits matches nowadays most used 32 bits depth Form - thus it's an optimization.<br>
> Note that the tolerance for testing Color components has to be increased to a value >= (1/255), I suggest 0.005.<br>
><br>
> =============== Diff against Graphics-nice.284 ===============<br>
><br>
> Item was added:<br>
> + (PackageInfo named: 'Graphics') preamble: '"Change color components from 10 to 8 bits"<br>
> + Color allSubInstancesDo:<br>
> + [:c |<br>
> + | rgb |<br>
> + rgb := c instVarNamed: ''rgb''.<br>
> + rgb := (rgb bitAnd: 16r3FC00000) >> 2 + (rgb bitAnd: 16rFF000) >> 2 + (rgb bitAnd: 16r3FC) >> 2.<br>
> + c instVarNamed: ''rgb'' put: rgb; flushCache].'!<br>
><br>
> Item was changed:<br>
> ----- Method: Color class>>initialize (in category 'class initialization') -----<br>
> initialize<br>
> "Color initialize"<br>
><br>
> "Details: Externally, the red, green, and blue components of color<br>
> are floats in the range [0.0..1.0]. Internally, they are represented<br>
> as integers in the range [0..ComponentMask] packing into a<br>
> small integer to save space and to allow fast hashing and<br>
> equality testing.<br>
><br>
> For a general description of color representations for computer<br>
> graphics, including the relationship between the RGB and HSV<br>
> color models used here, see Chapter 17 of Foley and van Dam,<br>
> Fundamentals of Interactive Computer Graphics, Addison-Wesley,<br>
> 1982."<br>
><br>
> + ComponentMask := 255.<br>
> + HalfComponentMask := 128. "used to round up in integer calculations"<br>
> + ComponentMax := 255.0. "a Float used to normalize components"<br>
> + RedShift := 16.<br>
> + GreenShift := 8.<br>
> - ComponentMask := 1023.<br>
> - HalfComponentMask := 512. "used to round up in integer calculations"<br>
> - ComponentMax := 1023.0. "a Float used to normalize components"<br>
> - RedShift := 20.<br>
> - GreenShift := 10.<br>
> BlueShift := 0.<br>
><br>
> PureRed := self r: 1 g: 0 b: 0.<br>
> PureGreen := self r: 0 g: 1 b: 0.<br>
> PureBlue := self r: 0 g: 0 b: 1.<br>
> PureYellow := self r: 1 g: 1 b: 0.<br>
> PureCyan := self r: 0 g: 1 b: 1.<br>
> PureMagenta := self r: 1 g: 0 b: 1.<br>
><br>
> RandomStream := Random new.<br>
><br>
> self initializeIndexedColors.<br>
> self initializeGrayToIndexMap.<br>
> self initializeNames.<br>
> self initializeHighLights.<br>
> !<br>
><br>
> Item was changed:<br>
> ----- Method: Color class>>initializeGrayToIndexMap (in category 'class initialization') -----<br>
> initializeGrayToIndexMap<br>
> "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."<br>
> "Note: This method must be called after initializeIndexedColors, since it uses IndexedColors."<br>
> "Color initializeGrayToIndexMap"<br>
><br>
> | grayLevels grayIndices c distToClosest dist indexOfClosest |<br>
> "record the level and index of each gray in the 8-bit color table"<br>
> grayLevels := OrderedCollection new.<br>
> grayIndices := OrderedCollection new.<br>
> "Note: skip the first entry, which is reserved for transparent"<br>
> 2 to: IndexedColors size do: [:i |<br>
> c := IndexedColors at: i.<br>
> c saturation = 0.0 ifTrue: [ "c is a gray"<br>
> + grayLevels add: c privateBlue. "top 8 bits; R, G, and B are the same"<br>
> - grayLevels add: (c privateBlue) >> 2. "top 8 bits; R, G, and B are the same"<br>
> grayIndices add: i - 1]]. "pixel values are zero-based"<br>
> grayLevels := grayLevels asArray.<br>
> grayIndices := grayIndices asArray.<br>
><br>
> "for each gray level in [0..255], select the closest match"<br>
> GrayToIndexMap := ByteArray new: 256.<br>
> 0 to: 255 do: [:level |<br>
> distToClosest := 10000. "greater than distance to any real gray"<br>
> 1 to: grayLevels size do: [:i |<br>
> dist := (level - (grayLevels at: i)) abs.<br>
> dist < distToClosest ifTrue: [<br>
> distToClosest := dist.<br>
> indexOfClosest := grayIndices at: i]].<br>
> GrayToIndexMap at: (level + 1) put: indexOfClosest].<br>
> !<br>
><br>
> Item was changed:<br>
> ----- Method: Color>>asHTMLColor (in category 'conversions') -----<br>
> asHTMLColor<br>
> + ^'#' , (rgb printStringBase: 16 length: 6 padded: true)!<br>
> - | s |<br>
> - s := '#000000' copy.<br>
> - s at: 2 put: (Character digitValue: ((rgb bitShift: -6 - RedShift) bitAnd: 15)).<br>
> - s at: 3 put: (Character digitValue: ((rgb bitShift: -2 - RedShift) bitAnd: 15)).<br>
> - s at: 4 put: (Character digitValue: ((rgb bitShift: -6 - GreenShift) bitAnd: 15)).<br>
> - s at: 5 put: (Character digitValue: ((rgb bitShift: -2 - GreenShift) bitAnd: 15)).<br>
> - s at: 6 put: (Character digitValue: ((rgb bitShift: -6 - BlueShift) bitAnd: 15)).<br>
> - s at: 7 put: (Character digitValue: ((rgb bitShift: -2 - BlueShift) bitAnd: 15)).<br>
> - ^ s!<br>
><br>
> Item was changed:<br>
> ----- Method: Color>>closestPixelValue1 (in category 'conversions') -----<br>
> closestPixelValue1<br>
> "Return the nearest approximation to this color for a monochrome Form."<br>
><br>
> "fast special cases"<br>
> rgb = 0 ifTrue: [^ 1]. "black"<br>
> + rgb = 16rFFFFFFF ifTrue: [^ 0]. "white"<br>
> - rgb = 16r3FFFFFFF ifTrue: [^ 0]. "white"<br>
><br>
> self luminance > 0.5<br>
> ifTrue: [^ 0] "white"<br>
> ifFalse: [^ 1]. "black"<br>
> !<br>
><br>
> Item was changed:<br>
> ----- Method: Color>>closestPixelValue2 (in category 'conversions') -----<br>
> closestPixelValue2<br>
> "Return the nearest approximation to this color for a 2-bit deep Form."<br>
><br>
> | lum |<br>
> "fast special cases"<br>
> rgb = 0 ifTrue: [^ 1]. "black"<br>
> + rgb = 16rFFFFFFF ifTrue: [^ 2]. "opaque white"<br>
> - rgb = 16r3FFFFFFF ifTrue: [^ 2]. "opaque white"<br>
><br>
> lum := self luminance.<br>
> lum < 0.2 ifTrue: [^ 1]. "black"<br>
> lum > 0.6 ifTrue: [^ 2]. "opaque white"<br>
> ^ 3 "50% gray"<br>
> !<br>
><br>
> Item was changed:<br>
> ----- Method: Color>>closestPixelValue4 (in category 'conversions') -----<br>
> closestPixelValue4<br>
> "Return the nearest approximation to this color for a 4-bit deep Form."<br>
><br>
> | bIndex |<br>
> "fast special cases"<br>
> rgb = 0 ifTrue: [^ 1]. "black"<br>
> + rgb = 16rFFFFFFF ifTrue: [^ 2]. "opaque white"<br>
> - rgb = 16r3FFFFFFF ifTrue: [^ 2]. "opaque white"<br>
><br>
> rgb = PureRed privateRGB ifTrue: [^ 4].<br>
> rgb = PureGreen privateRGB ifTrue: [^ 5].<br>
> rgb = PureBlue privateRGB ifTrue: [^ 6].<br>
> rgb = PureCyan privateRGB ifTrue: [^ 7].<br>
> rgb = PureYellow privateRGB ifTrue: [^ 8].<br>
> rgb = PureMagenta privateRGB ifTrue: [^ 9].<br>
><br>
> bIndex := (self luminance * 8.0) rounded. "bIndex in [0..8]"<br>
> ^ #(<br>
> 1 "black"<br>
> 10 "1/8 gray"<br>
> 11 "2/8 gray"<br>
> 12 "3/8 gray"<br>
> 3 "4/8 gray"<br>
> 13 "5/8 gray"<br>
> 14 "6/8 gray"<br>
> 15 "7/8 gray"<br>
> 2 "opaque white"<br>
> ) at: bIndex + 1.<br>
> !<br>
><br>
> Item was changed:<br>
> ----- Method: Color>>closestPixelValue8 (in category 'conversions') -----<br>
> closestPixelValue8<br>
> "Return the nearest approximation to this color for an 8-bit deep Form."<br>
><br>
> "fast special cases"<br>
> rgb = 0 ifTrue: [^ 1]. "black"<br>
> + rgb = 16rFFFFFFF ifTrue: [^ 255]. "white"<br>
> - rgb = 16r3FFFFFFF ifTrue: [^ 255]. "white"<br>
><br>
> self saturation < 0.2 ifTrue: [<br>
> + ^ GrayToIndexMap at: self privateGreen + 1. "nearest gray"<br>
> - ^ GrayToIndexMap at: (self privateGreen >> 2) + 1. "nearest gray"<br>
> ] ifFalse: [<br>
> "compute nearest entry in the color cube"<br>
> ^ 40 +<br>
> ((((self privateRed * 5) + HalfComponentMask) // ComponentMask) * 36) +<br>
> ((((self privateBlue * 5) + HalfComponentMask) // ComponentMask) * 6) +<br>
> (((self privateGreen * 5) + HalfComponentMask) // ComponentMask)].<br>
> !<br>
><br>
> Item was changed:<br>
> ----- Method: Color>>pixelValueForDepth: (in category 'conversions') -----<br>
> pixelValueForDepth: d<br>
> "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:"<br>
> "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."<br>
> "Transparency: The pixel value zero is reserved for transparent. For depths greater than 8, black maps to the darkest possible blue."<br>
><br>
> | val |<br>
> d > 8 "most common case"<br>
> ifTrue:<br>
> [d = 32 ifTrue: [<br>
> "eight bits per component; top 8 bits set to all ones (opaque alpha)"<br>
> + ^rgb = 0 ifTrue: [16rFF000001] ifFalse: [rgb bitOr: 16rFF000000]].<br>
> - val := (LargePositiveInteger new: 4)<br>
> - at: 4 put: 16rFF;<br>
> - at: 3 put: ((rgb bitShift: -22) bitAnd: 16rFF);<br>
> - at: 2 put: ((rgb bitShift: -12) bitAnd: 16rFF);<br>
> - at: 1 put: ((rgb bitShift: -2) bitAnd: 16rFF);<br>
> - normalize. "normalize is not necessary as long as SmallInteger maxVal highBit < 32, but let's be future proof"<br>
> - ^val < 16rFF000001 ifTrue: [16rFF000001] ifFalse: [val]].<br>
><br>
> d = 16 ifTrue: [<br>
> "five bits per component; top bits ignored"<br>
> + val := (((rgb bitShift: -9) bitAnd: 16r7C00) bitOr:<br>
> + ((rgb bitShift: -6) bitAnd: 16r03E0)) bitOr:<br>
> + ((rgb bitShift: -3) bitAnd: 16r001F).<br>
> - val := (((rgb bitShift: -15) bitAnd: 16r7C00) bitOr:<br>
> - ((rgb bitShift: -10) bitAnd: 16r03E0)) bitOr:<br>
> - ((rgb bitShift: -5) bitAnd: 16r001F).<br>
> ^val < 1 ifTrue: [1] ifFalse: [val]].<br>
><br>
> d = 12 ifTrue: [ "for indexing a color map with 4 bits per color component"<br>
> + val := (((rgb bitShift: -12) bitAnd: 16r0F00) bitOr:<br>
> + ((rgb bitShift: -8) bitAnd: 16r00F0)) bitOr:<br>
> + ((rgb bitShift: -4) bitAnd: 16r000F).<br>
> - val := (((rgb bitShift: -18) bitAnd: 16r0F00) bitOr:<br>
> - ((rgb bitShift: -12) bitAnd: 16r00F0)) bitOr:<br>
> - ((rgb bitShift: -6) bitAnd: 16r000F).<br>
> ^val < 1 ifTrue: [1] ifFalse: [val]].<br>
><br>
> d = 9 ifTrue: [ "for indexing a color map with 3 bits per color component"<br>
> + val := (((rgb bitShift: -15) bitAnd: 16r01C0) bitOr:<br>
> + ((rgb bitShift: -10) bitAnd: 16r0038)) bitOr:<br>
> + ((rgb bitShift: -5) bitAnd: 16r0007).<br>
> - val := (((rgb bitShift: -21) bitAnd: 16r01C0) bitOr:<br>
> - ((rgb bitShift: -14) bitAnd: 16r0038)) bitOr:<br>
> - ((rgb bitShift: -7) bitAnd: 16r0007).<br>
> ^val < 1 ifTrue: [1] ifFalse: [val]]].<br>
> d = 8 ifTrue: [^ self closestPixelValue8].<br>
> d = 4 ifTrue: [^ self closestPixelValue4].<br>
> d = 2 ifTrue: [^ self closestPixelValue2]..<br>
> d = 1 ifTrue: [^ self closestPixelValue1].<br>
><br>
> self error: 'unknown pixel depth: ', d printString<br>
> !<br>
><br>
> Item was added:<br>
> + (PackageInfo named: 'Graphics') postscript: '"The cache might hold incorrect values during 10->8 bits per component transition"<br>
> + Color allSubInstancesDo: [:c | c flushCache].'!<br>
><br>
><br>
<br>
</div></div><br><br>
<br></blockquote></div><br></div></div>