Depth8Image.st
changeset 3906 f77d3b42614a
parent 3900 2ee04532b466
child 4405 f4c62bb63035
equal deleted inserted replaced
3905:bc5f7af0d9d9 3906:f77d3b42614a
  1060 
  1060 
  1061     "Created: / 29.7.1998 / 00:21:25 / cg"
  1061     "Created: / 29.7.1998 / 00:21:25 / cg"
  1062 ! !
  1062 ! !
  1063 
  1063 
  1064 !Depth8Image methodsFor:'dither helpers'!
  1064 !Depth8Image methodsFor:'dither helpers'!
       
  1065 
       
  1066 floydSteinbergDitheredDepth8BitsColors:colors map:aMapOrNil
       
  1067     "return a floyd-steinberg dithered bitmap from the receiver picture,
       
  1068      which must be a depth-8 image. 
       
  1069      This method expects an array of colors to be used for dithering
       
  1070      (which need not be a colorCubes colors)."
       
  1071 
       
  1072     |pseudoBits  
       
  1073      rgbBytes 
       
  1074      ditherRGBBytes ditherColors
       
  1075      w       "{Class: SmallInteger }"
       
  1076      h       "{Class: SmallInteger }"
       
  1077      index   "{Class: SmallInteger }"
       
  1078      ditherIds failed lastColor qScramble
       
  1079      clrLookup lookupPos
       
  1080      error clr|
       
  1081 
       
  1082     "/
       
  1083     "/ collect color components as integer values (for integer arithmetic)
       
  1084     "/
       
  1085     rgbBytes := ByteArray uninitializedNew:256 * 3.
       
  1086 
       
  1087     photometric == #palette ifTrue:[
       
  1088         lastColor := colorMap size - 1
       
  1089     ] ifFalse:[
       
  1090         lastColor := 255.
       
  1091     ].
       
  1092     index := 1.
       
  1093     0 to:lastColor do:[:pix |
       
  1094         clr := self colorFromValue:pix.
       
  1095         rgbBytes at:index put:(clr redByte).
       
  1096         rgbBytes at:index+1 put:(clr greenByte).
       
  1097         rgbBytes at:index+2 put:(clr blueByte).
       
  1098 
       
  1099         index := index + 3.
       
  1100     ].
       
  1101 
       
  1102     "/ collect valid ditherColors ...
       
  1103     aMapOrNil isNil ifTrue:[
       
  1104         ditherColors := colors select:[:clr | clr notNil].
       
  1105     ] ifFalse:[
       
  1106         ditherColors := colors
       
  1107     ].
       
  1108 
       
  1109     "/ ... and sort by manhatten distance from black
       
  1110 
       
  1111     qScramble := #(
       
  1112                 "/  2rX00X00X00X00
       
  1113 
       
  1114                     2r000000000000    "/ 0
       
  1115                     2r000000000100    "/ 1
       
  1116                     2r000000100000    "/ 2
       
  1117                     2r000000100100    "/ 3
       
  1118                     2r000100000000    "/ 4
       
  1119                     2r000100000100    "/ 5
       
  1120                     2r000100100000    "/ 6
       
  1121                     2r000100100100    "/ 7
       
  1122                     2r100000000000    "/ 8
       
  1123                     2r100000000100    "/ 9
       
  1124                     2r100000100000    "/ a
       
  1125                     2r100000100100    "/ b
       
  1126                     2r100100000000    "/ c
       
  1127                     2r100100000100    "/ d
       
  1128                     2r100100100000    "/ e
       
  1129                     2r100100100100    "/ f
       
  1130                   ).
       
  1131 
       
  1132     ditherColors := ditherColors sort:[:a :b |
       
  1133                                 |cr "{Class: SmallInteger }"
       
  1134                                  cg "{Class: SmallInteger }"
       
  1135                                  cb "{Class: SmallInteger }"
       
  1136                                  i1 "{Class: SmallInteger }"
       
  1137                                  i2 "{Class: SmallInteger }"|
       
  1138 
       
  1139                                 cr := a redByte.
       
  1140                                 cg := a greenByte.
       
  1141                                 cb := a blueByte.
       
  1142                                 i1 := qScramble at:((cr bitShift:-4) bitAnd:16r0F) + 1.
       
  1143                                 i1 := i1 + ((qScramble at:((cg bitShift:-4) bitAnd:16r0F) + 1) bitShift:-1).
       
  1144                                 i1 := i1 + ((qScramble at:((cb bitShift:-4) bitAnd:16r0F) + 1) bitShift:-2).
       
  1145 
       
  1146                                 cr := b redByte.
       
  1147                                 cg := b greenByte.
       
  1148                                 cb := b blueByte.
       
  1149                                 i2 := qScramble at:((cr bitShift:-4) bitAnd:16r0F) + 1.
       
  1150                                 i2 := i2 + ((qScramble at:((cg bitShift:-4) bitAnd:16r0F) + 1) bitShift:-1).
       
  1151                                 i2 := i2 + ((qScramble at:((cb bitShift:-4) bitAnd:16r0F) + 1) bitShift:-2).
       
  1152 
       
  1153                                 i1 < i2
       
  1154                     ].
       
  1155     aMapOrNil isNil ifTrue:[
       
  1156         ditherIds := (ditherColors asArray collect:[:clr | clr colorId]) asByteArray.
       
  1157     ] ifFalse:[
       
  1158         ditherIds := aMapOrNil asByteArray
       
  1159     ].
       
  1160 
       
  1161     "/ build an index table, for fast lookup from manhatten-r-g-b distance
       
  1162     "/ to the position in the colorList
       
  1163 
       
  1164     clrLookup := ByteArray new:(4096).
       
  1165     index := 0.
       
  1166     ditherColors keysAndValuesDo:[:clrPosition :clr |
       
  1167         |r g b i|
       
  1168 
       
  1169         r := clr redByte.
       
  1170         g := clr greenByte.
       
  1171         b := clr blueByte.
       
  1172         i := qScramble at:((r bitShift:-4) bitAnd:16r0F) + 1.
       
  1173         i := i + ((qScramble at:((g bitShift:-4) bitAnd:16r0F) + 1) bitShift:-1).
       
  1174         i := i + ((qScramble at:((b bitShift:-4) bitAnd:16r0F) + 1) bitShift:-2).
       
  1175         lookupPos := i.
       
  1176 
       
  1177         [index < lookupPos] whileTrue:[        
       
  1178             clrLookup at:(index+1) put:(clrPosition-1-1).
       
  1179             index := index + 1
       
  1180         ]
       
  1181     ].
       
  1182     clrLookup from:index+1 to:4096 put:(ditherColors size - 1).
       
  1183 
       
  1184 "/    [index <= (4095)] whileTrue:[
       
  1185 "/        clrLookup at:(index+1) put:(ditherColors size - 1).
       
  1186 "/        index := index + 1.
       
  1187 "/    ].
       
  1188 
       
  1189     "/ collect ditherColor components
       
  1190 
       
  1191     lastColor := ditherColors size.
       
  1192     ditherIds := ByteArray uninitializedNew:lastColor.
       
  1193     ditherRGBBytes := ByteArray uninitializedNew:(lastColor * 3).
       
  1194     index := 1.
       
  1195     1 to:lastColor do:[:pix |
       
  1196         clr := ditherColors at:pix.
       
  1197         ditherRGBBytes at:index put:(clr redByte).
       
  1198         ditherRGBBytes at:index+1 put:(clr greenByte).
       
  1199         ditherRGBBytes at:index+2 put:(clr blueByte).
       
  1200         aMapOrNil isNil ifTrue:[
       
  1201             ditherIds at:pix put:clr colorId.
       
  1202         ] ifFalse:[
       
  1203             ditherIds at:pix put:(aMapOrNil at:pix).
       
  1204         ].
       
  1205         index := index + 3.
       
  1206     ].
       
  1207 
       
  1208     pseudoBits := ByteArray uninitializedNew:(width * height).
       
  1209 
       
  1210     w := width + 2.
       
  1211     error := ByteArray uninitializedNew:w*(3*2).
       
  1212 
       
  1213     w := width.
       
  1214     h := height.
       
  1215 
       
  1216     failed := true.
       
  1217 
       
  1218 %{
       
  1219     int __x, __y;
       
  1220     int __eR, __eG, __eB;
       
  1221     unsigned char *srcP, *dstP;
       
  1222     unsigned char *rgbP;
       
  1223     unsigned char *idP;
       
  1224     unsigned char *dp;
       
  1225     unsigned char *__clrLookup;
       
  1226     short *errP, *eP;
       
  1227     int __fR, __fG, __fB;
       
  1228     int iR, iG, iB;
       
  1229     int idx;
       
  1230     int __w = __intVal(w);
       
  1231     int __h = __intVal(h);
       
  1232     int __nColors = __intVal(lastColor);
       
  1233     int __wR = -1, __wG, __wB;
       
  1234     static int __qScramble[16] = {
       
  1235                     0x000 /* 2r000000000000    0 */,
       
  1236                     0x004 /* 2r000000000100    1 */,
       
  1237                     0x020 /* 2r000000100000    2 */,
       
  1238                     0x024 /* 2r000000100100    3 */,
       
  1239                     0x100 /* 2r000100000000    4 */,
       
  1240                     0x104 /* 2r000100000100    5 */,
       
  1241                     0x120 /* 2r000100100000    6 */,
       
  1242                     0x124 /* 2r000100100100    7 */,
       
  1243                     0x800 /* 2r100000000000    8 */,
       
  1244                     0x804 /* 2r100000000100    9 */,
       
  1245                     0x820 /* 2r100000100000    a */,
       
  1246                     0x824 /* 2r100000100100    b */,
       
  1247                     0x900 /* 2r100100000000    c */,
       
  1248                     0x904 /* 2r100100000100    d */,
       
  1249                     0x920 /* 2r100100100000    e */,
       
  1250                     0x924 /* 2r100100100100    f */,
       
  1251                   };
       
  1252 
       
  1253     if (__isByteArray(__INST(bytes))
       
  1254      && __isByteArray(pseudoBits)
       
  1255      && __isByteArray(rgbBytes)
       
  1256      && __isByteArray(ditherRGBBytes)
       
  1257      && __isByteArray(ditherIds)
       
  1258      && __isByteArray(clrLookup)
       
  1259      && __isByteArray(error)) {
       
  1260         failed = false;
       
  1261 
       
  1262         srcP = __ByteArrayInstPtr(_INST(bytes))->ba_element;
       
  1263         dstP = __ByteArrayInstPtr(pseudoBits)->ba_element;
       
  1264         rgbP = __ByteArrayInstPtr(rgbBytes)->ba_element;
       
  1265         idP = __ByteArrayInstPtr(ditherIds)->ba_element;
       
  1266         __clrLookup = __ByteArrayInstPtr(clrLookup)->ba_element;
       
  1267         errP = (short *) __ByteArrayInstPtr(error)->ba_element;
       
  1268 
       
  1269         /*
       
  1270          * clear error accumulator
       
  1271          */
       
  1272         eP = errP;
       
  1273         bzero(eP, (__w+2) * 2 * 3);
       
  1274 
       
  1275         for (__y=__h; __y>0; __y--) {
       
  1276             __eR = __eG = __eB = 0;
       
  1277 
       
  1278             eP = &(errP[3]);
       
  1279             __eR = eP[0];
       
  1280             __eG = eP[1];
       
  1281             __eB = eP[2];
       
  1282 
       
  1283             for (__x=__w; __x>0; __x--) {
       
  1284                 int __want;
       
  1285                 int pix;
       
  1286                 int __wantR, __wantG, __wantB;
       
  1287                 int idx;
       
  1288                 int tR, tG, tB;
       
  1289                 int nR, nG, nB;
       
  1290                 int dR, dG, dB;
       
  1291                 int minDelta, bestIdx;
       
  1292                 int cnt;
       
  1293 
       
  1294                 pix = *srcP++;
       
  1295 
       
  1296                 /*
       
  1297                  * wR, wG and wB is the wanted r/g/b value;
       
  1298                  */
       
  1299                 idx = pix+pix+pix;  /* pix * 3 */
       
  1300 
       
  1301                 __wantR = rgbP[idx] + __eR;
       
  1302                 __wantG = rgbP[idx+1] + __eG;
       
  1303                 __wantB = rgbP[idx+2] + __eB;
       
  1304 
       
  1305 #define RED_SCALE 30
       
  1306 #define GREEN_SCALE 59
       
  1307 #define BLUE_SCALE 11
       
  1308 #define GOOD_DELTA 30
       
  1309 
       
  1310 #define xRED_SCALE 1
       
  1311 #define xGREEN_SCALE 1
       
  1312 #define xBLUE_SCALE 1
       
  1313 #define xGOOD_DELTA 3
       
  1314 
       
  1315 #define FAST_LOOKUP
       
  1316 /* #define ONE_SHOT */
       
  1317 #define NPROBE 8
       
  1318 
       
  1319 #ifndef FAST_LOOKUP
       
  1320                 if ((__wantR == __wR)
       
  1321                  && (__wantG == __wG)
       
  1322                  && (__wantB == __wB)) {
       
  1323                     /*
       
  1324                      * same color again - reuse last bestMatch
       
  1325                      */
       
  1326                 } else 
       
  1327 #endif
       
  1328                 {
       
  1329                     __wR = __wantR;
       
  1330                     __wG = __wantG;
       
  1331                     __wB = __wantB;
       
  1332 
       
  1333 #ifdef FAST_LOOKUP
       
  1334                     if(__wR > 255) __wR = 255;
       
  1335                     else if (__wR < 0) __wR = 0;
       
  1336                     if(__wG > 255) __wG = 255;
       
  1337                     else if (__wG < 0) __wG = 0;
       
  1338                     if(__wB > 255) __wB = 255;
       
  1339                     else if (__wB < 0) __wB = 0;
       
  1340 
       
  1341                     {
       
  1342                         int lookupIndex;
       
  1343                         int idx, idx0;
       
  1344                         int d, delta;
       
  1345                         unsigned char *dp0;
       
  1346 
       
  1347                         dp = __ByteArrayInstPtr(ditherRGBBytes)->ba_element;
       
  1348                         lookupIndex =    __qScramble[((__wR & 0xF0)>>4)];
       
  1349                         lookupIndex |=   __qScramble[((__wG & 0xF0)>>4)] >> 1;
       
  1350                         lookupIndex |=   __qScramble[((__wB & 0xF0)>>4)] >> 2;
       
  1351                         idx = bestIdx =__clrLookup[lookupIndex];
       
  1352                         dp += (idx+idx+idx);
       
  1353 
       
  1354                         /* try color at lookupIndex */
       
  1355 
       
  1356                         d = dp[0];
       
  1357                         delta = (__wR - d) * RED_SCALE;
       
  1358                         if (delta < 0) delta = -delta;
       
  1359 
       
  1360                         d = dp[1];
       
  1361                         if (__wG > d) 
       
  1362                             delta += (__wG - d) * GREEN_SCALE;
       
  1363                         else 
       
  1364                             delta += (d - __wG) * GREEN_SCALE;
       
  1365                         d = dp[2];
       
  1366                         if (__wB > d) 
       
  1367                             delta += (__wB - d) * BLUE_SCALE;
       
  1368                         else 
       
  1369                             delta += (d - __wB) * BLUE_SCALE;
       
  1370 
       
  1371                         if (delta <= GOOD_DELTA) {
       
  1372                             goto foundBest;
       
  1373                         }
       
  1374                         minDelta = delta;
       
  1375 # ifndef ONE_SHOT
       
  1376                         idx0 = idx; dp0 = dp;
       
  1377                         cnt = 0;
       
  1378                         while ((++cnt <= NPROBE) && (idx > 0)) {
       
  1379                             /* try previous color(s) */
       
  1380 
       
  1381                             idx--; dp -= 3;
       
  1382                             d = dp[0];
       
  1383                             delta = (__wR - d) * RED_SCALE;
       
  1384                             if (delta < 0) delta = -delta;
       
  1385                             d = dp[1];
       
  1386                             if (__wG > d) 
       
  1387                                 delta += (__wG - d) * GREEN_SCALE;
       
  1388                             else 
       
  1389                                 delta += (d - __wG) * GREEN_SCALE;
       
  1390                             d = dp[2];
       
  1391                             if (__wB > d) 
       
  1392                                 delta += (__wB - d) * BLUE_SCALE;
       
  1393                             else 
       
  1394                                 delta += (d - __wB) * BLUE_SCALE;
       
  1395 
       
  1396                             if (delta < minDelta) {
       
  1397                                 bestIdx = idx;
       
  1398                                 if (delta <= GOOD_DELTA) {
       
  1399                                     goto foundBest;
       
  1400                                 }
       
  1401                                 minDelta = delta;
       
  1402                             }
       
  1403                         }
       
  1404 
       
  1405                         idx = idx0; dp = dp0;
       
  1406                         cnt = 0;
       
  1407                         while ((++cnt <= NPROBE) && (++idx < __nColors)) {
       
  1408                             /* try next color */
       
  1409 
       
  1410                             dp += 3;
       
  1411                             d = dp[0];
       
  1412                             delta = (__wR - d) * RED_SCALE;
       
  1413                             if (delta < 0) delta = -delta;
       
  1414                             d = dp[1];
       
  1415                             if (__wG > d) 
       
  1416                                 delta += (__wG - d) * GREEN_SCALE;
       
  1417                             else 
       
  1418                                 delta += (d - __wG) * GREEN_SCALE;
       
  1419                             d = dp[2];
       
  1420                             if (__wB > d) 
       
  1421                                 delta += (__wB - d) * BLUE_SCALE;
       
  1422                             else 
       
  1423                                 delta += (d - __wB) * BLUE_SCALE;
       
  1424 
       
  1425                             if (delta < minDelta) {
       
  1426                                 bestIdx = idx;
       
  1427                                 if (delta <= GOOD_DELTA) {
       
  1428                                     goto foundBest;
       
  1429                                 }
       
  1430                                 minDelta = delta;
       
  1431                             }
       
  1432                         }
       
  1433 # endif
       
  1434                     }
       
  1435         foundBest: ;
       
  1436 #else
       
  1437 /*
       
  1438                     if(__wR > 255) __wR = 255;
       
  1439                     else if (__wR < 0) __wR = 0;
       
  1440                     if(__wG > 255) __wG = 255;
       
  1441                     else if (__wG < 0) __wG = 0;
       
  1442                     if(__wB > 255) __wB = 255;
       
  1443                     else if (__wB < 0) __wB = 0;
       
  1444 */
       
  1445 
       
  1446                     /* find the best matching color */
       
  1447 
       
  1448                     minDelta = 99999;
       
  1449                     bestIdx = -1;
       
  1450                     dp = __ByteArrayInstPtr(ditherRGBBytes)->ba_element;
       
  1451                     for (idx = 0; idx<__nColors; idx++) {
       
  1452                         int d, delta;
       
  1453 
       
  1454                         d = dp[0];
       
  1455                         delta = (__wR - d) * RED_SCALE;
       
  1456                         if (delta < 0) delta = -delta;
       
  1457                         if (delta < minDelta) {
       
  1458                             d = dp[1];
       
  1459                             if (__wG > d) 
       
  1460                                 delta += (__wG - d) * GREEN_SCALE;
       
  1461                             else 
       
  1462                                 delta += (d - __wG) * GREEN_SCALE;
       
  1463                             if (delta < minDelta) {
       
  1464                                 d = dp[2];
       
  1465                                 if (__wB > d) 
       
  1466                                     delta += (__wB - d) * BLUE_SCALE;
       
  1467                                 else 
       
  1468                                     delta += (d - __wB) * BLUE_SCALE;
       
  1469 
       
  1470                                 if (delta < minDelta) {
       
  1471                                     bestIdx = idx;
       
  1472                                     if (delta <= GOOD_DELTA) {
       
  1473                                         break;
       
  1474                                     }
       
  1475                                     minDelta = delta;
       
  1476                                 }
       
  1477                             }
       
  1478                         }
       
  1479                         dp += 3;
       
  1480                     }
       
  1481 #endif
       
  1482                 }
       
  1483                 dp = __ByteArrayInstPtr(ditherRGBBytes)->ba_element;
       
  1484                 dp += bestIdx * 3;
       
  1485                 dR = dp[0];
       
  1486                 dG = dp[1];
       
  1487                 dB = dp[2];
       
  1488 
       
  1489 /*
       
  1490 printf("want: %d/%d/%d (%d/%d/%d) got: %d/%d/%d\n",
       
  1491                 __wantR, __wantG, __wantB,
       
  1492                 __wR, __wG, __wB,
       
  1493                 dR, dG, dB);
       
  1494 */
       
  1495                 /*
       
  1496                  * store the corresponding dither colors colorId
       
  1497                  */
       
  1498                 *dstP++ = idP[bestIdx];
       
  1499 
       
  1500                 /*
       
  1501                  * the new error & distribute the error
       
  1502                  */
       
  1503                 __eR = __wantR - dR; 
       
  1504                 if (__eR) {
       
  1505                     tR = __eR >> 4;  /* 16th of error */
       
  1506                     nR = eP[3] + (tR * 7);/* from accu: error for (x+1 / y) */
       
  1507                     eP[0] = tR*5;         /* 5/16th for (x / y+1) */
       
  1508                     eP[-3] = tR*3;        /* 3/16th for (x-1 / y+1) */
       
  1509                     eP[3] = __eR - (tR*15);  /* 1/16th for (x+1 / y+1) */
       
  1510                     __eR = nR;
       
  1511                 } else {
       
  1512                     __eR = eP[3];
       
  1513                     eP[0] = eP[-3] = eP[3] = 0;
       
  1514                 }
       
  1515 
       
  1516                 __eG = __wantG - dG;
       
  1517                 if (__eG) {
       
  1518                     tG = __eG >> 4;
       
  1519                     nG = eP[4] + (tG * 7);/* plus 7/16'th of this error */
       
  1520                     eP[1] = tG*5;
       
  1521                     eP[-2] = tG*3;
       
  1522                     eP[4] = __eG - (tG*15);
       
  1523                     __eG = nG;
       
  1524                 } else {
       
  1525                     __eG = eP[4];
       
  1526                     eP[1] = eP[-2] = eP[4] = 0;
       
  1527                 }
       
  1528 
       
  1529                 __eB = __wantB - dB; 
       
  1530                 if (__eB) {
       
  1531                     tB = __eB >> 4;
       
  1532                     nB = eP[5] + (tB * 7);
       
  1533                     eP[2] = tB*5;
       
  1534                     eP[-1] = tB*3;
       
  1535                     eP[5] = __eB - (tB*15);
       
  1536                     __eB = nB;
       
  1537                 } else {
       
  1538                     __eB = eP[5];
       
  1539                     eP[2] = eP[-1] = eP[5] = 0;
       
  1540                 }
       
  1541 
       
  1542                 eP += 3;
       
  1543             }
       
  1544         }
       
  1545     }
       
  1546 %}.
       
  1547     failed ifTrue:[
       
  1548         self primitiveFailed.
       
  1549         ^ nil
       
  1550     ].
       
  1551 
       
  1552     ^ pseudoBits
       
  1553 !
  1065 
  1554 
  1066 orderedDitheredGrayBitsWithDitherMatrix:ditherMatrix ditherWidth:dW depth:depth
  1555 orderedDitheredGrayBitsWithDitherMatrix:ditherMatrix ditherWidth:dW depth:depth
  1067     "return the bitmap for a dithered depth-bitmap from the image;
  1556     "return the bitmap for a dithered depth-bitmap from the image;
  1068      with a constant ditherMatrix, this can be used for thresholding.
  1557      with a constant ditherMatrix, this can be used for thresholding.
  1069      Redefined to make use of knowing that pixels are 8-bit values."
  1558      Redefined to make use of knowing that pixels are 8-bit values."
  1953 ! !
  2442 ! !
  1954 
  2443 
  1955 !Depth8Image class methodsFor:'documentation'!
  2444 !Depth8Image class methodsFor:'documentation'!
  1956 
  2445 
  1957 version
  2446 version
  1958     ^ '$Header: /cvs/stx/stx/libview/Depth8Image.st,v 1.105 2003-06-28 22:21:44 cg Exp $'
  2447     ^ '$Header: /cvs/stx/stx/libview/Depth8Image.st,v 1.106 2003-07-02 17:31:27 cg Exp $'
  1959 ! !
  2448 ! !