"
COPYRIGHT (c) 1993 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
Image subclass:#Depth24Image
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
category:'Graphics-Images'
!
!Depth24Image class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1993 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
this class represents true-color (24 bit / pixel) images.
It mainly consists of methods already implemented in Image,
reimplemented here for more performance.
Only the #rgb format is supported here.
[author:]
Claus Gittinger
[see also:]
Depth1Image Depth2Image Depth4Image Depth8Image Depth16Image
ImageReader
"
! !
!Depth24Image class methodsFor:'queries'!
imageDepth
"return the depth of images represented by instances of
this class - here we return 24"
^ 24
"Modified: 20.4.1996 / 23:39:50 / cg"
! !
!Depth24Image methodsFor:'accessing'!
atX:x y:y
"retrieve a pixel at x/y; return a color.
Pixels start at x=0 , y=0 for upper left pixel, end at
x = width-1, y=height-1 for lower right pixel"
|index "{ Class: SmallInteger }"
rVal gVal bVal|
index := 1 + (((width * y) + x) * 3).
rVal := bytes at:(index).
gVal := bytes at:(index + 1).
bVal := bytes at:(index + 2).
photometric ~~ #rgb ifTrue:[
^ super atX:x y:y
].
^ Color red:rVal * 100 / 255
green:gVal * 100 / 255
blue:bVal * 100 / 255
"Modified: 8.6.1996 / 10:45:05 / cg"
!
atX:x y:y put:aColor
"set the pixel at x/y to aColor.
Pixels start at x=0 , y=0 for upper left pixel, end at
x = width-1, y=height-1 for lower right pixel."
|index "{ Class: SmallInteger }"
val "{ Class: SmallInteger }" |
index := 1 + (((width * y) + x) * 3).
val := (aColor red / 100 * 255) rounded.
bytes at:(index) put:val.
val := (aColor green / 100 * 255) rounded.
bytes at:(index + 1) put:val.
val := (aColor blue / 100 * 255) rounded.
bytes at:(index + 2) put:val.
!
atX:x y:y putValue:aPixelValue
"set a pixel at x/y to aPixelValue, which is 24 bits RGB.
Pixels start at x=0 , y=0 for upper left pixel, end at
x = width-1, y=height-1 for lower right pixel"
|index "{ Class: SmallInteger }"
val "{ Class: SmallInteger }" |
index := 1 + (((width * y) + x) * 3).
val := aPixelValue.
bytes at:(index + 2) put:(val bitAnd:16rFF).
val := val bitShift:-8.
bytes at:(index + 1) put:(val bitAnd:16rFF).
val := val bitShift:-8.
bytes at:(index) put:val.
!
valueAtX:x y:y
"retrieve a pixel at x/y; return a color.
Pixels start at x=0 , y=0 for upper left pixel, end at
x = width-1, y=height-1 for lower right pixel"
|index "{ Class: SmallInteger }"
rVal "{ Class: SmallInteger }"
gVal "{ Class: SmallInteger }"
bVal "{ Class: SmallInteger }"|
index := 1 + (((width * y) + x) * 3).
rVal := bytes at:(index).
gVal := bytes at:(index + 1).
bVal := bytes at:(index + 2).
^ (((rVal bitShift:8) bitOr:gVal) bitShift:8) bitOr:bVal
! !
!Depth24Image methodsFor:'converting rgb images'!
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.
Redefined to make use of knowing that pixels are 24-bit values."
|f dH nDither v range
greyMap1 greyMap2 greyLevels outBits
bytesPerOutRow "{Class: SmallInteger }"
bytesPerRow "{Class: SmallInteger }"
w "{Class: SmallInteger }"
h "{Class: SmallInteger }"|
photometric ~~ #rgb ifTrue:[
self error:'invalid format'.
^ nil
].
nDither := ditherMatrix size.
dH := nDither / dW.
w := width.
h := height.
greyLevels := 1 bitShift:depth.
bytesPerRow := self bytesPerRow.
bytesPerOutRow := (w * depth + 7) // 8.
outBits := ByteArray uninitializedNew:(bytesPerOutRow * h).
(outBits isNil or:[bytes isNil]) ifTrue:[
^ nil
].
greyMap1 := Array new:256.
greyMap2 := Array new:256.
range := greyLevels-1.
1 to:256 do:[:i |
v := (range / 255 * (i-1)).
greyMap1 at:i put:v.
greyMap2 at:i put:v.
].
greyMap1 := (greyMap1 collect:[:b | b isNil ifTrue:[
0
] ifFalse:[
b truncated
]
]) asByteArray.
greyMap2 := (greyMap2 collect:[:el |
el isNil ifTrue:[
0
] ifFalse:[
((el - el truncated) "/ the error (0..1)
* nDither) rounded
]]) asByteArray.
%{
int __dW = __intVal(dW);
int __dH = __intVal(dH);
int __byte;
int __nDither = __intVal(nDither);
int __dT, __dO;
int __depth = __intVal(depth);
int __dstIdx = 0;
int __srcIdx = 0;
int __bitCnt;
int __grey;
int __w = __intVal(w);
int __h = __intVal(h);
int __x;
int __y;
int __oX, __oY, __dY;
int __nextDst;
int __nextSrc;
int __bytesPerRow = __intVal(bytesPerRow);
int __bytesPerOutRow = __intVal(bytesPerOutRow);
int __pixel;
char *__outBits = __ByteArrayInstPtr(outBits)->ba_element;
unsigned char *__ditherMatrix = __ByteArrayInstPtr(ditherMatrix)->ba_element;
unsigned char *__bytes = __ByteArrayInstPtr(__INST(bytes))->ba_element;
unsigned char *__greyMap1 = __ByteArrayInstPtr(greyMap1)->ba_element;
unsigned char *__greyMap2 = __ByteArrayInstPtr(greyMap2)->ba_element;
__oY = __dY = 0;
for (__y=0; __y<__h; __y++) {
__nextDst = __dstIdx + __bytesPerOutRow;
__nextSrc = __srcIdx + __bytesPerRow;
__byte = 0;
__bitCnt = 8;
__oX = 0;
for (__x=0; __x<__w; __x++) {
__grey = (__bytes[__srcIdx] * 3) /* 0.3*r + 0.6*g + b -> 0..2550 */
+ (__bytes[__srcIdx+1] * 6)
+ __bytes[__srcIdx+2];
__grey = __grey / 10; /* 0 .. 255 */
__pixel = __greyMap1[__grey]; /* 0..(greyLevels-1) */
__dO = __greyMap2[__grey]; /* 0.. nDither-1) */
__dT = __ditherMatrix[__dY + __oX];
if (__dO > __dT) /* dither says: next pixel */
__pixel++;
__srcIdx += 3;
__oX++;
if (__oX == __dW) __oX = 0;
__byte = (__byte << __depth) | __pixel;
__bitCnt = __bitCnt - __depth;
if (__bitCnt == 0) {
__outBits[__dstIdx] = __byte;
__dstIdx++;
__byte = 0;
__bitCnt = 8;
}
}
if (__bitCnt != 8) {
__byte = __byte << __bitCnt;
__outBits[__dstIdx] = __byte;
}
__oY++; __dY += __dW;
if (__oY == __dH) {
__oY = 0;
__dY = 0;
}
__srcIdx = __nextSrc;
__dstIdx = __nextDst;
}
%}.
^ outBits
"
|i|
i := Image fromFile:'bitmaps/granite.tiff'.
i asOrderedDitheredMonochromeImage inspect.
i asOrderedDitheredDepth2GrayImage inspect.
i asOrderedDitheredDepth4GrayImage inspect.
i asOrderedDitheredDepth8GrayImage inspect.
"
"Created: 7.6.1996 / 10:48:06 / cg"
"Modified: 7.6.1996 / 11:08:50 / cg"
!
orderedDitheredMonochromeBitsWithDitherMatrix:ditherMatrix ditherWidth:dW
"return the dithered monochrome bits for the receiver image;
with a constant ditherMatrix, this can be used for thresholding.
Redefined to make use of knowing that pixels are 24-bit values."
|f dH nDither
greyMap monoBits
bytesPerMonoRow "{Class: SmallInteger }"
bytesPerRow "{Class: SmallInteger }"
w "{Class: SmallInteger }"
h "{Class: SmallInteger }"|
photometric ~~ #rgb ifTrue:[
self error:'invalid format'.
^ nil
].
nDither := ditherMatrix size.
dH := nDither / dW.
w := width.
h := height.
bytesPerRow := self bytesPerRow.
bytesPerMonoRow := w + 7 // 8.
monoBits := ByteArray uninitializedNew:(bytesPerMonoRow * h).
(monoBits isNil or:[bytes isNil]) ifTrue:[
^ nil
].
%{
int __dW = __intVal(dW);
int __dH = __intVal(dH);
int __byte;
int __nDither = __intVal(nDither);
int __dT;
int __dstIdx = 0;
int __srcIdx = 0;
int __bitCnt;
int __grey;
int __w = __intVal(w);
int __h = __intVal(h);
int __x;
int __y;
int __oX, __oY, __dY;
int __nextDst;
int __nextSrc;
int __bytesPerRow = __intVal(bytesPerRow);
int __bytesPerMonoRow = __intVal(bytesPerMonoRow);
char *__monoBits = __ByteArrayInstPtr(monoBits)->ba_element;
unsigned char *__ditherMatrix = __ByteArrayInstPtr(ditherMatrix)->ba_element;
unsigned char *__bytes = __ByteArrayInstPtr(__INST(bytes))->ba_element;
__oY = __dY = 0;
for (__y=0; __y<__h; __y++) {
__nextDst = __dstIdx + __bytesPerMonoRow;
__nextSrc = __srcIdx + __bytesPerRow;
__byte = 0;
__bitCnt = 8;
__oX = 0;
for (__x=0; __x<__w; __x++) {
__grey = (__bytes[__srcIdx] * 3) /* 0.3*r + 0.6*g + b -> 0..2550 */
+ (__bytes[__srcIdx+1] * 6)
+ __bytes[__srcIdx+2];
__grey = __grey * (__nDither+1) / 2550; /* 0 .. nDither+1 */
__srcIdx += 3;
__dT = __ditherMatrix[__dY + __oX];
__oX++;
if (__oX == __dW) __oX = 0;
__byte = __byte << 1;
if (__grey > __dT) {
__byte = __byte | 1; /* white */
}
__bitCnt--;
if (__bitCnt == 0) {
__monoBits[__dstIdx] = __byte;
__dstIdx++;
__byte = 0;
__bitCnt = 8;
}
}
if (__bitCnt != 8) {
__byte = __byte << __bitCnt;
__monoBits[__dstIdx] = __byte;
}
__oY++; __dY += __dW;
if (__oY == __dH) {
__oY = 0;
__dY = 0;
}
__srcIdx = __nextSrc;
__dstIdx = __nextDst;
}
%}.
^ monoBits
"
|i f|
i := Image fromFile:'bitmaps/granite.tiff'.
f := i asOrderedDitheredMonochromeFormOn:Display.
"
"Created: 7.6.1996 / 10:48:06 / cg"
"Modified: 7.6.1996 / 11:08:50 / cg"
!
rgbImageAs2PlaneFormOn:aDevice
"return a 2-bit device form for aDevice from the rgb picture,
using a threshold algorithm.
(i.e. grey value < 0.25 -> black // 0.25..0.5 -> darkgrey //
0.5 .. 0.75 -> lightgrey // > 0.75 -> white)."
|twoPlaneBits f
map rMap gMap bMap
failed
r "{ Class: SmallInteger }"
g "{ Class: SmallInteger }"
b "{ Class: SmallInteger }"
v "{ Class: SmallInteger }"
w "{ Class: SmallInteger }"
h "{ Class: SmallInteger }"
srcIndex "{ Class: SmallInteger }"
dstIndex "{ Class: SmallInteger }"
bits "{ Class: SmallInteger }"
bitCount "{ Class: SmallInteger }" |
w := width.
h := height.
twoPlaneBits := ByteArray uninitializedNew:(((w * 2 + 7) // 8) * h).
failed := true.
%{
register unsigned char *srcPtr, *dstPtr;
register _v, _bits, _bitCount;
register j;
register i;
if ((__Class(_INST(bytes)) == ByteArray)
&& (__Class(twoPlaneBits) == ByteArray)) {
failed = false;
srcPtr = _ByteArrayInstPtr(_INST(bytes))->ba_element;
dstPtr = _ByteArrayInstPtr(twoPlaneBits)->ba_element;
for (i=_intVal(h); i>0; i--) {
_bitCount = 0;
_bits = 0;
for (j=_intVal(w); j>0; j--) {
_v = (*srcPtr++ * 3); /* 0.3*r + 0.6*g + b */
_v += (*srcPtr++ * 6);
_v += *srcPtr++;
_v /= 10;
_bits <<= 2;
_bits |= (_v >> 6); /* take top 2 bits */
_bitCount++;
if (_bitCount == 4) {
*dstPtr++ = _bits;
_bits = 0;
_bitCount = 0;
}
}
if (_bitCount != 0) {
while (_bitCount++ != 4) _bits <<= 2;
*dstPtr++ = _bits;
}
}
}
%}.
failed ifTrue:[
"/ the above is equivalent to:
"/
"/ srcIndex := 1.
"/ dstIndex := 1.
"/ 1 to:h do:[:row |
"/ bitCount := 0.
"/ bits := 0.
"/ 1 to:w do:[:col |
"/ r := bytes at:srcIndex.
"/ srcIndex := srcIndex + 1.
"/ g := bytes at:srcIndex.
"/ srcIndex := srcIndex + 1.
"/ b := bytes at:srcIndex.
"/ srcIndex := srcIndex + 1.
"/ v := ((3 * r) + (6 * g) + (1 * b)) // 10.
"/ v := v bitShift:-6. "take 2 hi bits"
"/ bits := (bits bitShift:2) bitOr:v.
"/ bitCount := bitCount + 1.
"/ (bitCount == 4) ifTrue:[
"/ twoPlaneBits at:dstIndex put:bits.
"/ dstIndex := dstIndex + 1.
"/ bits := 0.
"/ bitCount := 0
"/ ]
"/ ].
"/ (bitCount ~~ 0) ifTrue:[
"/ [bitCount == 4] whileFalse:[
"/ bitCount := bitCount + 1.
"/ bits := bits bitShift:2.
"/ ].
"/ twoPlaneBits at:dstIndex put:bits.
"/ dstIndex := dstIndex + 1
"/ ]
"/ ]
self primitiveFailed.
^ nil
].
f := Form width:width height:height depth:2 on:aDevice.
f isNil ifTrue:[^ nil].
f initGC.
(aDevice blackpixel == 0) ifFalse:[
"have to invert bits"
f function:#copyInverted
].
aDevice drawBits:twoPlaneBits depth:2 width:width height:height
x:0 y:0
into:(f id) x:0 y:0 width:width height:height with:(f gcId).
^ f
!
rgbImageAs8BitGreyFormOn:aDevice
"return an 8-bit greyForm from the rgb picture"
^ Form
width:width
height:height
fromArray:(self threshold8BitGreyBits)
"Modified: 8.6.1996 / 13:58:08 / cg"
!
rgbImageAs8BitGreyImage
"return an 8-bit grey image from the rgb picture.
Pixel values are reduced to a 0..255 grey level."
^ Depth8Image
width:width
height:height
fromArray:(self threshold8BitGreyBits)
"
|i|
i := Image fromFile:'bitmaps/granite.tiff'.
i rgbImageAs8BitGreyImage inspect
"
"
|i|
i := Image fromFile:'bitmaps/granite.tiff'.
(i rgbImageAs8BitGreyImage asOrderedDitheredGrayImageDepth:2) inspect
"
"
|i|
i := Image fromFile:'bitmaps/granite.tiff'.
(i rgbImageAs8BitGreyImage asOrderedDitheredGrayImageDepth:4) inspect
"
"
|i|
i := Image fromFile:'bitmaps/granite.tiff'.
i rgbImageAs8BitGreyImage asOrderedDitheredMonochromeImage inspect
"
"Created: 8.6.1996 / 13:58:46 / cg"
"Modified: 8.6.1996 / 14:02:05 / cg"
!
rgbImageAsDitheredPseudoFormOn:aDevice
"return a dithered pseudocolor form from the rgb-picture.
This method depends on fixColors being allocated (see Color>>getColors*)"
^ self rgbImageAsDitheredPseudoFormOn:aDevice
colors:Color fixColors
nRed:Color numFixRed
nGreen:Color numFixGreen
nBlue:Color numFixBlue
!
rgbImageAsDitheredPseudoFormOn:aDevice colors:fixColors nRed:nRed nGreen:nGreen nBlue:nBlue
"return a dithered pseudocolor form from the rgb-picture"
|pseudoBits f
h "{ Class: SmallInteger }"
w "{ Class: SmallInteger }"
"/ eR "{Class: SmallInteger }"
"/ eG "{Class: SmallInteger }"
"/ eB "{Class: SmallInteger }"
"/ wantR "{Class: SmallInteger }"
"/ wantG "{Class: SmallInteger }"
"/ wantB "{Class: SmallInteger }"
fixR "{Class: SmallInteger }"
fixG "{Class: SmallInteger }"
fixB "{Class: SmallInteger }"
srcIndex "{ Class: SmallInteger }"
dstIndex "{ Class: SmallInteger }"
deviceDepth has8BitImage
fixIds failed|
aDevice ~~ Display ifTrue:[^ nil].
fixR := nRed.
fixR == 0 ifTrue:[ ^ nil].
fixG := nGreen.
fixG == 0 ifTrue:[ ^ nil].
fixB := nBlue.
fixB == 0 ifTrue:[ ^ nil].
"/ simple check
(fixR * fixG * fixB) ~~ fixColors size ifTrue:[
self error:'invalid color array passed'.
^ nil
].
fixIds := (fixColors asArray collect:[:clr | clr colorId]) asByteArray.
deviceDepth := aDevice depth.
deviceDepth == 8 ifTrue:[
has8BitImage := true.
] ifFalse:[
has8BitImage := false.
aDevice supportedImageFormats do:[:fmt |
(fmt at:#bitsPerPixel) == 8 ifTrue:[
has8BitImage := true.
]
]
].
has8BitImage ifFalse:[^ nil].
'D24IMAGE: dithering ...' infoPrintNL.
pseudoBits := ByteArray uninitializedNew:(width * height).
h := height.
w := width.
%{
int __x, __y;
int __eR, __eG, __eB;
int __wantR, __wantG, __wantB;
unsigned char *srcP, *dstP;
unsigned char *redP, *greenP, *blueP;
int pix;
unsigned char *idP;
int __fR, __fG, __fB;
int iR, iG, iB;
int idx;
if (__isByteArray(_INST(bytes))
&& __isByteArray(pseudoBits)
&& __isByteArray(fixIds)
&& __bothSmallInteger(fixR, fixG)
&& __isSmallInteger(fixB)) {
failed = false;
srcP = _ByteArrayInstPtr(_INST(bytes))->ba_element;
dstP = _ByteArrayInstPtr(pseudoBits)->ba_element;
idP = _ByteArrayInstPtr(fixIds)->ba_element;
__fR = _intVal(fixR)-1;
__fG = _intVal(fixG)-1;
__fB = _intVal(fixB)-1;
for (__y=_intVal(h); __y>0; __y--) {
__eR = __eG = __eB = 0;
for (__x=_intVal(w); __x>0; __x--) {
int t;
int __want;
/*
* wR, wG and wB is the wanted r/g/b value;
* compute the index into the dId table ..
* values: 0..255; scale to 0..fR-1, 0..fG-1, 0..fB-1
*
* bad kludge: knows how to index into FixColor table
*/
__wantR = srcP[0] + __eR;
__wantG = srcP[1] + __eG;
__wantB = srcP[2] + __eB;
srcP += 3;
if (__wantR > 255) __want = 255;
else if (__wantR < 0) __want = 0;
else __want = __wantR;
iR = __want * __fR / 128;
iR = (iR / 2) + (iR & 1);
idx = iR * (__fG+1);
if (__wantG > 255) __want = 255;
else if (__wantG < 0) __want = 0;
else __want = __wantG;
iG = __want * __fG / 128;
iG = (iG / 2) + (iG & 1);
idx = (idx + iG) * (__fB+1);
if (__wantB > 255) __want = 255;
else if (__wantB < 0) __want = 0;
else __want = __wantB;
iB = __want * __fB / 128;
iB = (iB / 2) + (iB & 1);
idx = idx + iB;
/*
* store the corresponding dither colorId
*/
*dstP++ = idP[idx];
/*
* the new error:
*/
__eR = __wantR - (iR * 256 / __fR);
__eG = __wantG - (iG * 256 / __fG);
__eB = __wantB - (iB * 256 / __fB);
}
}
}
%}.
failed ifTrue:[
self primitiveFailed.
^ nil
"/ for non-C programmers:
"/ the above code is (roughly) equivalent to:
"/ srcIndex := 1.
"/ dstIndex := 1.
"/ 1 to:h do:[:y |
"/ eR := eG := eB := 0.
"/ 1 to:w do:[:x |
"/ |pixel "{ Class: SmallInteger }"
"/ clr
"/ idx "{ Class: SmallInteger }"
"/ iR "{ Class: SmallInteger }"
"/ iG "{ Class: SmallInteger }"
"/ iB "{ Class: SmallInteger }"
"/ wR "{ Class: SmallInteger }"
"/ wG "{ Class: SmallInteger }"
"/ wB "{ Class: SmallInteger }" |
"/
"/ wantR := ((bytes at:srcIndex) + eR). srcIndex := srcIndex + 1.
"/ wantG := ((bytes at:srcIndex) + eG). srcIndex := srcIndex + 1.
"/ wantB := ((bytes at:srcIndex) + eB). srcIndex := srcIndex + 1.
"/ wR := wantR.
"/ wR > 255 ifTrue:[wR := 255] ifFalse:[wR < 0 ifTrue:[wR := 0]].
"/ wG := wantG.
"/ wG > 255 ifTrue:[wG := 255] ifFalse:[wG < 0 ifTrue:[wG := 0]].
"/ wB := wantB.
"/ wB > 255 ifTrue:[wB := 255] ifFalse:[wB < 0 ifTrue:[wB := 0]].
"/
"/ iR := wR * (fixR-1) // 128.
"/ iR := (iR // 2) + (iR bitAnd:1).
"/ iG := wG * (fixG-1) // 128.
"/ iG := (iG // 2) + (iG bitAnd:1).
"/ iB := wB * (fixB-1) // 128.
"/ iB := (iB // 2) + (iB bitAnd:1).
"/ idx := (iR * fixR + iG) * fixB + iB + 1.
"/
"/ clr := fixColors at:idx.
"/
"/ eR := wantR - (clr red * 2) asInteger.
"/ eG := wantG - (clr green * 2) asInteger.
"/ eB := wantB - (clr blue * 2) asInteger.
"/
"/ pixel := clr colorId.
"/ pseudoBits at:dstIndex put:pixel.
"/
"/ dstIndex := dstIndex + 1
"/ ].
].
f := Form width:width height:height depth:aDevice depth on:aDevice.
f isNil ifTrue:[^ nil].
f colorMap:fixColors.
f initGC.
aDevice drawBits:pseudoBits bitsPerPixel:8 depth:aDevice depth
width:width height:height
x:0 y:0
into:(f id) x:0 y:0 width:width height:height with:(f gcId).
^ f
!
rgbImageAsGreyFormOn:aDevice
"convert an rgb image to a grey image for greyscale displays"
|deviceDepth|
deviceDepth := aDevice depth.
"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
].
"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
].
(deviceDepth == 8) ifTrue:[
^ self rgbImageAs8BitGreyFormOn:aDevice
].
"mhmh need another converter ...
till then we do:"
DitherAlgorithm == #error ifTrue:[
^ self rgbImageAsErrorDitheredGreyFormOn:aDevice
].
DitherAlgorithm == #pattern ifTrue:[
^ self rgbImageAsPatternDitheredGreyFormOn:aDevice
].
^ self rgbImageAsMonoFormOn:aDevice
!
rgbImageAsMonoFormOn:aDevice
"return a 1-bit monochrome form for aDevice from the rgb picture,
using a threshold algorithm.
(i.e. grey value < 0.5 -> black, grey value >= 0.5 -> white)."
^ self
asThresholdMonochromeFormOn:aDevice
"
|i|
i := Image fromFile:'bitmaps/granite.tiff'.
(i asThresholdMonochromeFormOn:Display) inspect
"
"
|i|
i := Image fromFile:'bitmaps/granite.tiff'.
(i
asOrderedDitheredMonochromeImageWithDitherMatrix:#[7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7]
ditherWidth:4) inspect
"
"
|i|
i := Image fromFile:'bitmaps/granite.tiff'.
(i
asOrderedDitheredMonochromeImageWithDitherMatrix:#[5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5]
ditherWidth:4) inspect
"
"
|i|
i := Image fromFile:'bitmaps/granite.tiff'.
(i
asOrderedDitheredMonochromeImageWithDitherMatrix:#[4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4]
ditherWidth:4) inspect
"
"Modified: 8.6.1996 / 14:08:21 / cg"
!
rgbImageAsPatternDitheredGreyFormOn: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."
|f depth
nDither "{Class: SmallInteger }"
nColors "{Class: SmallInteger }"
v "{Class: SmallInteger }"
h "{Class: SmallInteger }"
w "{Class: SmallInteger }"
srcIndex "{Class: SmallInteger }"
dstIndex "{Class: SmallInteger }"
mask "{Class: SmallInteger }"
outBits "{Class: SmallInteger }"
outCount "{Class: SmallInteger }"
patternOffset "{Class: SmallInteger }"
patternBits "{Class: SmallInteger }"
run "{Class: SmallInteger }"
r "{Class: SmallInteger }"
g "{Class: SmallInteger }"
b "{Class: SmallInteger }"
index "{Class: SmallInteger }"
p0 "{Class: SmallInteger }"
p1 "{Class: SmallInteger }"
map last clr
patterns formBytes patternBytes
pixel0bytes pixel1bytes ditherPattern
ditherColors first delta|
depth := aDevice depth.
depth == 1 ifTrue:[
^ self asOrderedDitheredMonochromeFormOn:aDevice
].
(depth == 2
or:[depth == 4
or:[depth == 8]]) ifTrue:[
^ (Form
width:width
height:height
depth:depth)
bits:(
self
orderedDitheredBitsWithDitherMatrix:(self class orderedDitherMatrixOfSize:8)
ditherWidth:8
depth:depth)
].
"/ funny output depth ....
Transcript showCR:'dithering ..'. Transcript endEntry.
h := height.
w := width.
nDither := NumberOfDitherColors.
ditherColors := Array new:nDither.
first := (100 / nDither / 2).
delta := 100 / nDither.
0 to:nDither-1 do:[:i |
ditherColors at:i+1 put:(Color gray:(i * delta + first)).
].
nColors := 256.
map := Array new:256.
1 to:256 do:[:i |
v := i - 1.
" v is now in the range 0 .. 255 "
v := (v * (nDither - 1) // 255) rounded.
" v is now 0 .. nDither-1 "
map at:i put:(ditherColors at:(v + 1))
].
"tuning - code below is so slooow"
"get the patterns, fill form bytes here"
w := width.
h := height.
"draw each pixel using dither color (let others do the dithering)
although the code is simple, its very slow"
f := Form width:w height:h depth:(aDevice depth) on:aDevice.
f isNil ifTrue:[^ nil].
f initGC.
"draw each pixel using dither color"
srcIndex := 1.
0 to:h-1 do:[:dstY |
run := 0.
last := nil.
0 to:w-1 do:[:dstX |
r := bytes at:srcIndex.
srcIndex := srcIndex + 1.
g := bytes at:srcIndex.
srcIndex := srcIndex + 1.
b := bytes at:srcIndex.
srcIndex := srcIndex + 1.
v := ((3 * r) + (6 * g) + (1 * b)) // 10.
clr := map at:(v + 1).
clr == last ifTrue:[
run := run + 1
] ifFalse:[
(run ~~ 0) ifTrue:[
f fillRectangleX:dstX-run y:dstY width:run height:1.
].
run := 1.
f paint:clr.
last := clr
].
].
f fillRectangleX:width-run y:dstY width:run height:1.
].
^ f
"Modified: 8.6.1996 / 15:19:34 / cg"
!
rgbImageAsPseudoFormOn:aDevice
"return a pseudocolor form from the rgb-picture"
|pseudoBits f
r "{ Class: SmallInteger }"
g "{ Class: SmallInteger }"
b "{ Class: SmallInteger }"
srcIndex "{ Class: SmallInteger }"
dstIndex "{ Class: SmallInteger }"
rMask "{ Class: SmallInteger }"
gMask "{ Class: SmallInteger }"
bMask "{ Class: SmallInteger }"
redArray greenArray blueArray
dataSize "{ Class: SmallInteger }"
nColors "{ Class: SmallInteger }"
fit fitMap colors color
fast
colorIndex "{ Class: SmallInteger }"
depth nColorCells deep|
Color fixColors notNil ifTrue:[
f := self rgbImageAsDitheredPseudoFormOn:aDevice.
f notNil ifTrue:[^ f].
].
"find used colors; build color-tree"
fit := false.
fitMap := false.
depth := aDevice depth.
nColorCells := aDevice ncells.
deep := (depth > 8).
rMask := 2r11111111.
gMask := 2r11111111.
bMask := 2r11111111.
'D24IMAGE: allocating colors ...' infoPrintNL.
[fit] whileFalse:[
[fitMap] whileFalse:[
srcIndex := 1.
redArray := Array new:256.
"
find used colors, build [r][g][b] 3-dimensional array
containing true for used colors
"
nColors := 0.
srcIndex := 1.
dataSize := bytes size.
[srcIndex < dataSize] whileTrue:[
%{
if (__isByteArray(_INST(bytes))) {
int sI = _intVal(srcIndex);
unsigned char *cp = _ByteArrayInstPtr(_INST(bytes))->ba_element;
r = __MKSMALLINT((cp[sI - 1] & _intVal(rMask)) + 1);
g = __MKSMALLINT((cp[sI] & _intVal(gMask)) + 1);
b = __MKSMALLINT((cp[sI + 1] & _intVal(bMask)) + 1);
srcIndex = __MKSMALLINT(sI + 3);
fast = true;
} else {
fast = false;
}
%}
.
fast ifFalse:[
r := bytes at:srcIndex.
r := (r bitAnd:rMask) + 1.
srcIndex := srcIndex + 1.
g := bytes at:srcIndex.
g := (g bitAnd:gMask) + 1.
srcIndex := srcIndex + 1.
b := bytes at:srcIndex.
b := (b bitAnd:bMask) + 1.
srcIndex := srcIndex + 1
].
greenArray := redArray at:r.
greenArray isNil ifTrue:[
greenArray := Array new:256.
redArray at:r put:greenArray
].
blueArray := greenArray at:g.
blueArray isNil ifTrue:[
deep ifTrue:[blueArray := Array new:256]
ifFalse:[blueArray := ByteArray new:256].
greenArray at:g put:blueArray
].
(blueArray at:b) == 0 ifTrue:[
blueArray at:b put:1.
nColors := nColors + 1.
(nColors > nColorCells) ifTrue:[
'D24IMAGE: more than ' infoPrint. nColorCells infoPrint. ' colors' infoPrintNL.
srcIndex := dataSize + 1
]
]
].
"again with less color bits if it does not fit colormap"
(nColors <= nColorCells) ifTrue:[
fitMap := true
] ifFalse:[
"must try again - cutting off some bits"
(bMask == 2r11111111) ifTrue:[
bMask := 2r11111110
] ifFalse:[
(bMask == 2r11111110) ifTrue:[
bMask := 2r11111100
] ifFalse:[
rMask := (rMask bitShift:1) bitAnd:2r11111111.
gMask := (gMask bitShift:1) bitAnd:2r11111111.
bMask := (bMask bitShift:1) bitAnd:2r11111111
]
].
'D24IMAGE: too many colors; retry with less color resolution' infoPrintNL.
"
'masks:' print. rMask print. ' ' print. gMask print. ' ' print.
bMask printNewline
"
]
].
'D24IMAGE: ' infoPrint. nColors infoPrint. ' colors used' infoPrintNL.
colors := Array new:nColors.
colorIndex := 1.
"
now, we have reduced things to the number of colors
which are theoretically supported by the devices colormap.
allocate all used colors in walking over true entries in
the [r][g][b] table - this may still fail
"
fit := true.
r := 0.
redArray do:[:greenArray |
(fit and:[greenArray notNil]) ifTrue:[
g := 0.
greenArray do:[:blueArray |
(fit and:[blueArray notNil]) ifTrue:[
b := 0.
blueArray do:[:present |
|id|
(fit and:[present ~~ 0]) ifTrue:[
color := Color red:(r * 100.0 / 255.0)
green:(g * 100.0 / 255.0)
blue:(b * 100.0 / 255.0).
color := color on:aDevice.
(id := color colorId) isNil ifTrue:[
fit := false
] ifFalse:[
colors at:colorIndex put:color.
colorIndex := colorIndex + 1.
blueArray at:(b + 1) put:id
]
].
b := b + 1
]
].
g := g + 1
]
].
r := r + 1
].
"again with less color bits if we did not get all colors"
fit ifFalse:[
'D24IMAGE: could not allocate color(s)' infoPrintNL.
"free the allocated colors"
colors atAllPut:nil.
"a kludge - force immediate freeing of colors"
ObjectMemory scavenge; finalize.
"cut off one more color-bit - cut off blue first"
(bMask == 2r11111111) ifTrue:[
bMask := 2r11111110
] ifFalse:[
(bMask == 2r11111110) ifTrue:[
bMask := 2r11111100
] ifFalse:[
rMask := (rMask bitShift:1) bitAnd:2r11111111.
gMask := (gMask bitShift:1) bitAnd:2r11111111.
bMask := (bMask bitShift:1) bitAnd:2r11111111
]
].
fitMap := false.
redArray := nil
]
].
"create pseudocolor bits and translate"
pseudoBits := ByteArray uninitializedNew:(width * height).
srcIndex := 1.
dstIndex := 1.
(rMask == 2r11111111
and:[gMask == 2r11111111
and:[bMask == 2r11111111]]) ifTrue:[
[srcIndex < dataSize] whileTrue:[
r := bytes at:srcIndex.
srcIndex := srcIndex + 1.
g := bytes at:srcIndex.
srcIndex := srcIndex + 1.
b := bytes at:srcIndex.
srcIndex := srcIndex + 1.
greenArray := redArray at:(r + 1).
blueArray := greenArray at:(g + 1).
pseudoBits at:dstIndex put:(blueArray at:(b + 1)).
dstIndex := dstIndex + 1
]
] ifFalse:[
[srcIndex < dataSize] whileTrue:[
r := bytes at:srcIndex.
r := r bitAnd:rMask.
srcIndex := srcIndex + 1.
g := bytes at:srcIndex.
g := g bitAnd:gMask.
srcIndex := srcIndex + 1.
b := bytes at:srcIndex.
b := b bitAnd:bMask.
srcIndex := srcIndex + 1.
greenArray := redArray at:(r + 1).
blueArray := greenArray at:(g + 1).
pseudoBits at:dstIndex put:(blueArray at:(b + 1)).
dstIndex := dstIndex + 1
]
].
f := Form width:width height:height depth:depth on:aDevice.
f isNil ifTrue:[^ nil].
f colorMap:colors.
f initGC.
aDevice drawBits:pseudoBits bitsPerPixel:8 depth:depth
width:width height:height
x:0 y:0
into:(f id) x:0 y:0 width:width height:height with:(f gcId).
^ f
!
rgbImageAsTrueColorFormOn:aDevice
"return a truecolor form from the rgb-picture."
|bestFormat usedDeviceDepth usedDeviceBitsPerPixel depth
myDepth form imageBits destIndex srcIndex
rightShiftR rightShiftG rightShiftB shiftRed shiftGreen shiftBlue ok|
bestFormat := self bestSupportedImageFormatFor:aDevice.
usedDeviceDepth := bestFormat at:#depth.
usedDeviceBitsPerPixel := bestFormat at:#bitsPerPixel.
rightShiftR := (8 - aDevice bitsRed).
rightShiftG := (8 - aDevice bitsGreen).
rightShiftB := (8 - aDevice bitsBlue).
shiftRed := aDevice shiftRed.
shiftGreen := aDevice shiftGreen.
shiftBlue := aDevice shiftBlue.
"/
"/ for now, only a few formats are supported
"/
myDepth := self bitsPerPixel.
myDepth == usedDeviceBitsPerPixel ifTrue:[
"/
"/ first, the trivial case, where the depths match
"/ 24 bit/pixel
"/
imageBits := bytes.
] ifFalse:[
"/
"/ 16 bit/pixel ...
"/
(usedDeviceBitsPerPixel == 16) ifTrue:[
imageBits := ByteArray uninitializedNew:(width * height * 2).
"/ now, walk over the image and compose 16bit values from the r/g/b triples
ok := false.
%{ /* OPTIONAL */
if (__bothSmallInteger(_INST(height),_INST(width))
&& __bothSmallInteger(rightShiftR, shiftRed)
&& __bothSmallInteger(rightShiftG, shiftGreen)
&& __bothSmallInteger(rightShiftB, shiftBlue)
&& __isByteArray(_INST(bytes))
&& __isByteArray(imageBits)) {
int rShRed = __intVal(rightShiftR),
rShGreen = __intVal(rightShiftG),
rShBlue = __intVal(rightShiftB),
lShRed = __intVal(shiftRed),
lShGreen = __intVal(shiftGreen),
lShBlue = __intVal(shiftBlue);
int x, y, w;
unsigned char *srcPtr = _ByteArrayInstPtr(_INST(bytes))->ba_element;
char *dstPtr = _ByteArrayInstPtr(imageBits)->ba_element;
w = __intVal(_INST(width));
if ((rShRed == 0) && (rShGreen == 0) && (rShBlue == 0)) {
for (y=__intVal(_INST(height)); y > 0; y--) {
for (x=w; x > 0; x--) {
unsigned v;
v = srcPtr[0] << lShRed;
v |= (srcPtr[1] << lShGreen);
v |= (srcPtr[2] << lShBlue);
# ifdef MSBFIRST
((short *)dstPtr)[0] = v;
# else
dstPtr[0] = (v>>8) & 0xFF;
dstPtr[1] = (v) & 0xFF;
# endif
dstPtr += 2;
srcPtr += 3;
}
}
} else {
for (y=__intVal(_INST(height)); y > 0; y--) {
for (x=w; x > 0; x--) {
unsigned r, g, b, v;
r = srcPtr[0] >> rShRed;
g = srcPtr[1] >> rShGreen;
b = srcPtr[2] >> rShBlue;
v = r << lShRed;
v |= (g << lShGreen);
v |= (b << lShBlue);
# ifdef MSBFIRST
((short *)dstPtr)[0] = v;
# else
dstPtr[0] = (v>>8) & 0xFF;
dstPtr[1] = (v) & 0xFF;
# endif
dstPtr += 2;
srcPtr += 3;
}
}
}
ok = true;
}
%}.
ok ifFalse:[
"/ this fallback is only executed if type is not
"/ what the primitive expects; for example, if the bytes-instvar
"/ is not a ByteArray
rightShiftR := rightShiftR negated.
rightShiftG := rightShiftG negated.
rightShiftB := rightShiftB negated.
destIndex := 1.
srcIndex := 1.
0 to:height-1 do:[:y |
0 to:width-1 do:[:x |
|r g b v|
r := bytes at:srcIndex.
g := bytes at:(srcIndex + 1).
b := bytes at:(srcIndex + 2).
r := r bitShift:rightShiftR.
g := g bitShift:rightShiftG.
b := b bitShift:rightShiftB.
v := r bitShift:shiftRed.
v := v bitOr:(g bitShift:shiftGreen).
v := v bitOr:(b bitShift:shiftBlue).
imageBits wordAt:destIndex put:v MSB:true.
destIndex := destIndex + 2.
srcIndex := srcIndex + 3.
]
]
]
] ifFalse:[
"/
"/ 32bit pixels
"/
(usedDeviceBitsPerPixel == 32) ifTrue:[
imageBits := ByteArray uninitializedNew:(width * height * 4).
"/ now, walk over the image and compose 32bit values from the r/g/b triples
ok := false.
%{ /* OPTIONAL */
if (__bothSmallInteger(_INST(height), _INST(width))
&& __bothSmallInteger(rightShiftR, shiftRed)
&& __bothSmallInteger(rightShiftG, shiftGreen)
&& __bothSmallInteger(rightShiftB, shiftBlue)
&& __isByteArray(_INST(bytes))
&& __isByteArray(imageBits)) {
int rShRed = __intVal(rightShiftR),
rShGreen = __intVal(rightShiftG),
rShBlue = __intVal(rightShiftB),
lShRed = __intVal(shiftRed),
lShGreen = __intVal(shiftGreen),
lShBlue = __intVal(shiftBlue);
int x, y, w;
unsigned char *srcPtr = _ByteArrayInstPtr(_INST(bytes))->ba_element;
char *dstPtr = _ByteArrayInstPtr(imageBits)->ba_element;
w = __intVal(_INST(width));
if ((rShRed == 0) && (rShGreen == 0) && (rShBlue == 0)) {
for (y=__intVal(_INST(height)); y > 0; y--) {
for (x=w; x > 0; x--) {
unsigned v;
v = srcPtr[0] << lShRed;
v |= (srcPtr[1] << lShGreen);
v |= (srcPtr[2] << lShBlue);
# ifdef MSBFIRST
((int *)dstPtr)[0] = v;
# else
dstPtr[0] = (v>>24) & 0xFF;
dstPtr[1] = (v>>16) & 0xFF;
dstPtr[2] = (v>>8) & 0xFF;
dstPtr[3] = (v) & 0xFF;
# endif
dstPtr += 4;
srcPtr += 3;
}
}
} else {
for (y=__intVal(_INST(height)); y > 0; y--) {
for (x=w; x > 0; x--) {
unsigned r, g, b, v;
r = srcPtr[0] >> rShRed;
g = srcPtr[1] >> rShGreen;
b = srcPtr[2] >> rShBlue;
v = r << lShRed;
v |= (g << lShGreen);
v |= (b << lShBlue);
# ifdef MSBFIRST
((int *)dstPtr)[0] = v;
# else
dstPtr[0] = (v>>24) & 0xFF;
dstPtr[1] = (v>>16) & 0xFF;
dstPtr[2] = (v>>8) & 0xFF;
dstPtr[3] = (v) & 0xFF;
# endif
dstPtr += 4;
srcPtr += 3;
}
}
}
ok = true;
}
%}.
ok ifFalse:[
"/ this fallback is only executed if type is not
"/ what the primitive expects; for example, if the bytes-instvar
"/ is not a ByteArray; or, if this class is autoload on non-compiling
"/ systems.
rightShiftR := rightShiftR negated.
rightShiftG := rightShiftG negated.
rightShiftB := rightShiftB negated.
destIndex := 1.
srcIndex := 1.
0 to:height-1 do:[:y |
0 to:width-1 do:[:x |
|r g b v|
r := bytes at:srcIndex.
g := bytes at:(srcIndex + 1).
b := bytes at:(srcIndex + 2).
r := r bitShift:rightShiftR.
g := g bitShift:rightShiftG.
b := b bitShift:rightShiftB.
v := r bitShift:shiftRed.
v := v bitOr:(g bitShift:shiftGreen).
v := v bitOr:(b bitShift:shiftBlue).
imageBits doubleWordAt:destIndex put:v MSB:true.
destIndex := destIndex + 4.
srcIndex := srcIndex + 3.
]
]
]
].
]
].
imageBits isNil ifTrue:[
'IMAGE: unimplemented trueColor depth in rgbImageAsTrueColorFormOn:' errorPrintNL.
^ self rgbImageAsMonoFormOn:aDevice
].
form := Form width:width height:height depth:usedDeviceDepth on:aDevice.
form isNil ifTrue:[
'IMAGE: display bitmap creation failed' errorPrintNL.
^ nil
].
form initGC.
form
copyBitsFrom:imageBits bitsPerPixel:usedDeviceBitsPerPixel depth:usedDeviceDepth
width:width height:height
x:0 y:0 toX:0 y:0.
^ form
"Modified: 21.10.1995 / 19:30:11 / cg"
!
threshold8BitGreyBits
"return the bits for an 8-bit grey image from the receiver.
Special code, since this is a common case."
|greyBits
srcIndex "{ Class: SmallInteger }"
dstIndex "{ Class: SmallInteger }"|
greyBits := ByteArray uninitializedNew:(width * height).
%{
register unsigned char *srcPtr, *dstPtr;
register __v;
register i;
if ((__Class(__INST(bytes)) == ByteArray)
&& (__Class(greyBits) == ByteArray)) {
srcPtr = __ByteArrayInstPtr(__INST(bytes))->ba_element;
dstPtr = __ByteArrayInstPtr(greyBits)->ba_element;
i = __intVal(__INST(height)) * __intVal(__INST(width));
for (; i > 0; i--) {
__v = (srcPtr[0] * 3); /* 3*r + 6*g + b ; 0 .. 2550 */
__v += (srcPtr[1] * 6);
__v += srcPtr[2];
srcPtr += 3;
__v /= 10; /* 0..255 */
*dstPtr++ = __v ;
}
}
%}.
^ greyBits
! !
!Depth24Image methodsFor:'enumerating'!
colorsAtY:y from:xLow to:xHigh do:aBlock
"perform aBlock for each pixel from x1 to x2 in row y.
The block is passed the color at each pixel.
This method allows slighly faster processing of an
image than using atX:y:, since some processing can be
avoided when going from pixel to pixel. However, for
real image processing, specialized methods should be written."
|srcIndex "{ Class: SmallInteger }"
x1 "{ Class: SmallInteger }"
x2 "{ Class: SmallInteger }"
rVal "{ Class: SmallInteger }"
gVal "{ Class: SmallInteger }"
bVal "{ Class: SmallInteger }"
lastR lastG lastB lastColor|
photometric ~~ #rgb ifTrue:[
^ super colorsAtY:y from:xLow to:xHigh do:aBlock.
].
x1 := xLow.
x2 := xHigh.
srcIndex := 1 + (((width * y) + x1) * 3).
x1 to:x2 do:[:x |
rVal := bytes at:(srcIndex).
gVal := bytes at:(srcIndex + 1).
bVal := bytes at:(srcIndex + 2).
srcIndex := srcIndex + 3.
(rVal == lastR and:[gVal == lastG and:[bVal == lastB]]) ifFalse:[
lastColor := Color red:rVal * 100 / 255
green:gVal * 100 / 255
blue:bVal * 100 / 255.
lastR := rVal.
lastG := gVal.
lastB := bVal.
].
aBlock value:x value:lastColor
]
"Created: 7.6.1996 / 19:12:28 / cg"
"Modified: 8.6.1996 / 10:16:51 / cg"
!
valuesAtY:y from:xLow to:xHigh do:aBlock
"perform aBlock for each pixelValue from x1 to x2 in row y.
The block is passed the pixelValue at each pixel.
This method allows slighly faster processing of an
image than using valueAtX:y:, since some processing can be
avoided when going from pixel to pixel. However, for
real image processing, specialized methods should be written.
Notice that the pixelValue is the r/g/b value packed into an integer
(r bitShift:16) bitOr:(g bitSHift:8) bitOr:b"
|srcIndex "{ Class: SmallInteger }"
x1 "{ Class: SmallInteger }"
x2 "{ Class: SmallInteger }"
r "{ Class: SmallInteger }"
g "{ Class: SmallInteger }"
b "{ Class: SmallInteger }"|
x1 := xLow.
x2 := xHigh.
srcIndex := 1 + (((width * y) + x1) * 3).
x1 to:x2 do:[:x |
r := bytes at:(srcIndex).
g := bytes at:(srcIndex + 1).
b := bytes at:(srcIndex + 2).
srcIndex := srcIndex + 3.
aBlock value:x value:(((r bitShift:16) bitOr:(g bitShift:8)) bitOr:b)
]
"Created: 7.6.1996 / 19:09:40 / cg"
! !
!Depth24Image methodsFor:'magnification'!
hardMagnifiedBy:extent
"return a new image magnified by extent, aPoint.
This is the general magnification method, handling non-integral values"
|mX mY
newWidth "{ Class: SmallInteger }"
newHeight "{ Class: SmallInteger }"
w "{ Class: SmallInteger }"
h "{ Class: SmallInteger }"
newImage newBytes
value "{ Class: SmallInteger }"
srcRowIdx "{ Class: SmallInteger }"
srcIndex "{ Class: SmallInteger }"
dstIndex "{ Class: SmallInteger }"|
mX := extent x.
mY := extent y.
((mX < 0) or:[mY < 0]) ifTrue:[^ nil].
((mX = 1) and:[mY = 1]) ifTrue:[^ self].
newWidth := (width * mX) truncated.
newHeight := (height * mY) truncated.
newBytes := ByteArray uninitializedNew:(newWidth * 3 * newHeight).
newImage := self species new.
newImage bits:newBytes.
newImage width:newWidth.
newImage height:newHeight.
newImage photometric:photometric.
newImage samplesPerPixel:samplesPerPixel.
newImage bitsPerSample:#(8 8 8).
"walk over destination image fetching pixels from source image"
mY := mY asFloat.
mX := mX asFloat.
%{
REGISTER unsigned char *_dstP = _ByteArrayInstPtr(newBytes)->ba_element;
unsigned char *_srcP = _ByteArrayInstPtr(_INST(bytes))->ba_element;
unsigned char *_srcRowP, *sP;
int _width3 = _intVal(_INST(width)) * 3;
int _w = _intVal(newWidth) - 1;
int _h = _intVal(newHeight) - 1;
int _row, _col;
double _mX = _floatVal(mX);
double _mY = _floatVal(mY);
for (_row = 0; _row <= _h; _row++) {
_srcRowP = _srcP + (_width3 * (int)((double)_row / _mY));
for (_col = 0; _col <= _w; _col++) {
sP = _srcRowP + (((int)((double)_col / _mX)) * 3);
_dstP[0] = sP[0];
_dstP[1] = sP[1];
_dstP[2] = sP[2];
_dstP += 3;
}
}
%}
.
" the above C-code is equivalent to:
dstIndex := 1.
w := newWidth - 1.
h := newHeight - 1.
0 to:h do:[:row |
srcRowIdx := (width * 3 * (row // mY)) + 1.
0 to:w do:[:col |
srcIndex := srcRowIdx + ((col // mX) * 3).
value := bytes at:srcIndex.
newBytes at:dstIndex put:value.
value := bytes at:(srcIndex + 1).
newBytes at:(dstIndex + 1) put:value.
value := bytes at:(srcIndex + 2).
newBytes at:(dstIndex + 2) put:value.
dstIndex := dstIndex + 3
]
].
"
^ newImage
!
magnifyRowFrom:srcBytes offset:srcStart
into:dstBytes offset:dstStart factor:mX
"magnify a single pixel row - can only magnify by integer factors"
%{
unsigned char *srcP, *dstP;
int _mag;
REGISTER int i;
REGISTER unsigned char byte1, byte2, byte3;
int _pixels;
OBJ w = _INST(width);
if (__bothSmallInteger(srcStart, dstStart)
&& __bothSmallInteger(w, mX)
&& __isByteArray(srcBytes) && __isByteArray(dstBytes)) {
_mag = _intVal(mX);
srcP = _ByteArrayInstPtr(srcBytes)->ba_element - 1 + _intVal(srcStart);
dstP = _ByteArrayInstPtr(dstBytes)->ba_element - 1 + _intVal(dstStart);
_pixels = _intVal(w);
while (_pixels--) {
byte1 = *srcP;
byte2 = *(srcP+1);
byte3 = *(srcP+2);
srcP += 3;
for (i=_mag; i>0; i--) {
*dstP = byte1;
*(dstP+1) = byte2;
*(dstP+2) = byte3;
dstP += 3;
}
}
RETURN (self);
}
%}
.
self primitiveFailed
! !
!Depth24Image methodsFor:'queries'!
bitsPerPixel
"return the number of bits per pixel"
^ 24
!
bitsPerRow
"return the number of bits in one scanline of the image"
^ width * 24
!
bitsPerSample
"return the number of bits per sample.
The return value is an array of bits-per-plane."
^ #(8 8 8)
!
blueBitsOf:pixel
^ pixel bitAnd:16rFF.
"Created: 8.6.1996 / 09:56:20 / cg"
!
blueComponentOf:pixel
^ (100.0 / 255.0) * (pixel bitAnd:16rFF)
"Created: 8.6.1996 / 08:42:44 / cg"
"Modified: 8.6.1996 / 09:57:41 / cg"
!
bytesPerRow
"return the number of bytes in one scanline of the image"
^ width * 3
!
greenBitsOf:pixel
^ (pixel bitShift:-8) bitAnd:16rFF.
"Modified: 8.6.1996 / 08:56:28 / cg"
"Created: 8.6.1996 / 09:56:30 / cg"
!
greenComponentOf:pixel
^ (100.0 / 255.0) * (pixel bitShift:-8) bitAnd:16rFF.
"Created: 8.6.1996 / 08:42:37 / cg"
"Modified: 8.6.1996 / 09:57:32 / cg"
!
redBitsOf:pixel
^ (pixel bitShift:-16) bitAnd:16rFF.
"Modified: 8.6.1996 / 08:56:31 / cg"
"Created: 8.6.1996 / 09:56:39 / cg"
!
redComponentOf:pixel
^ (100.0 / 255.0) * (pixel bitShift:-16) bitAnd:16rFF.
"Created: 8.6.1996 / 08:42:25 / cg"
"Modified: 8.6.1996 / 09:57:23 / cg"
!
samplesPerPixel
"return the number of samples per pixel in the image."
^ 3
! !
!Depth24Image class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libview/Depth24Image.st,v 1.29 1996-06-08 13:34:35 cg Exp $'
! !