--- a/Image.st Sat Jun 08 15:36:53 1996 +0200
+++ b/Image.st Mon Jun 10 15:21:51 1996 +0200
@@ -304,6 +304,46 @@
inspect
[exEnd]
+ a 2/2/0 rgb image (i.e. no blue):
+ [exBegin]
+ |i|
+
+ i := Depth4Image
+ width:4
+ height:4
+ fromArray:#[ 16r01 16r23
+ 16r45 16r67
+ 16r89 16rab
+ 16rcd 16ref ].
+ i photometric:#rgb.
+ i samplesPerPixel:3.
+ i bitsPerSample:#(2 2 0).
+
+ i := i magnifiedBy:30.
+ i inspect.
+ [exEnd]
+
+
+ a 0/0/4 rgb image (i.e. no red or green):
+ [exBegin]
+ |i|
+
+ i := Depth4Image
+ width:4
+ height:4
+ fromArray:#[ 16r01 16r23
+ 16r45 16r67
+ 16r89 16rab
+ 16rcd 16ref ].
+ i photometric:#rgb.
+ i samplesPerPixel:3.
+ i bitsPerSample:#(0 0 4).
+
+ i := i magnifiedBy:30.
+ i inspect.
+ [exEnd]
+
+
a 2plane greyscale image:
[exBegin]
((Depth2Image
@@ -429,8 +469,15 @@
Lobby := Registry new.
ObjectMemory addDependent:self.
- "define algorithm to use for dithering - currently only nil or #pattern supported"
- DitherAlgorithm := #pattern. "will be changed to error as soon as implemented"
+ "/ define the algorithm to use for dithering -
+ "/ supported values are:
+ "/ #threshold
+ "/ #ordered
+ "/ #floydSteinberg
+ "/ #burkes
+
+ DitherAlgorithm := #floydSteinberg.
+
(Display notNil and:[Display hasGrayscales]) ifFalse:[
NumberOfDitherColors := 64
] ifTrue:[
@@ -446,7 +493,7 @@
CollectGarbageWhenRunningOutOfColors := false
]
- "Modified: 28.5.1996 / 21:12:30 / cg"
+ "Modified: 10.6.1996 / 12:28:22 / cg"
!
initializeFileFormatTable
@@ -738,7 +785,7 @@
inStream isNil ifTrue:[
inStream := Smalltalk bitmapFileStreamFor:name.
inStream isNil ifTrue:[
- ('IMAGE: ' , aFileName , ' does not exist or is not readable') infoPrintNL.
+ ('IMAGE: ' , aFileName , ' does not exist or is not readable') infoPrintCR.
^ nil
].
name := 'bitmaps/' , name.
@@ -810,21 +857,28 @@
Image fromFile:'bitmaps/hello_world.icon'
"
- "Modified: 7.3.1996 / 19:18:13 / cg"
+ "Modified: 10.6.1996 / 14:36:18 / cg"
! !
!Image class methodsFor:'misc'!
dither:aSymbol
- "define how to dither - #pattern, #error or none;
- error diffusion dithering is currently not implemented,
- pattern dither is currently very slow."
+ "define how to dither -
+ #threshold, or nil -> no dither
+ #pattern, or #ordered -> orderedDither (ugly, but fast)
+ #error or #floydSteinberg -> errorDiffusion; much better
+ #burkes -> errorDiffusion; even better."
DitherAlgorithm := aSymbol
- "Image dither:#pattern"
- "Image dither:#error"
- "Image dither:nil"
+ "
+ Image dither:#pattern
+ Image dither:#floydSteinberg
+ Image dither:#burkes
+ Image dither:nil
+ "
+
+ "Modified: 10.6.1996 / 12:27:09 / cg"
!
numberOfDitherColors:n
@@ -1498,6 +1552,57 @@
!Image methodsFor:'converting'!
+asBurkesDitheredMonochromeImage
+ "return a burkes dithered monochrome image from the receiver image."
+
+ |monoBits|
+
+ monoBits := self burkesDitheredMonochromeBits.
+ ^ (Depth1Image width:width height:height fromArray:monoBits) photometric:#blackIs0
+
+ "
+ |i|
+
+ i := Image fromFile:'garfield.gif'.
+ i inspect.
+ i asFloydSteinbergDitheredMonochromeImage inspect.
+ i asBurkesDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "
+ |i|
+
+ i := Image fromFile:'claus.gif'.
+ i inspect.
+ i asFloydSteinbergDitheredMonochromeImage inspect.
+ i asBurkesDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "
+ |i|
+
+ i := Depth4Image
+ width:4
+ height:4
+ fromArray:#[
+ 16r01 16r23
+ 16r45 16r67
+ 16r89 16rab
+ 16rcd 16ref
+ ].
+ i := i magnifiedBy:30.
+ i inspect.
+ i asFloydSteinbergDitheredMonochromeImage inspect.
+ i asBurkesDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "Modified: 10.6.1996 / 12:18:32 / cg"
+ "Created: 10.6.1996 / 12:34:44 / cg"
+!
+
asCachedImage
"return the receiver associated to the current screens device.
For ST-80 compatibility
@@ -1508,6 +1613,270 @@
"Modified: 23.4.1996 / 11:10:32 / cg"
!
+asErrorDitheredMonochromeImage
+ "return an error-diffusion dithered monochrome image from the receiver image."
+
+ DitherAlgorithm == #burkes ifTrue:[
+ ^ self asBurkesDitheredMonochromeImage
+ ].
+ DitherAlgorithm == #stevensonArce ifTrue:[
+ ^ self asStevensonArgceDitheredMonochromeImage
+ ].
+ ^ self asFloydSteinbergDitheredMonochromeImage
+
+ "
+ |i|
+
+ i := Image fromFile:'garfield.gif'.
+ i inspect.
+ i asErrorDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "
+ |i|
+
+ i := Image fromFile:'claus.gif'.
+ i inspect.
+ i asErrorDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "
+ |i|
+
+ i := Depth4Image
+ width:4
+ height:4
+ fromArray:#[
+ 16r01 16r23
+ 16r45 16r67
+ 16r89 16rab
+ 16rcd 16ref
+ ].
+ i := i magnifiedBy:30.
+ i inspect.
+ i asErrorDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "Modified: 10.6.1996 / 14:22:30 / cg"
+!
+
+asFloydSteinbergDitheredGrayFormOn:aDevice
+ "return a dithered depth-x grey form from the receiver image."
+
+ |f depth bits|
+
+ depth := aDevice depth.
+ depth == 1 ifTrue:[
+ "/ for monochrome, there is specialized
+ "/ monochrome dither code available
+
+ bits := self floydSteinbergDitheredMonochromeBits.
+ ] ifFalse:[
+ bits := self floydSteinbergDitheredBitsDepth:depth.
+ ].
+
+ f := Form width:width height:height depth:depth.
+ f bits:bits.
+ ^ f on:aDevice
+
+ "
+ |i f|
+
+ i := Image fromFile:'bitmaps/claus.gif'.
+ f := i asFloydSteinbergDitheredGrayFormOn:Display.
+ "
+
+ "Modified: 8.6.1996 / 15:29:51 / cg"
+ "Created: 10.6.1996 / 14:11:39 / cg"
+!
+
+asFloydSteinbergDitheredGrayImageDepth:depth
+ "return a floyd-steinberg dithered image from the receiver image."
+
+ |ditheredBits|
+
+ depth == 1 ifTrue:[
+ ^ self asFloydSteinbergDitheredMonochromeImage
+ ].
+
+ ditheredBits := self floydSteinbergDitheredBitsDepth:depth.
+ ^ (self class implementorForDepth:depth)
+ width:width height:height fromArray:ditheredBits
+
+ "
+ |i|
+
+ i := Image fromFile:'garfield.gif'.
+ i inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:1) inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:2) inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:4) inspect.
+ "
+
+ "
+ |i|
+
+ i := Image fromFile:'claus.gif'.
+ i inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:1) inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:2) inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:4) inspect.
+ "
+
+ "
+ |i|
+
+ i := Depth4Image
+ width:4
+ height:4
+ fromArray:#[
+ 16r01 16r23
+ 16r45 16r67
+ 16r89 16rab
+ 16rcd 16ref
+ ].
+ i := i magnifiedBy:30.
+ i inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:1) inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:2) inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:4) inspect.
+ "
+
+ "Created: 10.6.1996 / 12:33:47 / cg"
+ "Modified: 10.6.1996 / 14:40:26 / cg"
+!
+
+asFloydSteinbergDitheredGreyImageDepth:depth
+ "return a floyd-steinberg dithered image from the receiver image."
+
+ |ditheredBits|
+
+ depth == 1 ifTrue:[
+ ^ self asFloydSteinbergDitheredMonochromeImage
+ ].
+
+ ditheredBits := self floydSteinbergDitheredBitsDepth:depth.
+ ditheredBits isNil ifTrue:[
+ ^ nil
+ ].
+ ^ (self class implementorForDepth:depth)
+ width:width height:height fromArray:ditheredBits
+
+ "
+ |i|
+
+ i := Image fromFile:'bitmaps/red-ball.gif'.
+ i inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:1) inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:2) inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:4) inspect.
+ "
+
+ "
+ |i|
+
+ i := Image fromFile:'claus.gif'.
+ i inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:1) inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:2) inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:4) inspect.
+
+ |i|
+
+ i := Image fromFile:'claus.gif'.
+ i inspect.
+ (i asOrderedDitheredGrayImageDepth:1) inspect.
+ (i asOrderedDitheredGrayImageDepth:2) inspect.
+ (i asOrderedDitheredGrayImageDepth:4) inspect.
+ "
+
+ "
+ |i|
+
+ i := Image fromFile:'bitmaps/granite.tiff'.
+ i inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:1) inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:2) inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:4) inspect.
+ "
+
+ "
+ |i|
+
+ i := Depth4Image
+ width:4
+ height:4
+ fromArray:#[
+ 16r01 16r23
+ 16r45 16r67
+ 16r89 16rab
+ 16rcd 16ref
+ ].
+ i := i magnifiedBy:30.
+ i inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:1) inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:2) inspect.
+ (i asFloydSteinbergDitheredGreyImageDepth:4) inspect.
+ "
+
+ "Created: 10.6.1996 / 12:33:47 / cg"
+ "Modified: 10.6.1996 / 15:09:50 / cg"
+!
+
+asFloydSteinbergDitheredMonochromeImage
+ "return a floyd-steinberg dithered monochrome image from the receiver image."
+
+ |monoBits|
+
+ monoBits := self floydSteinbergDitheredMonochromeBits.
+ ^ (Depth1Image width:width height:height fromArray:monoBits) photometric:#blackIs0
+
+ "
+ |i|
+
+ i := Image fromFile:'garfield.gif'.
+ i inspect.
+ i asFloydSteinbergDitheredMonochromeImage inspect.
+ i asBurkesDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "
+ |i|
+
+ i := Image fromFile:'claus.gif'.
+ i inspect.
+ i asFloydSteinbergDitheredMonochromeImage inspect.
+ i asBurkesDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "
+ |i|
+
+ i := Depth4Image
+ width:4
+ height:4
+ fromArray:#[
+ 16r01 16r23
+ 16r45 16r67
+ 16r89 16rab
+ 16rcd 16ref
+ ].
+ i := i magnifiedBy:30.
+ i inspect.
+ i asFloydSteinbergDitheredMonochromeImage inspect.
+ i asBurkesDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "Created: 10.6.1996 / 12:33:47 / cg"
+ "Modified: 10.6.1996 / 12:47:20 / cg"
+!
+
asFormOn:aDevice
"get a device form, with best possible approximation.
remember it in case someone asks again."
@@ -1587,132 +1956,6 @@
^ form
!
-asOrderedDitheredDepth2GrayImage
- "return a dithered depth2 grey image from the receiver image.
- Uses an 8x8 dithermatrix."
-
- ^ Depth2Image
- width:width
- height:height
- fromArray:(
- self
- orderedDitheredBitsWithDitherMatrix:(self class orderedDitherMatrixOfSize:8)
- ditherWidth:8
- depth:2)
-
- "
- |i i2|
-
- i := Image fromFile:'bitmaps/claus.gif'.
- i2 := i asOrderedDitheredDepth2GrayImage
-
-
- |i i2|
-
- i := (Image fromFile:'/cdrom/icons/a/a11.ico') magnifiedBy:10.
- i2 := i asOrderedDitheredDepth2GrayImage
-
-
- |i i2|
-
- i := Image fromFile:'bitmaps/garfield.gif'.
- i2 := i asOrderedDitheredDepth2GrayImage
-
-
- |i i2|
-
- i := (Image fromFile:'bitmaps/PasteButton.tiff') magnifiedBy:10.
- i2 := i asOrderedDitheredDepth2GrayImage
-
-
- |i i2|
-
- i := (Image fromFile:'bitmaps/blue-ball.gif') magnifiedBy:1.
- i2 := i asOrderedDitheredDepth2GrayImage
-
-
- |i i2|
-
- i := Image fromFile:'bitmaps/granite.tiff'.
- i2 := i asOrderedDitheredDepth2GrayImage
- "
-
- "Modified: 7.6.1996 / 17:59:15 / cg"
- "Created: 7.6.1996 / 18:03:54 / cg"
-!
-
-asOrderedDitheredDepth4GrayImage
- "return a dithered depth4 gray image from the receiver image.
- Uses an 8x8 dithermatrix."
-
- ^ Depth4Image
- width:width
- height:height
- fromArray:(
- self
- orderedDitheredBitsWithDitherMatrix:(self class orderedDitherMatrixOfSize:8)
- ditherWidth:8
- depth:4)
-
- "
- |i i2|
-
- i := Image fromFile:'bitmaps/claus.gif'.
- i2 := i asOrderedDitheredDepth4GrayImage
-
-
- |i i2|
-
- i := (Image fromFile:'/cdrom/icons/a/a11.ico') magnifiedBy:10.
- i2 := i asOrderedDitheredDepth4GrayImage
-
-
- |i i2|
-
- i := Image fromFile:'bitmaps/garfield.gif'.
- i2 := i asOrderedDitheredDepth4GrayImage
-
-
- |i i2|
-
- i := (Image fromFile:'bitmaps/PasteButton.tiff') magnifiedBy:10.
- i2 := i asOrderedDitheredDepth4GrayImage
-
-
- |i i2|
-
- i := (Image fromFile:'bitmaps/blue-ball.gif') magnifiedBy:1.
- i2 := i asOrderedDitheredDepth4GrayImage
-
-
- |i i2|
-
- i := Image fromFile:'bitmaps/granite.tiff'.
- i2 := i asOrderedDitheredDepth4GrayImage
- "
-
- "Modified: 7.6.1996 / 16:58:34 / cg"
- "Created: 7.6.1996 / 18:03:04 / cg"
-!
-
-asOrderedDitheredDepth8GrayImage
- "return a dithered depth8 grey image from the receiver image.
- Uses an 8x8 dithermatrix.
- This is provided for protocol completeness - 8bit grey images are
- usually not dithered at all."
-
- ^ Depth8Image
- width:width
- height:height
- fromArray:(
- self
- orderedDitheredBitsWithDitherMatrix:(self class orderedDitherMatrixOfSize:8)
- ditherWidth:8
- depth:8)
-
- "Modified: 7.6.1996 / 18:08:20 / cg"
-!
-
asOrderedDitheredGrayFormOn:aDevice
"return a dithered depth-x grey form from the receiver image.
Uses an 8x8 dithermatrix."
@@ -1930,44 +2173,44 @@
"/ ditherWidth:8
"
- |i i2|
+ |i|
i := Image fromFile:'bitmaps/claus.gif'.
- i2 := i asOrderedDitheredMonochromeImage
-
-
- |i i2|
+ i asOrderedDitheredMonochromeImage inspect
+
+
+ |i|
i := (Image fromFile:'/cdrom/icons/a/a11.ico') magnifiedBy:10.
- i2 := i asOrderedDitheredMonochromeImage
-
-
- |i i2|
+ i asOrderedDitheredMonochromeImage inspect
+
+
+ |i|
i := Image fromFile:'bitmaps/garfield.gif'.
- i2 := i asOrderedDitheredMonochromeImage
-
-
- |i i2|
+ i asOrderedDitheredMonochromeImage inspect
+
+
+ |i|
i := (Image fromFile:'bitmaps/PasteButton.tiff') magnifiedBy:10.
- i2 := i asOrderedDitheredMonochromeImage
-
-
- |i i2|
+ i asOrderedDitheredMonochromeImage inspect
+
+
+ |i|
i := (Image fromFile:'bitmaps/blue-ball.gif') magnifiedBy:1.
- i2 := i asOrderedDitheredMonochromeImage
-
-
- |i i2|
+ i asOrderedDitheredMonochromeImage inspect
+
+
+ |i|
i := Image fromFile:'bitmaps/granite.tiff'.
- i2 := i asOrderedDitheredMonochromeImage
+ i asOrderedDitheredMonochromeImage inspect
"
"Created: 7.6.1996 / 15:02:07 / cg"
- "Modified: 7.6.1996 / 16:58:34 / cg"
+ "Modified: 10.6.1996 / 11:15:09 / cg"
!
asOrderedDitheredMonochromeImageWithDitherMatrix:ditherMatrix ditherWidth:dW
@@ -2033,6 +2276,58 @@
"Modified: 7.6.1996 / 17:23:47 / cg"
!
+asStevensonArceDitheredMonochromeImage
+ "return a floyd-steinberg dithered monochrome image from the receiver image."
+
+ |monoBits|
+
+ monoBits := self stevensonArceDitheredMonochromeBits.
+ ^ (Depth1Image width:width height:height fromArray:monoBits) photometric:#blackIs0
+
+ "
+ |i|
+
+ i := Image fromFile:'garfield.gif'.
+ i inspect.
+ i asFloydSteinbergDitheredMonochromeImage inspect.
+ i asBurkesDitheredMonochromeImage inspect.
+ i asStevensonArceDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "
+ |i|
+
+ i := Image fromFile:'claus.gif'.
+ i inspect.
+ i asFloydSteinbergDitheredMonochromeImage inspect.
+ i asBurkesDitheredMonochromeImage inspect.
+ i asStevensonArceDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "
+ |i|
+
+ i := Depth4Image
+ width:4
+ height:4
+ fromArray:#[
+ 16r01 16r23
+ 16r45 16r67
+ 16r89 16rab
+ 16rcd 16ref
+ ].
+ i := i magnifiedBy:30.
+ i inspect.
+ i asStevensonArceDitheredMonochromeImage inspect.
+ i asOrderedDitheredMonochromeImage inspect.
+ "
+
+ "Created: 10.6.1996 / 12:38:29 / cg"
+ "Modified: 10.6.1996 / 13:54:14 / cg"
+!
+
asThresholdGrayImageDepth:depth
"return a thresholded depth-x grey image from the receiver image."
@@ -2059,24 +2354,27 @@
depth:depth)
"
- |i i1 i2 i4 i8|
+ |i|
i := Image fromFile:'bitmaps/claus.gif'.
- i1 := i asThresholdGrayImageDepth:1.
- i1 inspect.
-
- i2 := i asThresholdGrayImageDepth:2.
- i2 inspect.
-
- i4 := i asThresholdGrayImageDepth:4.
- i4 inspect.
-
- i8 := i asThresholdGrayImageDepth:8.
- i8 inspect.
+ (i asThresholdGrayImageDepth:1) inspect.
+ (i asThresholdGrayImageDepth:2) inspect.
+ (i asThresholdGrayImageDepth:4) inspect.
+ (i asThresholdGrayImageDepth:8) inspect.
+
+ (i asOrderedDitheredGrayImageDepth:1) inspect.
+ (i asOrderedDitheredGrayImageDepth:2) inspect.
+ (i asOrderedDitheredGrayImageDepth:4) inspect.
+ (i asOrderedDitheredGrayImageDepth:8) inspect.
+
+ (i asFloydSteinbergDitheredGrayImageDepth:1) inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:2) inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:4) inspect.
+ (i asFloydSteinbergDitheredGrayImageDepth:8) inspect.
"
"Created: 7.6.1996 / 18:13:33 / cg"
- "Modified: 7.6.1996 / 19:39:37 / cg"
+ "Modified: 10.6.1996 / 14:20:56 / cg"
!
asThresholdMonochromeFormOn:aDevice
@@ -2243,7 +2541,7 @@
]
].
- "Modified: 23.4.1996 / 11:11:00 / cg"
+ "Modified: 8.6.1996 / 16:02:03 / cg"
!
fromImage:anImage
@@ -2368,215 +2666,6 @@
].
deviceForm := self asFormOn:aDevice.
device := aDevice
-!
-
-orderedDitheredBitsWithDitherMatrix:ditherMatrix ditherWidth:dW depth:depth
- "return the bitmap for a dithered depth-bitmap from the image;
- with a constant ditherMatrix, this can be used for thresholding.
- Works for any source depths / photometric,
- but very very slow since each pixel is processed individually.
- Redefined by some subclasses for more performance (D8Image)"
-
- |f last dH nDither
- greyLevels
- dstIndex "{Class: SmallInteger }"
- nextDst
- bytesPerOutRow "{Class: SmallInteger }"
- pixelsPerByte "{Class: SmallInteger }"
- outBits
- w "{Class: SmallInteger }"
- h "{Class: SmallInteger }"
- bitCnt "{Class: SmallInteger }"
- byte "{Class: SmallInteger }" |
-
- Transcript showCR:'slow ordered dither ..'. Transcript endEntry.
-
- nDither := ditherMatrix size.
- dH := nDither / dW.
-
- w := width.
- h := height.
-
- greyLevels := 1 bitShift:depth.
- pixelsPerByte := 8 / depth.
-
- bytesPerOutRow := (w * depth + 7) // 8.
- outBits := ByteArray uninitializedNew:(bytesPerOutRow * h).
- (outBits isNil or:[bytes isNil]) ifTrue:[
- ^ nil
- ].
-
- dstIndex := 1.
- 0 to:(h-1) do:[:y |
- nextDst := dstIndex + bytesPerOutRow.
- byte := 0.
- bitCnt := 8.
-
- "/ this is the representaion independent (but slow)
- "/ inner loop - it extracts colors from the receiver
-
- self colorsAtY:y from:0 to:(w-1) do:[:x :clr |
- |dstClr grey dT pixel|
-
- "/ get the colors grey value [0 .. 1]
- grey := clr brightness.
-
- "/ remap into [0 .. greyLevels-1]
- grey := grey * (greyLevels-1).
-
- "/ get threshold pixel [0 .. greyLevels-1]
-
- pixel := grey truncated.
-
- "/ compute the error [0..1]
- grey := grey - pixel.
-
- "/ map into dither space [0 .. nDither]
- grey := (grey * (nDither)) rounded.
-
-%{
- int __dW = __intVal(dW);
- int __byte = __intVal(byte);
- int __dT;
- int __dstIdx;
- int __pixel;
- int __bitCnt = __intVal(bitCnt);
-
- __dT = __ByteArrayInstPtr(ditherMatrix)
- ->ba_element[__intVal(x) % __dW
- + (__intVal(y) % __intVal(dH)) * __dW];
-
- __pixel = __intVal(pixel);
-
- if (__intVal(grey) > __dT) {
- __pixel++;
- }
- __byte = (__byte << __intVal(depth)) | __pixel;
-
- __bitCnt = __bitCnt - __intVal(depth);
- if (__bitCnt == 0) {
- __dstIdx = __intVal(dstIndex);
- __ByteArrayInstPtr(outBits)->ba_element[__dstIdx-1] = __byte;
- __dstIdx = __dstIdx + 1;
- dstIndex = __MKSMALLINT(__dstIdx);
- __byte = 0;
- __bitCnt = 8;
- }
- byte = __MKSMALLINT(__byte);
- bitCnt = __MKSMALLINT(__bitCnt);
-%}.
- 0
-
- ].
- bitCnt ~~ 8 ifTrue:[
- byte := byte bitShift:bitCnt.
- outBits at:dstIndex put:byte.
- ].
- dstIndex := nextDst.
- ].
-
- ^ outBits
-!
-
-orderedDitheredMonochromeBitsWithDitherMatrix:ditherMatrix ditherWidth:dW
- "return the bitmap for a dithered monochrome bitmap from the image;
- with a constant ditherMatrix, this can be used for thresholding.
- Works for any source depths / photometric,
- but very very slow since each pixel is processed individually.
- Redefined by some subclasses for more performance (D8Image)"
-
- |f last dH nDither
- clr0 clr1
- dstIndex "{Class: SmallInteger }"
- nextDst
- bytesPerMonoRow "{Class: SmallInteger }"
- monoBits
- w "{Class: SmallInteger }"
- h "{Class: SmallInteger }"
- bitCnt "{Class: SmallInteger }"
- byte "{Class: SmallInteger }" |
-
- Transcript showCR:'slow ordered dither ..'. Transcript endEntry.
-
- nDither := ditherMatrix size.
- dH := nDither / dW.
-
- w := width.
- h := height.
-
- bytesPerMonoRow := (w + 7) // 8.
- monoBits := ByteArray uninitializedNew:(bytesPerMonoRow * h).
- (monoBits isNil or:[bytes isNil]) ifTrue:[
- ^ nil
- ].
-
- dstIndex := 1.
- 0 to:(h-1) do:[:y |
- nextDst := dstIndex + bytesPerMonoRow.
- byte := 0.
- bitCnt := 8.
- self colorsAtY:y from:0 to:(w-1) do:[:x :clr |
- |dstClr grey dT|
-
- "/ get the colors grey value [0 .. 1]
- grey := clr brightness.
-
- "/ map into dither space [0 .. nDither]
- grey := (grey * (nDither)) rounded.
-
-%{
- int __dW = __intVal(dW);
- int __byte = __intVal(byte);
- int __dT;
- int __dstIdx;
- int __bitCnt = __intVal(bitCnt);
-
- __dT = __ByteArrayInstPtr(ditherMatrix)
- ->ba_element[__intVal(x) % __dW
- + (__intVal(y) % __intVal(dH)) * __dW];
-
- __byte = __byte << 1;
- if (__intVal(grey) > __dT) {
- __byte = __byte | 1; /* white */
- }
- __bitCnt = __bitCnt - 1;
- if (__bitCnt == 0) {
- __dstIdx = __intVal(dstIndex);
- __ByteArrayInstPtr(monoBits)->ba_element[__dstIdx-1] = __byte;
- __dstIdx = __dstIdx + 1;
- dstIndex = __MKSMALLINT(__dstIdx);
- __byte = 0;
- __bitCnt = 8;
- }
- byte = __MKSMALLINT(__byte);
- bitCnt = __MKSMALLINT(__bitCnt);
-%}.
- 0
-
-"/ "/ compare
-"/ dT := ditherMatrix at:(x \\ dW) + (y \\ dH * dW) + 1.
-"/
-"/ byte := byte bitShift:1.
-"/ grey < dT ifTrue:[
-"/ byte := byte bitOr:1.
-"/ ].
-"/ bitCnt := bitCnt - 1.
-"/ bitCnt == 0 ifTrue:[
-"/ monoBits at:dstIndex put:byte.
-"/ dstIndex := dstIndex + 1.
-"/ byte := 0.
-"/ bitCnt := 8.
-"/ ].
-
- ].
- bitCnt ~~ 8 ifTrue:[
- byte := byte bitShift:bitCnt.
- monoBits at:dstIndex put:byte.
- ].
- dstIndex := nextDst.
- ].
-
- ^ monoBits
! !
!Image methodsFor:'converting greyscale images'!
@@ -2588,8 +2677,8 @@
nPlanes := samplesPerPixel.
(nPlanes == 2) ifTrue:[
- 'IMAGE: alpha plane ignored' errorPrintNL.
- nPlanes := 1
+ 'IMAGE: alpha plane ignored' errorPrintNL.
+ nPlanes := 1
].
pictureDepth := bitsPerSample at:1.
@@ -2597,70 +2686,70 @@
"monochrome is very easy ..."
(pictureDepth == 1) ifTrue:[
- ^ Form width:width height:height fromArray:bytes on:aDevice
+ ^ Form width:width height:height fromArray:bytes on:aDevice
].
(aDevice visualType == #StaticGray) ifTrue:[
- (aDevice depth == pictureDepth) ifTrue:[
-
- "greyscale is easy, if the depths match"
-
- f := Form width:width height:height depth:pictureDepth on:aDevice.
- f isNil ifTrue:[^ nil].
- f initGC.
-
- "if device has white at the opposite corner ..."
- ((aDevice blackpixel == 0) == (photometric == #blackIs0)) ifFalse:[
- "have to invert bits"
- f function:#copyInverted
- ].
- aDevice drawBits:bytes depth:pictureDepth width:width height:height
- x:0 y:0
- into:(f id)
- x:0 y:0 width:width height:height with:(f gcId).
- ^ f
- ].
-
- "the image has more greylevels than the display - dither"
+ (aDevice depth == pictureDepth) ifTrue:[
+
+ "greyscale is easy, if the depths match"
+
+ f := Form width:width height:height depth:pictureDepth on:aDevice.
+ f isNil ifTrue:[^ nil].
+ f initGC.
+
+ "if device has white at the opposite corner ..."
+ ((aDevice blackpixel == 0) == (photometric == #blackIs0)) ifFalse:[
+ "have to invert bits"
+ f function:#copyInverted
+ ].
+ aDevice drawBits:bytes depth:pictureDepth width:width height:height
+ x:0 y:0
+ into:(f id)
+ x:0 y:0 width:width height:height with:(f gcId).
+ ^ f
+ ].
+
+ "the image has more greylevels than the display - dither"
"
coming soon ...
- DitherAlgorithm == #error ifTrue:[
- ^ self greyImageAsErrorDitheredGreyFormOn:aDevice
- ].
+ DitherAlgorithm == #error ifTrue:[
+ ^ self greyImageAsErrorDitheredGreyFormOn:aDevice
+ ].
"
- DitherAlgorithm == #pattern ifTrue:[
- ^ self greyImageAsPatternDitheredGreyFormOn:aDevice
- ].
-
- "no dither, simply cut off information"
- (aDevice depth == 1) ifTrue:[
- "for monochrome, there is a special method to do this"
- ^ self greyImageAsMonoFormOn:aDevice
- ].
- "the general case, will take as many bits from the image
- as possible for the device"
- ^ self greyImageAsGreyFormOn:aDevice
+ DitherAlgorithm == #pattern ifTrue:[
+ ^ self greyImageAsPatternDitheredGrayFormOn:aDevice
+ ].
+
+ "no dither, simply cut off information"
+ (aDevice depth == 1) ifTrue:[
+ "for monochrome, there is a special method to do this"
+ ^ self greyImageAsMonoFormOn:aDevice
+ ].
+ "the general case, will take as many bits from the image
+ as possible for the device"
+ ^ self greyImageAsGrayFormOn:aDevice
].
(aDevice visualType == #PseudoColor
or:[aDevice visualType == #GrayScale
or:[aDevice visualType == #StaticColor]]) ifTrue:[
- ^ self greyImageAsPseudoFormOn:aDevice
+ ^ self greyImageAsPseudoFormOn:aDevice
].
(aDevice visualType == #TrueColor) ifTrue:[
- ^ self greyImageAsTrueColorFormOn:aDevice
+ ^ self greyImageAsTrueColorFormOn:aDevice
].
self error:'cannot convert this format'.
^ nil
- "Modified: 11.12.1995 / 18:55:01 / cg"
-!
-
-greyImageAsGreyFormOn:aDevice
+ "Modified: 10.6.1996 / 14:41:05 / cg"
+!
+
+greyImageAsGrayFormOn:aDevice
"return an 8-bit Form from the grey image"
|wideBits pictureDepth f map nplanes ncells
@@ -2674,8 +2763,8 @@
shift4 "{ Class: SmallInteger }" |
(aDevice depth == 8) ifFalse:[
- 'IMAGE: non-8 plane displays not supported' errorPrintNL.
- ^ self greyImageAsMonoFormOn:aDevice
+ 'IMAGE: non-8 plane displays not supported' errorPrintNL.
+ ^ self greyImageAsMonoFormOn:aDevice
].
pictureDepth := bitsPerSample at:1.
@@ -2688,8 +2777,8 @@
nplanes := 8.
ncells := 256.
[aDevice ncells < ncells] whileTrue:[
- nplanes := nplanes - 1.
- ncells := ncells // 2
+ nplanes := nplanes - 1.
+ ncells := ncells // 2
].
"prepare translation table"
@@ -2701,34 +2790,36 @@
inverse := aDevice blackpixel ~~ 0.
photometric == #blackIs0 ifFalse:[
- inverse := inverse not
+ inverse := inverse not
].
mapSize := map size.
1 to:mapSize do:[:index |
- oldValue := index - 1.
- newValue := oldValue bitShift:shift.
- newValue := newValue bitOr:(oldValue bitShift:shift2).
- newValue := newValue bitOr:(oldValue bitShift:shift3).
- newValue := newValue bitOr:(oldValue bitShift:shift4).
- inverse ifTrue:[
- map at:(map size - index + 1) put:newValue
- ] ifFalse:[
- map at:index put:newValue
- ]
+ oldValue := index - 1.
+ newValue := oldValue bitShift:shift.
+ newValue := newValue bitOr:(oldValue bitShift:shift2).
+ newValue := newValue bitOr:(oldValue bitShift:shift3).
+ newValue := newValue bitOr:(oldValue bitShift:shift4).
+ inverse ifTrue:[
+ map at:(map size - index + 1) put:newValue
+ ] ifFalse:[
+ map at:index put:newValue
+ ]
].
bytes expandPixels:pictureDepth
- width:width
- height:height
- into:wideBits
- mapping:map.
+ width:width
+ height:height
+ into:wideBits
+ mapping:map.
f := Form width:width height:height depth:8 on:aDevice.
f isNil ifTrue:[^ nil].
f initGC.
aDevice drawBits:wideBits depth:8 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
+
+ "Created: 10.6.1996 / 14:40:45 / cg"
!
greyImageAsMonoFormOn:aDevice
@@ -2739,7 +2830,7 @@
"Modified: 8.6.1996 / 15:22:35 / cg"
!
-greyImageAsPatternDitheredGreyFormOn:aDevice
+greyImageAsPatternDitheredGrayFormOn:aDevice
"return a dithered greyForm from the grey image.
Works for any source/destination depths, but very very slow
since each pixel is processed individually.
@@ -2787,6 +2878,7 @@
^ f
"Modified: 7.6.1996 / 19:11:46 / cg"
+ "Created: 10.6.1996 / 14:41:10 / cg"
!
greyImageAsPseudoFormOn:aDevice
@@ -3006,37 +3098,37 @@
|type ddepth|
(ddepth := aDevice depth) == 1 ifTrue:[
- ^ self paletteImageAsMonoFormOn:aDevice
+ ^ self paletteImageAsMonoFormOn:aDevice
].
((type := aDevice visualType) == #StaticGray) ifTrue:[
- ddepth == 8 ifTrue:[
- ^ self paletteImageAsGreyFormOn:aDevice
- ].
-
- DitherAlgorithm == #pattern ifTrue:[
- ^ self paletteImageAsPatternDitheredGreyFormOn:aDevice
- ].
-
- ddepth == 2 ifTrue:[
- ^ self paletteImageAs2PlaneFormOn:aDevice
- ].
-
- ^ self paletteImageAsMonoFormOn:aDevice
+ ddepth == 8 ifTrue:[
+ ^ self paletteImageAsGray8FormOn:aDevice
+ ].
+
+ DitherAlgorithm == #pattern ifTrue:[
+ ^ self paletteImageAsPatternDitheredGrayFormOn:aDevice
+ ].
+
+ ddepth == 2 ifTrue:[
+ ^ self paletteImageAs2PlaneFormOn:aDevice
+ ].
+
+ ^ self paletteImageAsMonoFormOn:aDevice
].
(type == #TrueColor) ifTrue:[
- ^ self paletteImageAsTrueColorFormOn:aDevice
+ ^ self paletteImageAsTrueColorFormOn:aDevice
].
(type == #PseudoColor) ifTrue:[
- ^ self paletteImageAsPseudoFormOn:aDevice
+ ^ self paletteImageAsPseudoFormOn:aDevice
].
(type == #StaticColor) ifTrue:[
- ^ self paletteImageAsPseudoFormOn:aDevice
+ ^ self paletteImageAsPseudoFormOn:aDevice
].
"/ dump fallback: every device should implement b&w images ...
^ self paletteImageAsMonoFormOn:aDevice
- "Modified: 11.12.1995 / 16:34:52 / cg"
+ "Modified: 10.6.1996 / 14:41:52 / cg"
!
paletteImageAsGreyFormOn:aDevice
@@ -3046,15 +3138,21 @@
!
paletteImageAsMonoFormOn:aDevice
- "return a 1-bit mono-deviceForm from the palette image"
-
- ^ self subclassResponsibility
-!
-
-paletteImageAsPatternDitheredGreyFormOn:aDevice
+ "return a 1-bit mono-deviceForm from the palette image.
+ the result is a thresholded form, with white for
+ brightness values above 50%, black below"
+
+ ^ self asThresholdMonochromeFormOn:aDevice
+
+ "Modified: 10.6.1996 / 14:27:51 / cg"
+!
+
+paletteImageAsPatternDitheredGrayFormOn:aDevice
"return a dithered grey-deviceForm from the palette image."
^ self subclassResponsibility
+
+ "Created: 10.6.1996 / 14:41:56 / cg"
!
paletteImageAsPseudoFormOn:aDevice
@@ -3306,10 +3404,12 @@
^ self subclassResponsibility
!
-rgbImageAs8BitGreyFormOn:aDevice
+rgbImageAs8BitGrayFormOn:aDevice
"return an 8-bit greyForm from the rgb picture"
^ self subclassResponsibility
+
+ "Created: 10.6.1996 / 14:42:03 / cg"
!
rgbImageAsFormOn:aDevice
@@ -3320,15 +3420,17 @@
visual := aDevice visualType.
(visual == #StaticGray) ifTrue:[
- ^ self rgbImageAsGreyFormOn:aDevice
+ ^ self rgbImageAsGrayFormOn:aDevice
].
(visual == #TrueColor) ifTrue:[
- ^ self rgbImageAsTrueColorFormOn:aDevice
+ ^ self rgbImageAsTrueColorFormOn:aDevice
].
^ self rgbImageAsPseudoFormOn:aDevice
-!
-
-rgbImageAsGreyFormOn:aDevice
+
+ "Modified: 10.6.1996 / 14:44:09 / cg"
+!
+
+rgbImageAsGrayFormOn:aDevice
"convert an rgb image to a grey device-form on aDevice
(for greyscale displays)"
@@ -3338,39 +3440,41 @@
"I have specially tuned methods for monochrome"
(deviceDepth == 1) ifTrue:[
- DitherAlgorithm == #error ifTrue:[
- ^ self rgbImageAsErrorDitheredGreyFormOn:aDevice
- ].
- DitherAlgorithm == #pattern ifTrue:[
- ^ self rgbImageAsPatternDitheredGreyFormOn:aDevice
- ].
- ^ self rgbImageAsMonoFormOn:aDevice
+ DitherAlgorithm == #error ifTrue:[
+ ^ self rgbImageAsErrorDitheredGrayFormOn:aDevice
+ ].
+ DitherAlgorithm == #pattern ifTrue:[
+ ^ self rgbImageAsPatternDitheredGrayFormOn:aDevice
+ ].
+ ^ self rgbImageAsMonoFormOn:aDevice
].
"and for 2plane greyscale (i.e. NeXTs)"
(deviceDepth == 2) ifTrue:[
- DitherAlgorithm == #error ifTrue:[
- ^ self rgbImageAsErrorDitheredGreyFormOn:aDevice
- ].
- DitherAlgorithm == #pattern ifTrue:[
- ^ self rgbImageAsPatternDitheredGreyFormOn:aDevice
- ].
- ^ self rgbImageAs2PlaneFormOn:aDevice
+ DitherAlgorithm == #error ifTrue:[
+ ^ self rgbImageAsErrorDitheredGrayFormOn:aDevice
+ ].
+ DitherAlgorithm == #pattern ifTrue:[
+ ^ self rgbImageAsPatternDitheredGrayFormOn:aDevice
+ ].
+ ^ self rgbImageAs2PlaneFormOn:aDevice
].
(deviceDepth == 8) ifTrue:[
- ^ self rgbImageAs8BitGreyFormOn:aDevice
+ ^ self rgbImageAs8BitGrayFormOn:aDevice
].
"mhmh need another converter ...
till then we do:"
DitherAlgorithm == #error ifTrue:[
- ^ self rgbImageAsErrorDitheredGreyFormOn:aDevice
+ ^ self rgbImageAsErrorDitheredGrayFormOn:aDevice
].
DitherAlgorithm == #pattern ifTrue:[
- ^ self rgbImageAsPatternDitheredGreyFormOn:aDevice
+ ^ self rgbImageAsPatternDitheredGrayFormOn:aDevice
].
^ self rgbImageAsMonoFormOn:aDevice
+
+ "Modified: 10.6.1996 / 14:44:58 / cg"
!
rgbImageAsMonoFormOn:aDevice
@@ -3378,16 +3482,27 @@
using a threshold algorithm.
(i.e. grey value < 0.5 -> black, grey value >= 0.5 -> white)."
- ^ self subclassResponsibility
-!
-
-rgbImageAsPatternDitheredGreyFormOn:aDevice
+ ^ self
+ asThresholdMonochromeFormOn:aDevice
+
+ "
+ |i|
+
+ i := Image fromFile:'bitmaps/granite.tiff'.
+ (i asThresholdMonochromeFormOn:Display) inspect
+ "
+
+ "Modified: 10.6.1996 / 12:31:23 / cg"
+!
+
+rgbImageAsPatternDitheredGrayFormOn:aDevice
"return a dithered greyForm for aDevice from the palette picture.
- works for any destination depth.
- A slow algorithm, using draw into the form (which indirectly does
- the dither) - should be rewritten."
-
- ^ self subclassResponsibility
+ works for any destination depth."
+
+ ^ self asOrderedDitheredGrayFormOn:aDevice
+
+ "Modified: 10.6.1996 / 14:19:21 / cg"
+ "Created: 10.6.1996 / 14:44:17 / cg"
!
rgbImageAsPseudoFormOn:aDevice
@@ -3516,6 +3631,1046 @@
"Modified: 29.5.1996 / 10:52:30 / cg"
! !
+!Image methodsFor:'dither helpers'!
+
+burkesDitheredMonochromeBits
+ "return the bitmap for a dithered monochrome bitmap from the image.
+ Works for any source depths / photometric"
+
+ |dstIndex "{Class: SmallInteger }"
+ nextDst "{Class: SmallInteger }"
+ bytesPerMonoRow "{Class: SmallInteger }"
+ monoBits greyValues
+ errorArray
+ errorArray1
+ e t
+ w "{Class: SmallInteger }"
+ h "{Class: SmallInteger }"
+ bitCnt "{Class: SmallInteger }"
+ byte "{Class: SmallInteger }"
+ grey dT
+ eR eRB eB eLB |
+
+ self depth > 12 ifTrue:[
+ ^ self floydSteinbergDitheredMonochromeBits
+ ].
+
+ w := width.
+ h := height.
+
+ bytesPerMonoRow := (w + 7) // 8.
+ monoBits := ByteArray uninitializedNew:(bytesPerMonoRow * h).
+ (monoBits isNil or:[bytes isNil]) ifTrue:[
+ ^ nil
+ ].
+
+ errorArray := Array new:(w+4).
+ errorArray1 := Array new:(w+4) withAll:0.
+
+ dstIndex := 1.
+
+ "/ fetch scaled brightness values outside of loop into a table;
+ "/ use table-value in loop
+
+ greyValues := self greyMapForRange:(255*1024).
+
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerMonoRow.
+ byte := 0.
+ bitCnt := 8.
+
+ t := errorArray.
+ errorArray := errorArray1.
+ errorArray1 := t.
+
+ errorArray1 atAllPut:0.
+
+ self valuesAtY:y from:0 to:(w-1) do:[:x :pixel |
+ |eP "{Class: SmallInteger }"
+ eD
+ eI "{Class: SmallInteger }"
+ xE "{Class: SmallInteger }"
+ xN "{Class: SmallInteger }" |
+
+ "/ get the colors grey value [0 .. 1]
+ grey := greyValues at:(pixel + 1).
+
+ "/ adjust error
+ xE := x + 2 + 1.
+ grey := (grey + (errorArray at:xE)).
+
+ byte := byte bitShift:1.
+ grey > (127*1024) ifTrue:[
+ byte := byte bitOr:1. "/ white
+ e := grey - (255*1024)
+ ] ifFalse:[
+ e := grey "/ black
+ ].
+
+ e ~= 0 ifTrue:[
+ "/ distribute the error:
+ "/ XX 8 4
+ "/ 2 4 8 4 2
+
+ eD := e.
+ eI := e // 32.
+
+ eP := eI * 8. eD := eD - eP.
+
+ xN := xE + 1.
+ errorArray at:xN put:(errorArray at:xN) + eP.
+
+ eD := eD - eP.
+ errorArray1 at:xE put:(errorArray1 at:xE) + eP.
+
+ eP := eI * 4. eD := eD - eP.
+ xN := xE + 2.
+ errorArray at:xN put:(errorArray at:xN) + eP.
+
+ eD := eD - eP.
+ xN := xE - 1.
+ errorArray1 at:xN put:(errorArray1 at:xN) + eP.
+
+ eD := eD - eP.
+ xN := xE + 1.
+ errorArray1 at:xN put:(errorArray1 at:xN) + eP.
+
+ eP := eI * 2. eD := eD - eP.
+ xN := xE - 2.
+ errorArray1 at:xN put:(errorArray1 at:xN) + eP.
+
+ eD := eD.
+ xN := xE + 2.
+ errorArray1 at:xN put:(errorArray1 at:xN) + eP.
+ ].
+
+ bitCnt := bitCnt - 1.
+ bitCnt == 0 ifTrue:[
+ monoBits at:dstIndex put:byte.
+ dstIndex := dstIndex + 1.
+ byte := 0.
+ bitCnt := 8.
+ ].
+
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ monoBits at:dstIndex put:byte.
+ ].
+
+ dstIndex := nextDst.
+ ].
+
+ ^ monoBits
+
+ "Created: 10.6.1996 / 12:18:20 / cg"
+ "Modified: 10.6.1996 / 13:16:33 / cg"
+!
+
+floydSteinbergDitheredBitsDepth:depth
+ "return the bitmap for a dithered depth bitmap from the image.
+ Works for any source depths / photometric,
+ but very slow since each pixel is processed individually.
+ Redefined by some subclasses for more performance (D8Image)"
+
+ |dstIndex "{Class: SmallInteger }"
+ nextDst "{Class: SmallInteger }"
+ bytesPerOutRow "{Class: SmallInteger }"
+ outBits greyValues greyErrors greyPixels greyLevels
+ errorArray
+ nextErrorArray
+ e t
+ w "{Class: SmallInteger }"
+ h "{Class: SmallInteger }"
+ bitCnt "{Class: SmallInteger }"
+ byte "{Class: SmallInteger }"
+ grey dT
+ eR eRB eB eLB |
+
+ depth > 8 ifTrue:[
+ self error:'unimplemented conversion'.
+ ^ nil
+ ].
+
+ w := width.
+ h := height.
+
+ bytesPerOutRow := ((w * depth) + 7) // 8.
+ outBits := ByteArray uninitializedNew:(bytesPerOutRow * h).
+ (outBits isNil or:[bytes isNil]) ifTrue:[
+ ^ nil
+ ].
+
+ greyLevels := (1 bitShift:depth) - 1.
+
+ errorArray := Array new:w+2.
+ nextErrorArray := Array new:w+2.
+
+ nextErrorArray atAllPut:0.
+
+ dstIndex := 1.
+
+ self depth <= 12 ifTrue:[
+ "/ fetch scaled brightness values outside of loop into a table;
+ "/ use table-value in loop
+
+ greyValues := self greyMapForRange:(greyLevels).
+
+ greyPixels := greyValues collect:[:v | v isNil ifTrue:[
+ 0
+ ] ifFalse:[
+ v truncated]].
+
+ greyPixels := ByteArray withAll:greyPixels.
+
+ greyErrors := greyValues collect:[:v | v isNil ifTrue:[
+ 0
+ ] ifFalse:[
+ (v - v truncated)
+ ]].
+
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerOutRow.
+ byte := 0.
+ bitCnt := 8.
+
+ t := errorArray.
+ errorArray := nextErrorArray.
+ nextErrorArray := t.
+
+ nextErrorArray atAllPut:0.
+
+ self valuesAtY:y from:0 to:(w-1) do:[:x :value |
+ |e eD pixel error
+ e16
+ xE "{ Class: SmallInteger }"
+ xN "{ Class: SmallInteger }" |
+
+ pixel := greyPixels at:(value + 1).
+
+ "/ adjust error
+ xE := x + 2.
+ error := (greyErrors at:(value + 1)) + (errorArray at:xE).
+
+ byte := byte bitShift:depth.
+ error > 0.5 ifTrue:[
+ pixel := pixel + 1.
+ e := error - 1.0
+ ] ifFalse:[
+ e := error
+ ].
+ byte := byte bitOr:pixel.
+
+ e ~= 0 ifTrue:[
+ eD := e.
+ e16 := e / 16.
+
+ eR := e16 * 7. "/ 7/16 to right
+ eRB := e16 * 1. "/ 1/16 to right below
+ eB := e16 * 5. "/ 5/16 to below
+ eLB := eD - eR - eRB - eB. "/ 3/16 to left below
+
+ xN := xE + 1.
+ eR ~= 0 ifTrue:[
+ errorArray at:xN put:(errorArray at:xN) + eR.
+ ].
+ eRB ~= 0 ifTrue:[
+ nextErrorArray at:xN put:(nextErrorArray at:xN) + eRB.
+ ].
+ eB ~= 0 ifTrue:[
+ nextErrorArray at:xE put:(nextErrorArray at:xE) + eB.
+ ].
+ eLB ~= 0 ifTrue:[
+ xN := xE - 1.
+ nextErrorArray at:xN put:(nextErrorArray at:xN) + eLB.
+ ].
+ ].
+
+ bitCnt := bitCnt - depth.
+ bitCnt == 0 ifTrue:[
+ outBits at:dstIndex put:byte.
+ dstIndex := dstIndex + 1.
+ byte := 0.
+ bitCnt := 8.
+ ].
+
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ outBits at:dstIndex put:byte.
+ ].
+
+ dstIndex := nextDst.
+ ].
+ ] ifFalse:[
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerOutRow.
+ byte := 0.
+ bitCnt := 8.
+
+ t := errorArray.
+ errorArray := nextErrorArray.
+ nextErrorArray := t.
+
+ nextErrorArray atAllPut:0.
+
+ self colorsAtY:y from:0 to:(w-1) do:[:x :clr |
+ |e eD pixel error
+ e16
+ xE "{ Class: SmallInteger }"
+ xN "{ Class: SmallInteger }" |
+
+ grey := (clr brightness * greyLevels).
+ pixel := grey truncated.
+ error := grey - pixel.
+
+ "/ adjust error
+ xE := x + 2.
+ error := error + (errorArray at:xE).
+
+ byte := byte bitShift:depth.
+ error > 0.5 ifTrue:[
+ pixel := pixel + 1.
+ e := error - 1.0
+ ] ifFalse:[
+ e := error
+ ].
+
+ byte := byte bitOr:pixel.
+
+ e ~= 0 ifTrue:[
+ eD := e.
+ e16 := e / 16.
+
+ eR := e16 * 7. "/ 7/16 to right
+ eRB := e16 * 1. "/ 1/16 to right below
+ eB := e16 * 5. "/ 5/16 to below
+ eLB := eD - eR - eRB - eB. "/ 3/16 to left below
+
+ xN := xE + 1.
+ eR ~= 0 ifTrue:[
+ errorArray at:xN put:(errorArray at:xN) + eR.
+ ].
+ eRB ~= 0 ifTrue:[
+ nextErrorArray at:xN put:(nextErrorArray at:xN) + eRB.
+ ].
+ eB ~= 0 ifTrue:[
+ nextErrorArray at:xE put:(nextErrorArray at:xE) + eB.
+ ].
+ eLB ~= 0 ifTrue:[
+ xN := xE - 1.
+ nextErrorArray at:xN put:(nextErrorArray at:xN) + eLB.
+ ].
+ ].
+
+ bitCnt := bitCnt - depth.
+ bitCnt == 0 ifTrue:[
+ outBits at:dstIndex put:byte.
+ dstIndex := dstIndex + 1.
+ byte := 0.
+ bitCnt := 8.
+ ].
+
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ outBits at:dstIndex put:byte.
+ ].
+
+ dstIndex := nextDst.
+ ].
+ ].
+
+ ^ outBits
+
+ "Created: 10.6.1996 / 13:28:22 / cg"
+ "Modified: 10.6.1996 / 15:09:07 / cg"
+!
+
+floydSteinbergDitheredMonochromeBits
+ "return the bitmap for a dithered monochrome bitmap from the image.
+ Works for any source depths / photometric,
+ but very very slow since each pixel is processed individually.
+ Redefined by some subclasses for more performance (D8Image)"
+
+ |dstIndex "{Class: SmallInteger }"
+ nextDst "{Class: SmallInteger }"
+ bytesPerMonoRow "{Class: SmallInteger }"
+ monoBits greyValues
+ errorArray
+ nextErrorArray
+ e eD t
+ w "{Class: SmallInteger }"
+ h "{Class: SmallInteger }"
+ bitCnt "{Class: SmallInteger }"
+ byte "{Class: SmallInteger }"
+ grey dT
+ eR eRB eB eLB |
+
+ w := width.
+ h := height.
+
+ bytesPerMonoRow := (w + 7) // 8.
+ monoBits := ByteArray uninitializedNew:(bytesPerMonoRow * h).
+ (monoBits isNil or:[bytes isNil]) ifTrue:[
+ ^ nil
+ ].
+
+ errorArray := Array new:w+2.
+ nextErrorArray := Array new:w+2.
+
+ nextErrorArray atAllPut:0.
+
+ dstIndex := 1.
+
+ self depth <= 12 ifTrue:[
+ "/ fetch scaled brightness values outside of loop into a table;
+ "/ use table-value in loop
+
+ greyValues := self greyMapForRange:(255 * 1024).
+ greyValues := greyValues collect:[:v | v isNil ifTrue:[
+ 0
+ ] ifFalse:[
+ v rounded
+ ]].
+
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerMonoRow.
+ byte := 0.
+ bitCnt := 8.
+
+ t := errorArray.
+ errorArray := nextErrorArray.
+ nextErrorArray := t.
+
+ nextErrorArray atAllPut:0.
+
+ self valuesAtY:y from:0 to:(w-1) do:[:x :pixel |
+ |eI "{ Class: SmallInteger }"
+ xE "{ Class: SmallInteger }"
+ xN "{ Class: SmallInteger }" |
+
+ "/ get the colors grey value [0 .. 1]
+ grey := greyValues at:(pixel + 1).
+
+ "/ adjust error
+ xE := x + 2.
+ grey := (grey + (errorArray at:xE)).
+
+ byte := byte bitShift:1.
+ grey > (127*1024) ifTrue:[
+ byte := byte bitOr:1. "/ white
+ e := grey - (255*1024)
+ ] ifFalse:[
+ e := grey "/ black
+ ].
+
+ e ~= 0 ifTrue:[
+ eD := e.
+ eI := e // 16.
+
+ eR := eI * 7. "/ 7/16 to right
+ eRB := eI * 1. "/ 1/16 to right below
+ eB := eI * 5. "/ 5/16 to below
+ eLB := eD - eR - eRB - eB. "/ 3/16 to left below
+
+ xN := xE + 1.
+ eR ~= 0 ifTrue:[
+ errorArray at:xN put:(errorArray at:xN) + eR.
+ ].
+ eRB ~= 0 ifTrue:[
+ nextErrorArray at:xN put:(nextErrorArray at:xN) + eRB.
+ ].
+ eB ~= 0 ifTrue:[
+ nextErrorArray at:xE put:(nextErrorArray at:xE) + eB.
+ ].
+ eLB ~= 0 ifTrue:[
+ xN := xE - 1.
+ nextErrorArray at:xN put:(nextErrorArray at:xN) + eLB.
+ ].
+ ].
+
+ bitCnt := bitCnt - 1.
+ bitCnt == 0 ifTrue:[
+ monoBits at:dstIndex put:byte.
+ dstIndex := dstIndex + 1.
+ byte := 0.
+ bitCnt := 8.
+ ].
+
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ monoBits at:dstIndex put:byte.
+ ].
+
+ dstIndex := nextDst.
+ ].
+ ] ifFalse:[
+ 'IMAGE: slow floydSteinberg dither ..' infoPrintCR.
+
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerMonoRow.
+ byte := 0.
+ bitCnt := 8.
+
+ t := errorArray.
+ errorArray := nextErrorArray.
+ nextErrorArray := t.
+
+ nextErrorArray atAllPut:0.
+
+ self colorsAtY:y from:0 to:(w-1) do:[:x :clr |
+ |eI "{ Class: SmallInteger }"
+ xE "{ Class: SmallInteger }"
+ xN "{ Class: SmallInteger }" |
+
+ "/ get the colors grey value [0 .. 1]
+ grey := (clr brightness * 255).
+
+ "/ adjust error
+ xE := x + 2.
+ grey := (grey + (errorArray at:xE)) rounded.
+
+ byte := byte bitShift:1.
+ grey > 127 ifTrue:[
+ byte := byte bitOr:1. "/ white
+ e := grey - 255
+ ] ifFalse:[
+ e := grey "/ black
+ ].
+
+ e ~= 0 ifTrue:[
+ eD := e.
+ eI := e // 16.
+ eR := eI * 7. "/ 7/16 to right
+ eRB := eI * 1. "/ 1/16 to right below
+ eB := eI * 5. "/ 5/16 to below
+ eLB := eD - eR - eRB - eB. "/ 3/16 to left below
+
+ xN := xE + 1.
+ eR ~= 0 ifTrue:[
+ errorArray at:xN put:(errorArray at:xN) + eR.
+ ].
+ eRB ~= 0 ifTrue:[
+ nextErrorArray at:xN put:(nextErrorArray at:xN) + eRB.
+ ].
+ eB ~= 0 ifTrue:[
+ nextErrorArray at:xE put:(nextErrorArray at:xE) + eB.
+ ].
+ eLB ~= 0 ifTrue:[
+ xN := xE - 1.
+ nextErrorArray at:xN put:(nextErrorArray at:xN) + eLB.
+ ].
+ ].
+
+ bitCnt := bitCnt - 1.
+ bitCnt == 0 ifTrue:[
+ monoBits at:dstIndex put:byte.
+ dstIndex := dstIndex + 1.
+ byte := 0.
+ bitCnt := 8.
+ ].
+
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ monoBits at:dstIndex put:byte.
+ ].
+
+ dstIndex := nextDst.
+ ].
+ ].
+
+ ^ monoBits
+
+ "Created: 8.6.1996 / 16:39:46 / cg"
+ "Modified: 10.6.1996 / 15:12:11 / cg"
+!
+
+orderedDitheredBitsWithDitherMatrix:ditherMatrix ditherWidth:dW depth:depth
+ "return the bitmap for a dithered depth-bitmap from the image;
+ with a constant ditherMatrix, this can be used for thresholding.
+ Works for any source depths / photometric,
+ but very very slow since each pixel is processed individually.
+ Redefined by some subclasses for more performance (D8Image)"
+
+ |f last dH nDither
+ greyLevels greyValues greyPixels greyErrors
+ dstIndex "{Class: SmallInteger }"
+ nextDst
+ bytesPerOutRow "{Class: SmallInteger }"
+ pixelsPerByte "{Class: SmallInteger }"
+ outBits
+ w "{Class: SmallInteger }"
+ h "{Class: SmallInteger }"
+ bitCnt "{Class: SmallInteger }"
+ byte "{Class: SmallInteger }" |
+
+ depth > 8 ifTrue:[
+ 'IMAGE: unimplemented orderedDither conversion' errorPrintCR.
+ ^ nil
+ ].
+
+ nDither := ditherMatrix size.
+ dH := nDither / dW.
+
+ w := width.
+ h := height.
+
+ greyLevels := 1 bitShift:depth.
+ pixelsPerByte := 8 / depth.
+
+ bytesPerOutRow := (w * depth + 7) // 8.
+ outBits := ByteArray uninitializedNew:(bytesPerOutRow * h).
+ (outBits isNil or:[bytes isNil]) ifTrue:[
+ ^ nil
+ ].
+
+ dstIndex := 1.
+
+ self bitsPerPixel <= 12 ifTrue:[
+ "/ fetch scaled brightness values outside of loop into a table;
+ "/ use table-value in loop
+
+ greyValues := self greyMapForRange:(greyLevels-1).
+ greyPixels := greyValues collect:[:v | v isNil ifTrue:[
+ 0
+ ] ifFalse:[
+ v truncated]].
+ greyPixels := ByteArray withAll:greyPixels.
+
+ greyErrors := greyValues collect:[:v | v isNil ifTrue:[
+ 0
+ ] ifFalse:[
+ ((v - v truncated) * nDither) rounded
+ ]].
+ greyErrors := ByteArray withAll:greyErrors.
+
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerOutRow.
+ byte := 0.
+ bitCnt := 8.
+
+ self valuesAtY:y from:0 to:(w-1) do:[:x :value |
+%{
+ int __dW = __intVal(dW);
+ int __byte = __intVal(byte);
+ int __value = __intVal(value);
+ int __dT;
+ int __dstIdx;
+ int __pixel, __grey;
+ int __bitCnt = __intVal(bitCnt);
+ unsigned char *__greyPixels = __ByteArrayInstPtr(greyPixels)->ba_element;
+ unsigned char *__greyErrors = __ByteArrayInstPtr(greyErrors)->ba_element;
+
+ __pixel = __greyPixels[__value];
+ __grey = __greyErrors[__value];
+
+ __dT = __ByteArrayInstPtr(ditherMatrix)
+ ->ba_element[__intVal(x) % __dW
+ + (__intVal(y) % __intVal(dH)) * __dW];
+
+ if (__grey > __dT) {
+ __pixel++;
+ }
+ __byte = (__byte << __intVal(depth)) | __pixel;
+
+ __bitCnt = __bitCnt - __intVal(depth);
+ if (__bitCnt == 0) {
+ __dstIdx = __intVal(dstIndex);
+ __ByteArrayInstPtr(outBits)->ba_element[__dstIdx-1] = __byte;
+ __dstIdx = __dstIdx + 1;
+ dstIndex = __MKSMALLINT(__dstIdx);
+ __byte = 0;
+ __bitCnt = 8;
+ }
+ byte = __MKSMALLINT(__byte);
+ bitCnt = __MKSMALLINT(__bitCnt);
+%}.
+ 0
+
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ outBits at:dstIndex put:byte.
+ ].
+ dstIndex := nextDst.
+ ].
+ ] ifFalse:[
+ Transcript showCR:'slow ordered dither ..'. Transcript endEntry.
+
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerOutRow.
+ byte := 0.
+ bitCnt := 8.
+
+ "/ this is the representaion independent (but slow)
+ "/ inner loop - it extracts colors from the receiver
+
+ self colorsAtY:y from:0 to:(w-1) do:[:x :clr |
+ |dstClr grey dT pixel|
+
+ "/ get the colors grey value [0 .. 1]
+ grey := clr brightness.
+
+ "/ remap into [0 .. greyLevels-1]
+ grey := grey * (greyLevels-1).
+
+ "/ get threshold pixel [0 .. greyLevels-1]
+
+ pixel := grey truncated.
+
+ "/ compute the error [0..1]
+ grey := grey - pixel.
+
+ "/ map into dither space [0 .. nDither]
+ grey := (grey * (nDither)) rounded.
+
+%{
+ int __dW = __intVal(dW);
+ int __byte = __intVal(byte);
+ int __dT;
+ int __dstIdx;
+ int __pixel;
+ int __bitCnt = __intVal(bitCnt);
+
+ __dT = __ByteArrayInstPtr(ditherMatrix)
+ ->ba_element[__intVal(x) % __dW
+ + (__intVal(y) % __intVal(dH)) * __dW];
+
+ __pixel = __intVal(pixel);
+
+ if (__intVal(grey) > __dT) {
+ __pixel++;
+ }
+ __byte = (__byte << __intVal(depth)) | __pixel;
+
+ __bitCnt = __bitCnt - __intVal(depth);
+ if (__bitCnt == 0) {
+ __dstIdx = __intVal(dstIndex);
+ __ByteArrayInstPtr(outBits)->ba_element[__dstIdx-1] = __byte;
+ __dstIdx = __dstIdx + 1;
+ dstIndex = __MKSMALLINT(__dstIdx);
+ __byte = 0;
+ __bitCnt = 8;
+ }
+ byte = __MKSMALLINT(__byte);
+ bitCnt = __MKSMALLINT(__bitCnt);
+%}.
+ 0
+
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ outBits at:dstIndex put:byte.
+ ].
+ dstIndex := nextDst.
+ ].
+ ].
+ ^ outBits
+!
+
+orderedDitheredMonochromeBitsWithDitherMatrix:ditherMatrix ditherWidth:dW
+ "return the bitmap for a dithered monochrome bitmap from the image;
+ with a constant ditherMatrix, this can be used for thresholding.
+ Works for any source depths / photometric,
+ but very very slow since each pixel is processed individually.
+ Redefined by some subclasses for more performance (D8Image)"
+
+ |f last dH nDither
+ greyValues
+ dstIndex "{Class: SmallInteger }"
+ nextDst "{Class: SmallInteger }"
+ bytesPerMonoRow "{Class: SmallInteger }"
+ monoBits
+ w "{Class: SmallInteger }"
+ h "{Class: SmallInteger }"
+ bitCnt "{Class: SmallInteger }"
+ byte "{Class: SmallInteger }" |
+
+ nDither := ditherMatrix size.
+ dH := nDither / dW.
+
+ w := width.
+ h := height.
+
+ bytesPerMonoRow := (w + 7) // 8.
+ monoBits := ByteArray uninitializedNew:(bytesPerMonoRow * h).
+ (monoBits isNil or:[bytes isNil]) ifTrue:[
+ ^ nil
+ ].
+
+ dstIndex := 1.
+
+ self bitsPerPixel <= 12 ifTrue:[
+ "/ fetch scaled brightness values outside of loop into a table;
+ "/ use table-value in loop
+
+ greyValues := self greyByteMapForRange:nDither.
+
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerMonoRow.
+ byte := 0.
+ bitCnt := 8.
+ self valuesAtY:y from:0 to:(w-1) do:[:x :value |
+%{
+ int __dW = __intVal(dW);
+ int __byte = __intVal(byte);
+ int __dT;
+ int __dstIdx;
+ int __bitCnt = __intVal(bitCnt);
+ int __grey;
+ unsigned char *__greyValues = __ByteArrayInstPtr(greyValues)->ba_element;
+
+ __grey = __greyValues[__intVal(value)];
+
+ __dT = __ByteArrayInstPtr(ditherMatrix)
+ ->ba_element[__intVal(x) % __dW
+ + (__intVal(y) % __intVal(dH)) * __dW];
+
+ __byte = __byte << 1;
+ if (__grey > __dT) {
+ __byte = __byte | 1; /* white */
+ }
+ __bitCnt = __bitCnt - 1;
+ if (__bitCnt == 0) {
+ __dstIdx = __intVal(dstIndex);
+ __ByteArrayInstPtr(monoBits)->ba_element[__dstIdx-1] = __byte;
+ __dstIdx = __dstIdx + 1;
+ dstIndex = __MKSMALLINT(__dstIdx);
+ __byte = 0;
+ __bitCnt = 8;
+ }
+ byte = __MKSMALLINT(__byte);
+ bitCnt = __MKSMALLINT(__bitCnt);
+%}.
+ 0
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ monoBits at:dstIndex put:byte.
+ ].
+ dstIndex := nextDst.
+ ].
+ ] ifFalse:[
+ Transcript showCR:'slow ordered dither ..'. Transcript endEntry.
+
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerMonoRow.
+ byte := 0.
+ bitCnt := 8.
+ self colorsAtY:y from:0 to:(w-1) do:[:x :clr |
+ |dstClr grey dT|
+
+ "/ get the colors grey value [0 .. 1]
+ grey := clr brightness.
+
+ "/ map into dither space [0 .. nDither]
+ grey := (grey * (nDither)) rounded.
+
+%{
+ int __dW = __intVal(dW);
+ int __byte = __intVal(byte);
+ int __dT;
+ int __dstIdx;
+ int __bitCnt = __intVal(bitCnt);
+
+ __dT = __ByteArrayInstPtr(ditherMatrix)
+ ->ba_element[__intVal(x) % __dW
+ + (__intVal(y) % __intVal(dH)) * __dW];
+
+ __byte = __byte << 1;
+ if (__intVal(grey) > __dT) {
+ __byte = __byte | 1; /* white */
+ }
+ __bitCnt = __bitCnt - 1;
+ if (__bitCnt == 0) {
+ __dstIdx = __intVal(dstIndex);
+ __ByteArrayInstPtr(monoBits)->ba_element[__dstIdx-1] = __byte;
+ __dstIdx = __dstIdx + 1;
+ dstIndex = __MKSMALLINT(__dstIdx);
+ __byte = 0;
+ __bitCnt = 8;
+ }
+ byte = __MKSMALLINT(__byte);
+ bitCnt = __MKSMALLINT(__bitCnt);
+%}.
+ 0
+
+"/ dT := ditherMatrix at:(x \\ dW) + (y \\ dH * dW) + 1.
+"/
+"/ byte := byte bitShift:1.
+"/ grey < dT ifTrue:[
+"/ byte := byte bitOr:1.
+"/ ].
+"/ bitCnt := bitCnt - 1.
+"/ bitCnt == 0 ifTrue:[
+"/ monoBits at:dstIndex put:byte.
+"/ dstIndex := dstIndex + 1.
+"/ byte := 0.
+"/ bitCnt := 8.
+"/ ].
+
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ monoBits at:dstIndex put:byte.
+ ].
+ dstIndex := nextDst.
+ ].
+ ].
+ ^ monoBits
+!
+
+stevensonArceDitheredMonochromeBits
+ "return the bitmap for a dithered monochrome bitmap from the image.
+ Works for any source depths / photometric"
+
+ |f last
+ dstIndex "{Class: SmallInteger }"
+ nextDst "{Class: SmallInteger }"
+ bytesPerMonoRow "{Class: SmallInteger }"
+ monoBits greyValues
+ errorArray
+ errorArray1 errorArray2 errorArray3
+ e t
+ w "{Class: SmallInteger }"
+ h "{Class: SmallInteger }"
+ bitCnt "{Class: SmallInteger }"
+ byte "{Class: SmallInteger }"
+ direction "{Class: SmallInteger }"
+ dstClr grey dT
+ xE "{Class: SmallInteger }"
+ xN "{Class: SmallInteger }"
+ eR eRB eB eLB |
+
+ self depth > 12 ifTrue:[
+ ^ self floydSteinbergDitheredMonochromeBits
+ ].
+
+ w := width.
+ h := height.
+
+ bytesPerMonoRow := (w + 7) // 8.
+ monoBits := ByteArray uninitializedNew:(bytesPerMonoRow * h).
+ (monoBits isNil or:[bytes isNil]) ifTrue:[
+ ^ nil
+ ].
+
+ errorArray := Array new:(w+6).
+ errorArray1 := Array new:(w+6) withAll:0.
+ errorArray2 := Array new:(w+6) withAll:0.
+ errorArray3 := Array new:(w+6) withAll:0.
+
+ dstIndex := 1.
+
+ "/ fetch scaled brightness values outside of loop into a table;
+ "/ use table-value in loop
+
+ greyValues := self greyMapForRange:(255 * 1024).
+
+ 0 to:(h-1) do:[:y |
+ nextDst := dstIndex + bytesPerMonoRow.
+ byte := 0.
+ bitCnt := 8.
+
+ t := errorArray.
+ errorArray := errorArray1.
+ errorArray1 := errorArray2.
+ errorArray2 := errorArray3.
+ errorArray3 := t.
+
+ errorArray3 atAllPut:0.
+
+ self valuesAtY:y from:0 to:(w-1) do:[:x :pixel |
+ |eP eD|
+
+ "/ get the colors grey value [0 .. 1]
+ grey := greyValues at:(pixel + 1).
+
+ "/ adjust error
+ xE := x + 3 + 1.
+ grey := (grey + (errorArray at:xE)).
+
+ byte := byte bitShift:1.
+ grey > (127 * 1024) ifTrue:[
+ byte := byte bitOr:1. "/ white
+ e := grey - (255 * 1024)
+ ] ifFalse:[
+ e := grey "/ black
+ ].
+
+ e ~= 0 ifTrue:[
+ "/ distribute the error:
+ "/ XX 32
+ "/ 12 26 30 16
+ "/ 12 26 12
+ "/ 5 12 12 5
+
+ eD := e.
+ e := e // 200.
+
+ eP := e * 32. eD := eD - eP.
+ errorArray at:xE+2 put:(errorArray at:xE+2) + eP.
+
+ eP := e * 30. eD := eD - eP.
+ errorArray1 at:xE+1 put:(errorArray1 at:xE+1) + eP.
+
+ eP := e * 16. eD := eD - eP.
+ errorArray1 at:xE+3 put:(errorArray1 at:xE+3) + eP.
+
+ eP := e * 26. eD := eD - eP.
+ errorArray1 at:xE-1 put:(errorArray1 at:xE-1) + eP.
+
+ eD := eD - eP.
+ errorArray2 at:xE put:(errorArray2 at:xE) + eP.
+
+ eP := e * 12. eD := eD - eP.
+ errorArray1 at:xE-3 put:(errorArray1 at:xE-3) + eP.
+
+ eD := eD - eP.
+ errorArray2 at:xE-2 put:(errorArray2 at:xE-2) + eP.
+
+ eD := eD - eP.
+ errorArray2 at:xE+2 put:(errorArray2 at:xE+2) + eP.
+
+ eD := eD - eP.
+ errorArray3 at:xE-1 put:(errorArray3 at:xE-1) + eP.
+
+ eD := eD - eP.
+ errorArray3 at:xE+1 put:(errorArray3 at:xE+1) + eP.
+
+ eP := e * 5. eD := eD - eP.
+ errorArray3 at:xE-3 put:(errorArray3 at:xE-3) + eP.
+
+ eP := eD.
+ errorArray3 at:xE+3 put:(errorArray3 at:xE+3) + eP.
+ ].
+
+ bitCnt := bitCnt - 1.
+ bitCnt == 0 ifTrue:[
+ monoBits at:dstIndex put:byte.
+ dstIndex := dstIndex + 1.
+ byte := 0.
+ bitCnt := 8.
+ ].
+
+ ].
+ bitCnt ~~ 8 ifTrue:[
+ byte := byte bitShift:bitCnt.
+ monoBits at:dstIndex put:byte.
+ ].
+
+ dstIndex := nextDst.
+ ].
+
+ ^ monoBits
+
+ "Created: 10.6.1996 / 12:38:35 / cg"
+ "Modified: 10.6.1996 / 12:52:20 / cg"
+! !
+
!Image methodsFor:'enumerating'!
atY:y from:x1 to:x2 do:aBlock
@@ -3549,8 +4704,8 @@
aBlock value:xRun value:(self atX:xRun y:y)
]
- "Modified: 7.6.1996 / 18:29:25 / cg"
"Created: 7.6.1996 / 19:12:51 / cg"
+ "Modified: 10.6.1996 / 10:27:29 / cg"
!
colorsFromX:xStart y:yStart toX:xEnd y:yEnd do:aBlock
@@ -4448,7 +5603,9 @@
"return a collection to map from pixelValues to greyLevels
in the range 0..range. The brightness values are not rounded."
- |d n greyMap|
+ |d r
+ n "{Class: SmallInteger }"
+ greyArray|
d := self bitsPerPixel.
n := 1 bitShift:d.
@@ -4457,26 +5614,27 @@
^ nil
].
- greyMap := Array new:n.
+ greyArray := Array new:n.
photometric == #palette ifTrue:[
1 to:(colorMap size) do:[:i |
- greyMap at:i put:(range * (colorMap at:i) brightness)
+ greyArray at:i put:(range * (colorMap at:i) brightness)
].
] ifFalse:[
photometric == #rgb ifTrue:[
1 to:n do:[:i |
- greyMap at:i put:(range * (self colorFromValue:(i-1)) brightness)
+ greyArray at:i put:(range * (self colorFromValue:(i-1)) brightness)
]
] ifFalse:[
+ r := range asFloat.
1 to:n do:[:i |
- greyMap at:i put:(range / (n-1) * (i-1))
+ greyArray at:i put:(r / (n-1) * (i-1))
].
photometric == #blackIs0 ifTrue:[
"/ we are done
] ifFalse:[
photometric == #whiteIs0 ifTrue:[
- greyMap reverse
+ greyArray reverse
] ifFalse:[
self error:'invalid format'.
^ nil
@@ -4484,16 +5642,18 @@
]
]
].
- ^ greyMap
+ ^ greyArray
"
Depth8Image new greyMapForRange:64
Depth4Image new greyMapForRange:64
+ Depth16Image new greyMapForRange:1
Depth4Image new greyMapForRange:1
- "
-
- "Modified: 8.6.1996 / 12:03:46 / cg"
+ Depth2Image new greyMapForRange:1
+ "
+
+ "Modified: 10.6.1996 / 10:37:40 / cg"
!
magnifyRowFrom:srcBytes offset:srcStart pixels:oldPixels
@@ -4568,6 +5728,7 @@
"/ assume that the red bits are the leftMost bits
blueBits := bitsPerSample at:3.
+ blueBits == 0 ifTrue:[^ 0].
^ pixel bitAnd:(1 bitShift:blueBits)-1
].
@@ -4575,7 +5736,7 @@
self subclassResponsibility
"Created: 8.6.1996 / 09:44:21 / cg"
- "Modified: 8.6.1996 / 09:51:45 / cg"
+ "Modified: 10.6.1996 / 14:59:44 / cg"
!
blueComponentOf:pixel
@@ -4589,6 +5750,8 @@
"/ assume that the red bits are the leftMost bits
blueBits := bitsPerSample at:3.
+ blueBits == 0 ifTrue:[^ 0].
+
s := (1 bitShift:blueBits) - 1.
^ 100.0 / s * (pixel bitAnd:(1 bitShift:blueBits)-1)
@@ -4597,7 +5760,7 @@
self subclassResponsibility
"Created: 8.6.1996 / 08:45:22 / cg"
- "Modified: 8.6.1996 / 09:51:40 / cg"
+ "Modified: 10.6.1996 / 14:55:39 / cg"
!
bounds
@@ -4676,6 +5839,7 @@
"/ assume that the red bits are the leftMost bits
greenBits := bitsPerSample at:2.
+ greenBits == 0 ifTrue:[^ 0].
blueBits := bitsPerSample at:3.
^ (pixel bitShift:blueBits negated) bitAnd:(1 bitShift:greenBits)-1
@@ -4683,8 +5847,8 @@
self subclassResponsibility
- "Modified: 8.6.1996 / 08:56:00 / cg"
"Created: 8.6.1996 / 09:44:37 / cg"
+ "Modified: 10.6.1996 / 14:59:35 / cg"
!
greenComponentOf:pixel
@@ -4698,6 +5862,7 @@
"/ assume that the red bits are the leftMost bits
greenBits := bitsPerSample at:2.
+ greenBits == 0 ifTrue:[^ 0].
blueBits := bitsPerSample at:3.
s := (1 bitShift:greenBits) - 1.
@@ -4708,7 +5873,7 @@
self subclassResponsibility
"Created: 8.6.1996 / 08:45:34 / cg"
- "Modified: 8.6.1996 / 09:47:12 / cg"
+ "Modified: 10.6.1996 / 14:55:24 / cg"
!
heightOn:aGC
@@ -4747,6 +5912,7 @@
"/ assume that the red bits are the leftMost bits
redBits := bitsPerSample at:1.
+ redBits == 0 ifTrue:[^ 0].
greenBits := bitsPerSample at:2.
blueBits := bitsPerSample at:3.
@@ -4757,7 +5923,7 @@
self subclassResponsibility
"Created: 8.6.1996 / 09:44:51 / cg"
- "Modified: 8.6.1996 / 09:50:59 / cg"
+ "Modified: 10.6.1996 / 14:59:05 / cg"
!
redComponentOf:pixel
@@ -4771,6 +5937,8 @@
"/ assume that the red bits are the leftMost bits
redBits := bitsPerSample at:1.
+ redBits == 0 ifTrue:[^ 0].
+
greenBits := bitsPerSample at:2.
blueBits := bitsPerSample at:3.
@@ -4784,7 +5952,7 @@
self subclassResponsibility
"Created: 8.6.1996 / 08:45:30 / cg"
- "Modified: 8.6.1996 / 09:51:29 / cg"
+ "Modified: 10.6.1996 / 14:57:24 / cg"
!
usedColors
@@ -5175,6 +6343,6 @@
!Image class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libview/Image.st,v 1.84 1996-06-08 13:35:52 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libview/Image.st,v 1.85 1996-06-10 13:21:51 cg Exp $'
! !
Image initialize!