--- a/Image.st Sat Jun 22 16:46:00 1996 +0200
+++ b/Image.st Sat Jun 22 16:54:04 1996 +0200
@@ -5436,6 +5436,530 @@
"Modified: 18.6.1996 / 09:18:09 / cg"
!
+nfloydSteinbergDitheredDepth8BitsColors:colors
+ "return a floyd-steinberg dithered bitmap from the receiver picture,
+ which must be a depth-8 image.
+ This method expects an array of colors to be used for dithering
+ (which need not be a colorCubes colors)."
+
+ |pseudoBits
+ rgbBytes
+ ditherRGBBytes ditherColors
+ w "{Class: SmallInteger }"
+ h "{Class: SmallInteger }"
+ index "{Class: SmallInteger }"
+ numR "{Class: SmallInteger }"
+ numG "{Class: SmallInteger }"
+ numB "{Class: SmallInteger }"
+ bitsR "{Class: SmallInteger }"
+ bitsG "{Class: SmallInteger }"
+ bitsB "{Class: SmallInteger }"
+ maxBits "{Class: SmallInteger }"
+ maskR "{Class: SmallInteger }"
+ maskG "{Class: SmallInteger }"
+ maskB "{Class: SmallInteger }"
+ shR "{Class: SmallInteger }"
+ shG "{Class: SmallInteger }"
+ shB "{Class: SmallInteger }"
+ ditherIds failed map lastColor colorsByDistance qScramble
+ clrLookup lookupPos cube nCube
+ dR "{Class: SmallInteger }"
+ dG "{Class: SmallInteger }"
+ dB "{Class: SmallInteger }"
+ iR "{Class: SmallInteger }"
+ iRG "{Class: SmallInteger }"
+ iRGB "{Class: SmallInteger }"
+ clr
+ rI "{Class: SmallInteger }"
+ gI "{Class: SmallInteger }"
+ bI "{Class: SmallInteger }"
+ maxIDX "{Class: SmallInteger }"
+ subCubeColorCollection
+ error
+ dl "{Class: SmallInteger }"|
+
+ self depth ~~ 8 ifTrue:[^ nil].
+
+ "/
+ "/ collect color components as integer values (for integer arithmetic)
+ "/
+ rgbBytes := ByteArray uninitializedNew:256 * 3.
+
+ photometric == #palette ifTrue:[
+ lastColor := colorMap size - 1
+ ] ifFalse:[
+ lastColor := 255.
+ ].
+ index := 1.
+ 0 to:lastColor do:[:pix |
+ clr := self colorFromValue:pix.
+ rgbBytes at:index put:(clr redByte).
+ rgbBytes at:index+1 put:(clr greenByte).
+ rgbBytes at:index+2 put:(clr blueByte).
+
+ index := index + 3.
+ ].
+
+ "/ collect valid ditherColors ...
+
+ ditherColors := colors select:[:clr | clr notNil].
+
+ "/ collect ditherColor components
+
+ lastColor := ditherColors size.
+ ditherIds := ByteArray uninitializedNew:lastColor.
+ ditherRGBBytes := ByteArray uninitializedNew:(lastColor * 3).
+ index := 1.
+ 1 to:lastColor do:[:pix |
+ clr := ditherColors at:pix.
+ ditherRGBBytes at:index put:(clr redByte).
+ ditherRGBBytes at:index+1 put:(clr greenByte).
+ ditherRGBBytes at:index+2 put:(clr blueByte).
+ ditherIds at:pix put:clr colorId.
+
+ index := index + 3.
+ ].
+
+ "/ place the ditherColor positions into a color cube
+ bitsR := 5.
+ bitsG := 6.
+ bitsB := 4.
+ maxBits := 6.
+
+"/ bitsR := 4.
+"/ bitsG := 4.
+"/ bitsB := 3.
+
+ numR := 1 bitShift:bitsR.
+ numG := 1 bitShift:bitsG.
+ numB := 1 bitShift:bitsB.
+
+ maskR := (numR-1) bitShift:(bitsG + bitsB).
+ maskG := (numG-1) bitShift:bitsB.
+ maskB := numB-1.
+
+ shR := -16+bitsR+bitsG+bitsB.
+ shG := -16+bitsG+bitsB.
+ shB := -16+bitsB.
+
+ maxIDX := numR*numG*numB.
+ cube := Array new:maxIDX.
+ 1 to:lastColor do:[:clrIdx |
+ clr := ditherColors at:clrIdx.
+ rI := clr scaledRed. rI := (rI bitShift:shR) bitAnd:maskR.
+ gI := clr scaledGreen. gI := (gI bitShift:shG) bitAnd:maskG.
+ bI := clr scaledBlue. bI := (bI bitShift:shB) bitAnd:maskB.
+ index := rI + gI + bI + 1.
+ subCubeColorCollection := cube at:index.
+ subCubeColorCollection isNil ifTrue:[
+ subCubeColorCollection := OrderedCollection new.
+ cube at:index put:subCubeColorCollection.
+ ].
+ subCubeColorCollection add:(clrIdx - 1).
+ ].
+
+ shR := 1 bitShift:(bitsG+bitsB).
+ shG := 1 bitShift:(bitsB).
+ shB := 1.
+
+ 1 to:maxIDX do:[:i |
+ subCubeColorCollection := cube at:i.
+ subCubeColorCollection notNil ifTrue:[
+ cube at:i put:(subCubeColorCollection asByteArray)
+ ]
+ ].
+
+"/ nCube := cube copy.
+"/
+"/ cube keysAndValuesDo:[:i :indices |
+"/ indices notNil ifTrue:[
+"/ nCube at:i put:(indices asByteArray)
+"/ ] ifFalse:[
+"/ "/ find nearest color
+"/
+"/ dl := 1.
+"/ [dl < maxBits] whileTrue:[
+"/ dR := dl negated.
+"/ [dR <= dl] whileTrue:[
+"/ iR := i + (dR * shR).
+"/ (iR > 0 and:[iR < maxIDX]) ifTrue:[
+"/ dG := dl negated.
+"/ [dG < dl] whileTrue:[
+"/ iRG := iR + (dG * shG).
+"/ (iRG > 0 and:[iRG < maxIDX]) ifTrue:[
+"/ dB := dl negated.
+"/ [dB < dl] whileTrue:[
+"/ iRGB := iRG + dB.
+"/ (iRG > 0 and:[iRG < maxIDX]) ifTrue:[
+"/ (cube at:iRGB) notNil ifTrue:[
+"/ nCube at:i put:(cube at:iRGB).
+"/ dB := dG := dR := dl := 999.
+"/ ]
+"/ ].
+"/ dB := dB + 1.
+"/ ]
+"/ ].
+"/ dG := dG + 1.
+"/ ]
+"/ ].
+"/ dR := dR + 1.
+"/ ].
+"/ dl := dl + 1.
+"/ ]
+"/ ]
+"/ ].
+"/self halt.
+
+ "/ now, cube contains collections of colors which are
+ "/ positioned in a subCube; quickly accessed by a lookup
+
+ pseudoBits := ByteArray uninitializedNew:(width * height).
+
+ w := width.
+ h := height.
+ error := ByteArray new:(w+2)*3*2.
+
+%{
+#define BITSR 5
+#define BITSG 6
+#define BITSB 4
+#define MAXBITS 6
+
+#define xBITSR 4
+#define xBITSG 4
+#define xBITSB 3
+#define xMAXBITS 4
+
+#define NR 32 /* (1<<BITSR) */
+#define NG 64 /* (1<<BITSG) */
+#define NB 16 /* (1<<BITSB) */
+#define MAXRGB 64 /* (1<<MAXBITS) */
+
+#define SHR (BITSG+BITSB)
+#define SHG BITSB
+
+#define REMEMBER_SEARCH
+#define xNO_FLOYD_STEINBERG
+
+ int __x, __y;
+ int __eR, __eG, __eB;
+ unsigned char *srcP, *dstP;
+ unsigned char *rgbP;
+ unsigned char *idP;
+ unsigned char *dp;
+ short *errP, *eP;
+ int __fR, __fG, __fB;
+ int idx;
+ int __w = __intVal(w);
+ int __h = __intVal(h);
+ int __nColors = __intVal(lastColor);
+ int __wR = -1, __wG, __wB;
+ OBJ *__cube;
+ OBJ subCubeColors;
+ int cubeIndex, cubeIndex2;
+
+ if (__isByteArray(__INST(bytes))
+ && __isByteArray(pseudoBits)
+ && __isByteArray(rgbBytes)
+ && __isByteArray(ditherRGBBytes)
+ && __isByteArray(ditherIds)
+ && __isByteArray(error)) {
+ failed = false;
+
+ srcP = __ByteArrayInstPtr(_INST(bytes))->ba_element;
+ dstP = __ByteArrayInstPtr(pseudoBits)->ba_element;
+ rgbP = __ByteArrayInstPtr(rgbBytes)->ba_element;
+ idP = __ByteArrayInstPtr(ditherIds)->ba_element;
+ errP = (short *) __ByteArrayInstPtr(error)->ba_element;
+ __cube = __ArrayInstPtr(cube)->a_element;
+
+ eP = errP;
+
+ for (__y=__h; __y>0; __y--) {
+ 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;
+ int __dR, __dG, __dB;
+ int minDelta, bestIdx;
+ int __iR, __iG, __iB;
+ int cR, cG, cB;
+ int delta;
+
+ pix = *srcP++;
+
+ /*
+ * wR, wG and wB is the wanted r/g/b value;
+ */
+ idx = pix+pix+pix; /* pix * 3 */
+
+ __wR = __wantR = rgbP[idx] + __eR;
+ __wG = __wantG = rgbP[idx+1] + __eG;
+ __wB = __wantB = rgbP[idx+2] + __eB;
+ if(__wR > 255) __wR = 255;
+ else if (__wR < 0) __wR = 0;
+ if(__wG > 255) __wG = 255;
+ else if (__wG < 0) __wG = 0;
+ if(__wB > 255) __wB = 255;
+ else if (__wB < 0) __wB = 0;
+
+ __iR = __wR >> (8-BITSR);
+ __iG = __wG >> (8-BITSG);
+ __iB = __wB >> (8-BITSB);
+
+ cubeIndex = (__iR<<SHR) + (__iG<<SHG) + __iB;
+ subCubeColors = __cube[cubeIndex];
+
+ if (subCubeColors == nil) {
+ /* search around in spirals, for the first match */
+
+ delta = 1;
+ while (delta < MAXRGB) {
+ /* check plane above */
+ cR = __iR + delta;
+ if ((unsigned)cR < NR) {
+ for (cG=__iG-delta; cG<=__iG+delta; cG++) {
+ if ((unsigned)cG < NG) {
+ for (cB=__iB-delta; cB<=__iB+delta; cB++) {
+ if ((unsigned)cB < NB) {
+ cubeIndex2 = (cR<<SHR) + (cG<<SHG) + cB;
+ subCubeColors = __cube[cubeIndex2];
+ if (__isNonNilObject(subCubeColors)) {
+ goto found;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* check plane below */
+ cR = __iR - delta;
+ if ((unsigned)cR < NR) {
+ for (cG=__iG-delta; cG<=__iG+delta; cG++) {
+ if ((unsigned)cG < NG) {
+ for (cB=__iB-delta; cB<=__iB+delta; cB++) {
+ if ((unsigned)cB < NB) {
+ cubeIndex2 = (cR<<SHR) + (cG<<SHG) + cB;
+ subCubeColors = __cube[cubeIndex2];
+ if (__isNonNilObject(subCubeColors)) {
+ goto found;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* check plane to the right */
+ cG = __iG + delta;
+ if ((unsigned)cG < NG) {
+ for (cR=__iR-delta+1; cR<=__iR+delta-1; cR++) {
+ if ((unsigned)cR < NR) {
+ for (cB=__iB-delta; cB<=__iB+delta; cB++) {
+ if ((unsigned)cB < NB) {
+ cubeIndex2 = (cR<<SHR) + (cG<<SHG) + cB;
+ subCubeColors = __cube[cubeIndex2];
+ if (__isNonNilObject(subCubeColors)) {
+ goto found;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* check plane to the left */
+ cG = __iG - delta;
+ if ((unsigned)cG < NG) {
+ for (cR=__iR-delta+1; cR<=__iR+delta-1; cR++) {
+ if ((unsigned)cR < NR) {
+ for (cB=__iB-delta; cB<=__iB+delta; cB++) {
+ if ((unsigned)cB < NB) {
+ cubeIndex2 = (cR<<SHR) + (cG<<SHG) + cB;
+ subCubeColors = __cube[cubeIndex2];
+ if (__isNonNilObject(subCubeColors)) {
+ goto found;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* check plane at back */
+ cB = __iB + delta;
+ if ((unsigned)cB < NB) {
+ for (cR=__iR-delta+1; cR<=(__iR+delta-1); cR++) {
+ if ((unsigned)cR < NR) {
+ for (cG=__iG-delta+1; cG<=(__iG+delta-1); cG++) {
+ if ((unsigned)cG < NG) {
+ cubeIndex2 = (cR<<SHR) + (cG<<SHG) + cB;
+ subCubeColors = __cube[cubeIndex2];
+ if (__isNonNilObject(subCubeColors)) {
+ goto found;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* check plane at front */
+ cB = __iB - delta;
+ if ((unsigned)cB < NB) {
+ for (cR=__iR-delta+1; cR<=(__iR+delta-1); cR++) {
+ if ((unsigned)cR < NR) {
+ for (cG=__iG-delta+1; cG<=(__iG+delta-1); cG++) {
+ if ((unsigned)cG < NG) {
+ cubeIndex2 = (cR<<SHR) + (cG<<SHG) + cB;
+ subCubeColors = __cube[cubeIndex2];
+ if (__isNonNilObject(subCubeColors)) {
+ goto found;
+ }
+ }
+ }
+ }
+ }
+ }
+ delta = delta + 1;
+
+ if (InterruptPending) {
+ int d_srcP = srcP - __ByteArrayInstPtr(_INST(bytes))->ba_element;
+ int d_dstP = dstP - __ByteArrayInstPtr(pseudoBits)->ba_element;
+ int d_errP = errP - (short *) __ByteArrayInstPtr(error)->ba_element;
+
+ __interrupt__();
+
+ srcP = __ByteArrayInstPtr(_INST(bytes))->ba_element + d_srcP;
+ dstP = __ByteArrayInstPtr(pseudoBits)->ba_element + d_dstP;
+ rgbP = __ByteArrayInstPtr(rgbBytes)->ba_element;
+ idP = __ByteArrayInstPtr(ditherIds)->ba_element;
+ errP = (short *) __ByteArrayInstPtr(error)->ba_element + d_errP;
+ __cube = __ArrayInstPtr(cube)->a_element;
+ }
+ }
+ /* cannot happen - will lead to a segmentation violation ... */
+ subCubeColors = nil;
+
+ found:
+ __iR = cR;
+ __iG = cG;
+ __iB = cB;
+ bestIdx = __ByteArrayInstPtr(subCubeColors)->ba_element[0];
+#ifdef REMEMBER_SEARCH
+ __cube[cubeIndex] = __MKSMALLINT(bestIdx);
+#endif
+ } else {
+#ifdef REMEMBER_SEARCH
+ if (__isSmallInteger(subCubeColors)) {
+ bestIdx = __intVal(subCubeColors);
+ } else
+#endif
+ {
+ bestIdx = __ByteArrayInstPtr(subCubeColors)->ba_element[0];
+ }
+ }
+
+ /*
+ * ok, now, we have found a collection of nearby
+ * colors in subCubeColors.
+ *
+ * since the error is at most 1/16 (i.e. roughly 6%),
+ * dont care for searching the best - simply take the
+ * first color found there.
+ * (statistic reduces the error to even a smaller value).
+ * There is no real problem due to that error, since
+ * it will be diffused anyway ...
+ */
+
+#ifndef NO_FLOYD_STEINBERG
+ /*
+ * fetch that colors r/g/b components
+ */
+ dp = __ByteArrayInstPtr(ditherRGBBytes)->ba_element;
+ dp += bestIdx * 3;
+ __dR = dp[0];
+ __dG = dp[1];
+ __dB = dp[2];
+#endif
+
+/*
+printf("want: %d/%d/%d (%d/%d/%d) got: %d/%d/%d\n",
+ __wantR, __wantG, __wantB,
+ __wR, __wG, __wB,
+ __dR, __dG, __dB);
+*/
+ /*
+ * store the corresponding dither colors colorId
+ */
+ *dstP++ = idP[bestIdx];
+
+#ifndef NO_FLOYD_STEINBERG
+ /*
+ * the new error & distribute the error
+ */
+ __eR = __wantR - __dR;
+ if (__eR) {
+ tR = __eR >> 4; /* 16th of error */
+ nR = eP[3] + (tR * 7);/* from accu: error for (x+1 / y) */
+ eP[0] = tR*5; /* 5/16th for (x / y+1) */
+ eP[-3] = tR*3; /* 3/16th for (x-1 / y+1) */
+ eP[3] = __eR - (tR*15); /* 1/16th for (x+1 / y+1) */
+ __eR = nR;
+ } else {
+ __eR = eP[3];
+ eP[0] = eP[-3] = eP[3] = 0;
+ }
+
+ __eG = __wantG - __dG;
+ if (__eG) {
+ tG = __eG >> 4;
+ nG = eP[4] + (tG * 7);/* plus 7/16'th of this error */
+ eP[1] = tG*5;
+ eP[-2] = tG*3;
+ eP[4] = __eG - (tG*15);
+ __eG = nG;
+ } else {
+ __eG = eP[4];
+ eP[1] = eP[-2] = eP[4] = 0;
+ }
+
+ __eB = __wantB - __dB;
+ if (__eB) {
+ tB = __eB >> 4;
+ nB = eP[5] + (tB * 7);
+ eP[2] = tB*5;
+ eP[-1] = tB*3;
+ eP[5] = __eB - (tB*15);
+ __eB = nB;
+ } else {
+ __eB = eP[5];
+ eP[2] = eP[-1] = eP[5] = 0;
+ }
+
+ eP += 3;
+#endif
+ }
+ }
+ }
+%}.
+ failed ifTrue:[
+ self primitiveFailed.
+ ^ nil
+ ].
+
+ ^ pseudoBits
+!
+
orderedDitheredBitsDepth:depth
"return the bitmap for a dithered depth-bitmap from the image"
@@ -7780,6 +8304,6 @@
!Image class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libview/Image.st,v 1.111 1996-06-21 17:48:43 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libview/Image.st,v 1.112 1996-06-22 14:54:04 cg Exp $'
! !
Image initialize!