--- a/Depth8Image.st Fri Jun 14 17:57:21 1996 +0200
+++ b/Depth8Image.st Fri Jun 14 17:58:34 1996 +0200
@@ -160,276 +160,6 @@
"Modified: 10.6.1996 / 18:54:36 / cg"
!
-paletteImageAsDitheredPseudoFormOn:aDevice
- "return a dithered pseudoForm from the palette picture. Depend
- on dither colors being preallocated (see Color>>getColors*)"
-
- ^ self paletteImageAsDitheredPseudoFormOn:aDevice
- colors:Color fixColors
- nRed:Color numFixRed
- nGreen:Color numFixGreen
- nBlue:Color numFixBlue
-!
-
-paletteImageAsDitheredPseudoFormOn:aDevice colors:fixColors nRed:nRed nGreen:nGreen nBlue:nBlue
- "return a floyd-steinberg dithered pseudoForm from the palette picture.
- Use the colors in the fixColors array, which must be fixR x fixG x fixB
- colors assigned to aDevice, such as the preallocated colors of the
- Color class.
- By passing the ditherColors as extra array, this method can
- also be used to dither an 8bit image into a smaller number of colors,
- for example to create dithered Depth4Images from Depth8Images."
-
- |pseudoBits f has8BitImage deviceDepth
- rgbBytes
- w "{Class: SmallInteger }"
- h "{Class: SmallInteger }"
- index "{Class: SmallInteger }"
- fixR "{Class: SmallInteger }"
- fixG "{Class: SmallInteger }"
- fixB "{Class: SmallInteger }"
- fixIds failed map colorMapSize
- error clr|
-
- aDevice ~~ Display ifTrue:[^ nil].
-
- fixR := nRed.
- fixR == 0 ifTrue:[ ^ nil].
- fixG := nGreen.
- fixG == 0 ifTrue:[ ^ nil].
- fixB := nBlue.
- fixB == 0 ifTrue:[ ^ nil].
-
- "/ simple check
- (fixR * fixG * fixB) ~~ fixColors size ifTrue:[
- self error:'invalid color array passed'.
- ^ nil
- ].
- fixIds := (fixColors asArray collect:[:clr | clr colorId]) asByteArray.
-
- deviceDepth := aDevice depth.
- deviceDepth == 8 ifTrue:[
- has8BitImage := true.
- ] ifFalse:[
- has8BitImage := false.
- aDevice supportedImageFormats do:[:fmt |
- (fmt at:#bitsPerPixel) == 8 ifTrue:[
- has8BitImage := true.
- ]
- ]
- ].
- has8BitImage ifFalse:[^ nil].
-
- "/
- "/ collect color components as integer values (for integer arithmetic)
- "/
- rgbBytes := ByteArray uninitializedNew:256 * 3.
-
- index := 1.
- 0 to:255 do:[:i |
- clr := self colorFromValue:i.
- rgbBytes at:index put:(clr redByte).
- rgbBytes at:index+1 put:(clr greenByte).
- rgbBytes at:index+2 put:(clr blueByte).
- index := index + 3.
- ].
-
- pseudoBits := ByteArray uninitializedNew:(width * height).
-
- w := width + 2.
- error := ByteArray uninitializedNew:w*(3*2).
-
- w := width.
- h := height.
-
- failed := true.
-
-%{
- int __x, __y;
- int __eR, __eG, __eB;
- unsigned char *srcP, *dstP;
- unsigned char *rgbP;
- unsigned char *idP;
- short *errP, *eP;
- int __fR, __fG, __fB;
- int iR, iG, iB;
- int idx;
- int __w = __intVal(w);
-
- if (__isByteArray(__INST(bytes))
- && __isByteArray(pseudoBits)
- && __isByteArray(rgbBytes)
- && __isByteArray(fixIds)
- && __isByteArray(error)
- && __bothSmallInteger(fixR, fixG)
- && __isSmallInteger(fixB)) {
- failed = false;
-
- srcP = __ByteArrayInstPtr(_INST(bytes))->ba_element;
- dstP = __ByteArrayInstPtr(pseudoBits)->ba_element;
- rgbP = __ByteArrayInstPtr(rgbBytes)->ba_element;
- idP = __ByteArrayInstPtr(fixIds)->ba_element;
- errP = (short *) _ByteArrayInstPtr(error)->ba_element;
- __fR = __intVal(fixR)-1;
- __fG = __intVal(fixG)-1;
- __fB = __intVal(fixB)-1;
-
- /*
- * clear error accumulator
- */
- eP = errP;
- bzero(eP, (__w+2) * 2 * 3);
-
- for (__y=__intVal(h); __y>0; __y--) {
- __eR = __eG = __eB = 0;
-
- eP = &(errP[3]);
- __eR = eP[0];
- __eG = eP[1];
- __eB = eP[2];
-
- for (__x=__w; __x>0; __x--) {
- int __want;
- int pix;
- int __wantR, __wantG, __wantB;
- int idx;
- int tR, tG, tB;
- int nR, nG, nB;
-
- pix = *srcP++;
-
- /*
- * wR, wG and wB is the wanted r/g/b value;
- */
- idx = pix+pix+pix; /* pix * 3 */
-
- __wantR = rgbP[idx] + __eR;
- __wantG = rgbP[idx+1] + __eG;
- __wantB = rgbP[idx+2] + __eB;
-
- if (__wantR > 255) __want = 255;
- else if (__wantR < 0) __want = 0;
- else __want = __wantR;
-
- iR = (__want * __fR + 128) / 255; /* red index rounded */
- idx = iR * (__fG+1);
-
- if (__wantG > 255) __want = 255;
- else if (__wantG < 0) __want = 0;
- else __want = __wantG;
-
- iG = (__want * __fG + 128) / 255; /* green index rounded */
- idx = (idx + iG) * (__fB+1);
-
- if (__wantB > 255) __want = 255;
- else if (__wantB < 0) __want = 0;
- else __want = __wantB;
-
- iB = (__want * __fB + 128) / 255; /* blue index rounded */
- idx = idx + iB;
-
- /*
- * store the corresponding dither colors colorId
- */
- *dstP++ = idP[idx];
-
- /*
- * the new error:
- */
- __eR = __wantR - (iR * 255 / __fR);
- __eG = __wantG - (iG * 255 / __fG);
- __eB = __wantB - (iB * 255 / __fB);
-
- /*
- * distribute the error
- */
- tR = __eR >> 4; /* 16th of error */
- tG = __eG >> 4;
- tB = __eB >> 4;
-
- nR = eP[3] + (tR * 7);/* from accu: error for (x+1 / y) */
- nG = eP[4] + (tG * 7);/* plus 7/16'th of this error */
- nB = eP[5] + (tB * 7);
-
- eP[0] = tR*5; /* 5/16th for (x / y+1) */
- eP[1] = tG*5;
- eP[2] = tB*5;
-
- eP[-3] = tR*3; /* 3/16th for (x-1 / y+1) */
- eP[-2] = tG*3;
- eP[-1] = tB*3;
-
- eP[3] = __eR - (tR*15); /* 1/16th for (x+1 / y+1) */
- eP[4] = __eG - (tG*15);
- eP[5] = __eB - (tB*15);
-
- __eR = nR;
- __eG = nG;
- __eB = nB;
-
- eP += 3;
- }
- }
- }
-%}.
- failed ifTrue:[
- self primitiveFailed.
- ^ nil
- ].
-
- f := Form width:width height:height depth:deviceDepth on:aDevice.
- f isNil ifTrue:[^ nil].
- "/
- "/ have to create a funny colorMap, where
- "/ color at:index == color colorId:index
- "/
- map := Array new:256.
- fixColors do:[:clr |
- map at:clr colorId + 1 put:clr
- ].
- f colorMap:map.
- f initGC.
- f bits:pseudoBits.
- aDevice drawBits:pseudoBits bitsPerPixel:8 depth:deviceDepth
- width:width height:height
- x:0 y:0
- into:(f id) x:0 y:0
- width:width height:height with:(f gcId).
- ^ f
-
- "
- example:
- color reduction from Depth8 to Depth4 (dithering) can be done by:
-
- |img8 reducedImg8 img4 map form|
-
- map := #(
- (0 0 0)
- (0 0 100)
- (0 50 0)
- (0 50 100)
- (0 100 0)
- (0 100 100)
- (100 0 0)
- (100 0 100)
- (100 50 0)
- (100 50 100)
- (100 100 0)
- (100 100 100)) collect:[:rgb | (Color red:(rgb at:1)
- green:(rgb at:2)
- blue:(rgb at:3)) on:Display].
-
- img8 := Image fromFile:'bitmaps/bf.im8'.
- form := img8 paletteImageAsDitheredPseudoFormOn:Display
- colors:map
- nRed:2
- nGreen:3
- nBlue:2.
- img8 := Depth8Image fromForm:form. 'dithered version of original image'.
- img4 := Depth4Image fromImage:img8.
- "
-!
-
paletteImageAsPseudoFormOn:aDevice
"return a pseudoForm from the palette picture. The main work is
in color reduction, when not all colors can be aquired."
@@ -444,18 +174,23 @@
m "{Class: SmallInteger }" |
Color fixColors notNil ifTrue:[
- f := self paletteImageAsDitheredPseudoFormOn:aDevice.
- f notNil ifTrue:[^ f].
+ f := self
+ asFloydSteinbergDitheredDepth8FormOn:aDevice
+ colors:Color fixColors
+ nRed:Color numFixRed
+ nGreen:Color numFixGreen
+ nBlue:Color numFixBlue.
+ f notNil ifTrue:[^ f].
].
"find used colors"
usedColors := bytes usedValues. "gets us an array filled with used values"
- "(could use bytes asBag)"
+ "(could use bytes asBag)"
maxIndex := usedColors max + 1.
usedColors size > 20 ifTrue:[
- ('D8IMAGE: allocating ' , usedColors size printString , ' colors ...') infoPrintNL.
+ ('D8IMAGE: allocating ' , usedColors size printString , ' colors ...') infoPrintNL.
].
"sort by usage"
@@ -481,55 +216,55 @@
gcRound := 0.
usedColors do:[:aColorIndex |
- |devColor color
- r "{Class: SmallInteger }"
- g "{Class: SmallInteger }"
- b "{Class: SmallInteger }"
- mapIndex "{Class: SmallInteger }"
- rMask "{Class: SmallInteger }"
- gMask "{Class: SmallInteger }"
- bMask "{Class: SmallInteger }"|
+ |devColor color
+ r "{Class: SmallInteger }"
+ g "{Class: SmallInteger }"
+ b "{Class: SmallInteger }"
+ mapIndex "{Class: SmallInteger }"
+ rMask "{Class: SmallInteger }"
+ gMask "{Class: SmallInteger }"
+ bMask "{Class: SmallInteger }"|
- fit ifTrue:[
- gMask := bMask := rMask := m.
+ fit ifTrue:[
+ gMask := bMask := rMask := m.
- mapIndex := aColorIndex + 1.
- color := colorMap at:mapIndex.
- color colorId notNil ifTrue:[
- "wow - an immediate hit"
- devColor := color
- ] ifFalse:[
- devColor := color exactOn:aDevice.
- devColor isNil ifTrue:[
- "
- could not allocate color - on the first round, do a GC to flush
- unused colors - this may help if some colors where locked by
- already free images.
- "
- gcRound == 0 ifTrue:[
- ObjectMemory scavenge; finalize.
- devColor := color exactOn:aDevice.
- gcRound := 1
- ].
- devColor isNil ifTrue:[
- gcRound == 1 ifTrue:[
- CollectGarbageWhenRunningOutOfColors ifTrue:[
- 'D8IMAGE: force GC for possible color reclamation.' infoPrintNL.
- ObjectMemory incrementalGC; finalize.
- devColor := color exactOn:aDevice.
- ].
- gcRound := 2
- ]
- ]
- ].
- ].
- (devColor notNil and:[devColor colorId notNil]) ifTrue:[
- imgMap at:mapIndex put:devColor.
- lastOK := lastOK + 1.
- ] ifFalse:[
- fit := false
- ]
- ]
+ mapIndex := aColorIndex + 1.
+ color := colorMap at:mapIndex.
+ color colorId notNil ifTrue:[
+ "wow - an immediate hit"
+ devColor := color
+ ] ifFalse:[
+ devColor := color exactOn:aDevice.
+ devColor isNil ifTrue:[
+ "
+ could not allocate color - on the first round, do a GC to flush
+ unused colors - this may help if some colors where locked by
+ already free images.
+ "
+ gcRound == 0 ifTrue:[
+ ObjectMemory scavenge; finalize.
+ devColor := color exactOn:aDevice.
+ gcRound := 1
+ ].
+ devColor isNil ifTrue:[
+ gcRound == 1 ifTrue:[
+ CollectGarbageWhenRunningOutOfColors ifTrue:[
+ 'D8IMAGE: force GC for possible color reclamation.' infoPrintNL.
+ ObjectMemory incrementalGC; finalize.
+ devColor := color exactOn:aDevice.
+ ].
+ gcRound := 2
+ ]
+ ]
+ ].
+ ].
+ (devColor notNil and:[devColor colorId notNil]) ifTrue:[
+ imgMap at:mapIndex put:devColor.
+ lastOK := lastOK + 1.
+ ] ifFalse:[
+ fit := false
+ ]
+ ]
].
fit ifFalse:[
@@ -551,103 +286,103 @@
"/ imgMap at:mapIndex put:(tree findBest:(colorMap at:mapIndex))
"/ ].
- "
- again, this time allow wrong colors (loop while increasing allowed error)
- "
- error := 10.
- [fit] whileFalse:[
- fit := true.
- usedColors from:(lastOK+1) to:(usedColors size) do:[:aColorIndex |
- |devColor color
- r "{Class: SmallInteger }"
- g "{Class: SmallInteger }"
- b "{Class: SmallInteger }"
- mapIndex "{Class: SmallInteger }"
- rMask "{Class: SmallInteger }"
- gMask "{Class: SmallInteger }"
- bMask "{Class: SmallInteger }"|
+ "
+ again, this time allow wrong colors (loop while increasing allowed error)
+ "
+ error := 10.
+ [fit] whileFalse:[
+ fit := true.
+ usedColors from:(lastOK+1) to:(usedColors size) do:[:aColorIndex |
+ |devColor color
+ r "{Class: SmallInteger }"
+ g "{Class: SmallInteger }"
+ b "{Class: SmallInteger }"
+ mapIndex "{Class: SmallInteger }"
+ rMask "{Class: SmallInteger }"
+ gMask "{Class: SmallInteger }"
+ bMask "{Class: SmallInteger }"|
- fit ifTrue:[
- gMask := bMask := rMask := m.
+ fit ifTrue:[
+ gMask := bMask := rMask := m.
- mapIndex := aColorIndex + 1.
- color := colorMap at:mapIndex.
- r := (color red * 255 / 100) rounded.
- g := (color green * 255 / 100) rounded.
- b := (color blue * 255 / 100) rounded.
+ mapIndex := aColorIndex + 1.
+ color := colorMap at:mapIndex.
+ r := (color red * 255 / 100) rounded.
+ g := (color green * 255 / 100) rounded.
+ b := (color blue * 255 / 100) rounded.
- color := Color red:((r bitShift:shift) bitAnd:rMask) * scale
- green:((g bitShift:shift) bitAnd:gMask) * scale
- blue:((b bitShift:shift) bitAnd:bMask) * scale.
+ color := Color red:((r bitShift:shift) bitAnd:rMask) * scale
+ green:((g bitShift:shift) bitAnd:gMask) * scale
+ blue:((b bitShift:shift) bitAnd:bMask) * scale.
- color colorId notNil ifTrue:[
- "wow - an immediate hit"
- devColor := color
- ] ifFalse:[
- devColor := color nearestOn:aDevice error:error.
- devColor isNil ifTrue:[
- "
- no free color - on the first round, do a GC to flush unused
- colors - this may help if some colors where locked by already
- free images.
- "
- gcRound == 0 ifTrue:[
- ObjectMemory scavenge; finalize.
- devColor := color nearestOn:aDevice error:error.
- gcRound := 1
- ].
- devColor isNil ifTrue:[
- gcRound == 1 ifTrue:[
- CollectGarbageWhenRunningOutOfColors ifTrue:[
- 'D8IMAGE: force GC for possible color reclamation.' infoPrintNL.
- ObjectMemory incrementalGC; finalize.
- devColor := color nearestOn:aDevice error:error.
- ].
- gcRound := 2
- ]
- ]
- ].
- ].
- (devColor notNil and:[devColor colorId notNil]) ifTrue:[
- imgMap at:mapIndex put:devColor.
- lastOK := lastOK + 1.
- ] ifFalse:[
- fit := false
- ]
- ].
- ].
- error := error * 2.
- error > 1000 ifTrue:[
- "
- break out, if the error becomes too big.
- "
- 'D8IMAGE: hard color allocation problem - revert to b&w' infoPrintNL.
- "
- map to b&w as a last fallback.
- (should really do a dither here)
- "
- usedColors from:(lastOK+1) to:(usedColors size) do:[:aColorIndex |
- |color
- mapIndex "{ Class: SmallInteger }"|
+ color colorId notNil ifTrue:[
+ "wow - an immediate hit"
+ devColor := color
+ ] ifFalse:[
+ devColor := color nearestOn:aDevice error:error.
+ devColor isNil ifTrue:[
+ "
+ no free color - on the first round, do a GC to flush unused
+ colors - this may help if some colors where locked by already
+ free images.
+ "
+ gcRound == 0 ifTrue:[
+ ObjectMemory scavenge; finalize.
+ devColor := color nearestOn:aDevice error:error.
+ gcRound := 1
+ ].
+ devColor isNil ifTrue:[
+ gcRound == 1 ifTrue:[
+ CollectGarbageWhenRunningOutOfColors ifTrue:[
+ 'D8IMAGE: force GC for possible color reclamation.' infoPrintNL.
+ ObjectMemory incrementalGC; finalize.
+ devColor := color nearestOn:aDevice error:error.
+ ].
+ gcRound := 2
+ ]
+ ]
+ ].
+ ].
+ (devColor notNil and:[devColor colorId notNil]) ifTrue:[
+ imgMap at:mapIndex put:devColor.
+ lastOK := lastOK + 1.
+ ] ifFalse:[
+ fit := false
+ ]
+ ].
+ ].
+ error := error * 2.
+ error > 1000 ifTrue:[
+ "
+ break out, if the error becomes too big.
+ "
+ 'D8IMAGE: hard color allocation problem - revert to b&w' infoPrintNL.
+ "
+ map to b&w as a last fallback.
+ (should really do a dither here)
+ "
+ usedColors from:(lastOK+1) to:(usedColors size) do:[:aColorIndex |
+ |color
+ mapIndex "{ Class: SmallInteger }"|
- mapIndex := aColorIndex + 1.
- color := colorMap at:mapIndex.
- color brightness > 0.5 ifTrue:[
- color := Color white.
- ] ifFalse:[
- color := Color black.
- ].
- imgMap at:mapIndex put:(color on:aDevice).
- ].
- fit := true.
- ]
- ].
+ mapIndex := aColorIndex + 1.
+ color := colorMap at:mapIndex.
+ color brightness > 0.5 ifTrue:[
+ color := Color white.
+ ] ifFalse:[
+ color := Color black.
+ ].
+ imgMap at:mapIndex put:(color on:aDevice).
+ ].
+ fit := true.
+ ]
+ ].
- error > 100 ifTrue:[
- 'D8IMAGE: not enough colors for a reasonable image' infoPrintNL
- ] ifFalse:[
- 'D8IMAGE: not enough colors for exact picture' infoPrintNL.
- ]
+ error > 100 ifTrue:[
+ 'D8IMAGE: not enough colors for a reasonable image' infoPrintNL
+ ] ifFalse:[
+ 'D8IMAGE: not enough colors for exact picture' infoPrintNL.
+ ]
].
"
@@ -655,11 +390,11 @@
"
map := ByteArray new:256.
1 to:imgMap size do:[:i |
- |clr|
+ |clr|
- (clr := imgMap at:i) notNil ifTrue:[
- map at:i put:clr colorId
- ]
+ (clr := imgMap at:i) notNil ifTrue:[
+ map at:i put:clr colorId
+ ]
].
"
@@ -667,14 +402,14 @@
"
deviceDepth := aDevice depth.
deviceDepth == 8 ifTrue:[
- has8BitImage := true.
+ has8BitImage := true.
] ifFalse:[
- has8BitImage := false.
- aDevice supportedImageFormats do:[:fmt |
- (fmt at:#bitsPerPixel) == 8 ifTrue:[
- has8BitImage := true.
- ]
- ]
+ has8BitImage := false.
+ aDevice supportedImageFormats do:[:fmt |
+ (fmt at:#bitsPerPixel) == 8 ifTrue:[
+ has8BitImage := true.
+ ]
+ ]
].
"
@@ -682,26 +417,26 @@
the pixel values
"
has8BitImage ifTrue:[
- pseudoBits := ByteArray uninitializedNew:(width * height).
+ pseudoBits := ByteArray uninitializedNew:(width * height).
- bytes expandPixels:8 "xlate only"
- width:width
- height:height
- into:pseudoBits
- mapping:map.
+ bytes expandPixels:8 "xlate only"
+ width:width
+ height:height
+ into:pseudoBits
+ mapping:map.
- map := nil.
+ map := nil.
- f := Form width:width height:height depth:deviceDepth on:aDevice.
- f isNil ifTrue:[^ nil].
- f colorMap:imgMap.
- f initGC.
- aDevice drawBits:pseudoBits bitsPerPixel:8 depth:deviceDepth
- width:width height:height
- x:0 y:0
- into:(f id) x:0 y:0
- width:width height:height with:(f gcId).
- ^ f
+ f := Form width:width height:height depth:deviceDepth on:aDevice.
+ f isNil ifTrue:[^ nil].
+ f colorMap:imgMap.
+ f initGC.
+ aDevice drawBits:pseudoBits bitsPerPixel:8 depth:deviceDepth
+ width:width height:height
+ x:0 y:0
+ into:(f id) x:0 y:0
+ width:width height:height with:(f gcId).
+ ^ f
].
"
@@ -714,10 +449,10 @@
newImage bits:(ByteArray uninitializedNew:(height * newImage bytesPerRow)).
0 to:height-1 do:[:row |
- 0 to:width-1 do:[:col |
- pxl := self valueAtX:col y:row.
- newImage atX:col y:row putValue:(map at:pxl)
- ]
+ 0 to:width-1 do:[:col |
+ pxl := self valueAtX:col y:row.
+ newImage atX:col y:row putValue:(map at:pxl)
+ ]
].
f := Form width:width height:height depth:deviceDepth on:aDevice.
@@ -726,11 +461,13 @@
f initGC.
aDevice drawBits:(newImage bits) depth:deviceDepth width:width height:height
- x:0 y:0
- into:(f id) x:0 y:0
- width:width height:height with:(f gcId).
+ x:0 y:0
+ into:(f id) x:0 y:0
+ width:width height:height with:(f gcId).
^ f
+
+ "Modified: 14.6.1996 / 16:55:24 / cg"
! !
!Depth8Image methodsFor:'dither helpers'!
@@ -1522,5 +1259,5 @@
!Depth8Image class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libview/Depth8Image.st,v 1.49 1996-06-14 14:09:25 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libview/Depth8Image.st,v 1.50 1996-06-14 15:58:34 cg Exp $'
! !