Depth1Image.st
changeset 279 2751e757e228
parent 219 9ff0660f447f
child 315 2abc494f0c45
equal deleted inserted replaced
278:15e2959e1e58 279:2751e757e228
    29  inclusion of the above copyright notice.   This software may not
    29  inclusion of the above copyright notice.   This software may not
    30  be provided or otherwise made available to, or used by, any
    30  be provided or otherwise made available to, or used by, any
    31  other person.  No title to or ownership of the software is
    31  other person.  No title to or ownership of the software is
    32  hereby transferred.
    32  hereby transferred.
    33 "
    33 "
    34 !
       
    35 
       
    36 version
       
    37     ^ '$Header: /cvs/stx/stx/libview/Depth1Image.st,v 1.14 1995-11-11 15:49:05 cg Exp $'
       
    38 !
    34 !
    39 
    35 
    40 documentation
    36 documentation
    41 "
    37 "
    42     this class represents bilevel (1 bit / pixel) images.
    38     this class represents bilevel (1 bit / pixel) images.
    51 
    47 
    52 imageDepth
    48 imageDepth
    53     ^ 1
    49     ^ 1
    54 ! !
    50 ! !
    55 
    51 
    56 !Depth1Image methodsFor:'queries'!
       
    57 
       
    58 bitsPerPixel
       
    59     "return the number of bits per pixel"
       
    60 
       
    61     ^ 1
       
    62 !
       
    63 
       
    64 bitsPerRow
       
    65     "return the number of bits in one scanline of the image"
       
    66 
       
    67     ^  width
       
    68 !
       
    69 
       
    70 bitsPerSample
       
    71     "return the number of bits per sample.
       
    72      The return value is an array of bits-per-plane."
       
    73 
       
    74     ^ #(1)
       
    75 !
       
    76 
       
    77 bytesPerRow
       
    78     "return the number of bytes in one scanline of the image"
       
    79 
       
    80     |nbytes|
       
    81 
       
    82     nbytes := width // 8.
       
    83     ((width \\ 8) ~~ 0) ifTrue:[
       
    84 	^ nbytes + 1
       
    85     ].
       
    86     ^ nbytes
       
    87 !
       
    88 
       
    89 samplesPerPixel
       
    90     "return the number of samples per pixel in the image."
       
    91 
       
    92     ^ 1
       
    93 !
       
    94 
       
    95 usedColors
       
    96     "return a collection of colors used in the receiver.
       
    97      For depth1 images, this is very easy"
       
    98 
       
    99     photometric ~~ #palette ifTrue:[
       
   100 	^ Array with:Color white with:Color black.
       
   101     ].
       
   102     ^ colorMap
       
   103 
       
   104     "
       
   105      (Image fromFile:'bitmaps/garfield.gif') usedColors
       
   106      (Image fromFile:'bitmaps/SBrowser.xbm') usedColors
       
   107     "
       
   108 !
       
   109 
       
   110 usedValues
       
   111     "return a collection of color values used in the receiver.
       
   112      For depth1 images, this is very easy"
       
   113 
       
   114     ^ #(0 1)
       
   115 ! !
       
   116 
       
   117 !Depth1Image methodsFor:'accessing'!
    52 !Depth1Image methodsFor:'accessing'!
   118 
       
   119 valueAtX:x y:y
       
   120     "retrieve a pixelValue at x/y; return a number.
       
   121      The interpretation of the returned value depends on the photometric
       
   122      and the colormap. See also Image>>atX:y:)
       
   123      Pixels start at 0@0 for upper left pixel, end at
       
   124      (width-1)@(height-1) for lower right pixel"
       
   125 
       
   126     |bytesPerRow "{Class: SmallInteger}"
       
   127      index       "{Class: SmallInteger}"
       
   128      byte        "{Class: SmallInteger}"
       
   129      mask        "{Class: SmallInteger}"|
       
   130 
       
   131 %{  /* NOCONTEXT */
       
   132 
       
   133     OBJ b = _INST(bytes);
       
   134     OBJ w = _INST(width);
       
   135 
       
   136     if (__isByteArray(b) && __bothSmallInteger(x, y) && __isSmallInteger(w) ) {
       
   137 	int _w = _intVal(w);
       
   138 	int _y = _intVal(y);
       
   139 	int _x = _intVal(x);
       
   140 	unsigned _byte;
       
   141 
       
   142 	_byte = _ByteArrayInstPtr(b)->ba_element[(_w + 7) / 8 * _y + (_x / 8)];
       
   143 	RETURN( (_byte & (0x80 >> (_x % 8))) ? _MKSMALLINT(1) : _MKSMALLINT(0) );
       
   144     }
       
   145 %}.
       
   146 
       
   147 "/ the above is equivalent to:
       
   148 "/   (notice that the code below is evaluated if the bytes-collection is
       
   149 "/   not a byteArray, or the arguments are not integers)
       
   150 
       
   151 "/    bytesPerRow := width // 8.
       
   152 "/    ((width \\ 8) ~~ 0) ifTrue:[
       
   153 "/        bytesPerRow := bytesPerRow + 1
       
   154 "/    ].
       
   155 "/    index := (bytesPerRow * y) + 1 + (x // 8).
       
   156 "/
       
   157 "/    "left pixel is in high bit"
       
   158 "/    byte := bytes at:index.
       
   159 "/    mask := #(16r80 16r40 16r20 16r10 16r08 16r04 16r02 16r01) at:((x \\ 8) + 1).
       
   160 "/    (byte bitAnd:mask) == 0 ifTrue:[^ 0].
       
   161 "/    ^ 1
       
   162 
       
   163 "/ since that cannot happen, we faile here
       
   164     self primitiveFailed.
       
   165     ^ 0
       
   166 !
       
   167 
    53 
   168 atX:x y:y
    54 atX:x y:y
   169     "retrieve a pixel at x/y; return a color.
    55     "retrieve a pixel at x/y; return a color.
   170      Pixels start at x=0 , y=0 for upper left pixel, end at
    56      Pixels start at x=0 , y=0 for upper left pixel, end at
   171      x = width-1, y=height-1 for lower right pixel"
    57      x = width-1, y=height-1 for lower right pixel"
   196 	self error:'format not supported'.
    82 	self error:'format not supported'.
   197 	^ nil
    83 	^ nil
   198     ].
    84     ].
   199     value := value + 1.
    85     value := value + 1.
   200     ^ colorMap at:value
    86     ^ colorMap at:value
   201 !
       
   202 
       
   203 atX:x y:y putValue:aPixelValue
       
   204     "set a pixels value at x/y to aPixelValue.
       
   205      Pixels start at x=0 , y=0 for upper left pixel, end at
       
   206      x = width-1, y=height-1 for lower right pixel"
       
   207 
       
   208     |bytesPerRow "{Class: SmallInteger}"
       
   209      index       "{Class: SmallInteger}"
       
   210      byte        "{Class: SmallInteger}"
       
   211      mask        "{Class: SmallInteger}"|
       
   212 
       
   213 %{  /* NOCONTEXT */
       
   214 
       
   215     OBJ b = _INST(bytes);
       
   216     OBJ w = _INST(width);
       
   217 
       
   218     if (__isByteArray(b) && __bothSmallInteger(x, y) && __isSmallInteger(w) ) {
       
   219 	int _w = _intVal(w);
       
   220 	int _y = _intVal(y);
       
   221 	int _x = _intVal(x);
       
   222 	int _idx;
       
   223 
       
   224 	_idx = (_w + 7) / 8 * _y + (_x / 8);
       
   225 	if (aPixelValue == _MKSMALLINT(0)) {
       
   226 	    _ByteArrayInstPtr(b)->ba_element[_idx] &= ~(0x80 >> (_x % 8));
       
   227 	} else {
       
   228 	    _ByteArrayInstPtr(b)->ba_element[_idx] |= (0x80 >> (_x % 8));
       
   229 	}
       
   230 	RETURN( self );
       
   231     }
       
   232 %}.
       
   233     "fall back code for nonByteArray or nonInteger arguments"
       
   234 
       
   235     bytesPerRow := width // 8.
       
   236     ((width \\ 8) ~~ 0) ifTrue:[
       
   237 	bytesPerRow := bytesPerRow + 1
       
   238     ].
       
   239     index := (bytesPerRow * y) + 1 + (x // 8).
       
   240 
       
   241     "left pixel is in high bit"
       
   242     byte := bytes at:index.
       
   243     mask := #(16r80 16r40 16r20 16r10 16r08 16r04 16r02 16r01) at:((x \\ 8) + 1).
       
   244     aPixelValue == 0 ifTrue:[
       
   245 	byte := byte bitAnd:(mask bitInvert)
       
   246     ] ifFalse:[
       
   247 	byte := byte bitOr:mask
       
   248     ].
       
   249     bytes at:index put:byte
       
   250 !
    87 !
   251 
    88 
   252 atX:x y:y put:aColor
    89 atX:x y:y put:aColor
   253     "set the pixel at x/y to aColor.
    90     "set the pixel at x/y to aColor.
   254      Pixels start at x=0 , y=0 for upper left pixel, end at
    91      Pixels start at x=0 , y=0 for upper left pixel, end at
   285     ].
   122     ].
   286     "
   123     "
   287      the color to be stored is not in the images colormap
   124      the color to be stored is not in the images colormap
   288     "
   125     "
   289     self error:'invalid color'
   126     self error:'invalid color'
       
   127 !
       
   128 
       
   129 atX:x y:y putValue:aPixelValue
       
   130     "set a pixels value at x/y to aPixelValue.
       
   131      Pixels start at x=0 , y=0 for upper left pixel, end at
       
   132      x = width-1, y=height-1 for lower right pixel"
       
   133 
       
   134     |bytesPerRow "{Class: SmallInteger}"
       
   135      index       "{Class: SmallInteger}"
       
   136      byte        "{Class: SmallInteger}"
       
   137      mask        "{Class: SmallInteger}"|
       
   138 
       
   139 %{  /* NOCONTEXT */
       
   140 
       
   141     OBJ b = _INST(bytes);
       
   142     OBJ w = _INST(width);
       
   143 
       
   144     if (__isByteArray(b) && __bothSmallInteger(x, y) && __isSmallInteger(w) ) {
       
   145 	int _w = _intVal(w);
       
   146 	int _y = _intVal(y);
       
   147 	int _x = _intVal(x);
       
   148 	int _idx;
       
   149 
       
   150 	_idx = (_w + 7) / 8 * _y + (_x / 8);
       
   151 	if (aPixelValue == _MKSMALLINT(0)) {
       
   152 	    _ByteArrayInstPtr(b)->ba_element[_idx] &= ~(0x80 >> (_x % 8));
       
   153 	} else {
       
   154 	    _ByteArrayInstPtr(b)->ba_element[_idx] |= (0x80 >> (_x % 8));
       
   155 	}
       
   156 	RETURN( self );
       
   157     }
       
   158 %}.
       
   159     "fall back code for nonByteArray or nonInteger arguments"
       
   160 
       
   161     bytesPerRow := width // 8.
       
   162     ((width \\ 8) ~~ 0) ifTrue:[
       
   163 	bytesPerRow := bytesPerRow + 1
       
   164     ].
       
   165     index := (bytesPerRow * y) + 1 + (x // 8).
       
   166 
       
   167     "left pixel is in high bit"
       
   168     byte := bytes at:index.
       
   169     mask := #(16r80 16r40 16r20 16r10 16r08 16r04 16r02 16r01) at:((x \\ 8) + 1).
       
   170     aPixelValue == 0 ifTrue:[
       
   171 	byte := byte bitAnd:(mask bitInvert)
       
   172     ] ifFalse:[
       
   173 	byte := byte bitOr:mask
       
   174     ].
       
   175     bytes at:index put:byte
       
   176 !
       
   177 
       
   178 valueAtX:x y:y
       
   179     "retrieve a pixelValue at x/y; return a number.
       
   180      The interpretation of the returned value depends on the photometric
       
   181      and the colormap. See also Image>>atX:y:)
       
   182      Pixels start at 0@0 for upper left pixel, end at
       
   183      (width-1)@(height-1) for lower right pixel"
       
   184 
       
   185     |bytesPerRow "{Class: SmallInteger}"
       
   186      index       "{Class: SmallInteger}"
       
   187      byte        "{Class: SmallInteger}"
       
   188      mask        "{Class: SmallInteger}"|
       
   189 
       
   190 %{  /* NOCONTEXT */
       
   191 
       
   192     OBJ b = _INST(bytes);
       
   193     OBJ w = _INST(width);
       
   194 
       
   195     if (__isByteArray(b) && __bothSmallInteger(x, y) && __isSmallInteger(w) ) {
       
   196 	int _w = _intVal(w);
       
   197 	int _y = _intVal(y);
       
   198 	int _x = _intVal(x);
       
   199 	unsigned _byte;
       
   200 
       
   201 	_byte = _ByteArrayInstPtr(b)->ba_element[(_w + 7) / 8 * _y + (_x / 8)];
       
   202 	RETURN( (_byte & (0x80 >> (_x % 8))) ? _MKSMALLINT(1) : _MKSMALLINT(0) );
       
   203     }
       
   204 %}.
       
   205 
       
   206 "/ the above is equivalent to:
       
   207 "/   (notice that the code below is evaluated if the bytes-collection is
       
   208 "/   not a byteArray, or the arguments are not integers)
       
   209 
       
   210 "/    bytesPerRow := width // 8.
       
   211 "/    ((width \\ 8) ~~ 0) ifTrue:[
       
   212 "/        bytesPerRow := bytesPerRow + 1
       
   213 "/    ].
       
   214 "/    index := (bytesPerRow * y) + 1 + (x // 8).
       
   215 "/
       
   216 "/    "left pixel is in high bit"
       
   217 "/    byte := bytes at:index.
       
   218 "/    mask := #(16r80 16r40 16r20 16r10 16r08 16r04 16r02 16r01) at:((x \\ 8) + 1).
       
   219 "/    (byte bitAnd:mask) == 0 ifTrue:[^ 0].
       
   220 "/    ^ 1
       
   221 
       
   222 "/ since that cannot happen, we faile here
       
   223     self primitiveFailed.
       
   224     ^ 0
       
   225 ! !
       
   226 
       
   227 !Depth1Image methodsFor:'converting greyscale images'!
       
   228 
       
   229 greyImageAsFormOn:aDevice
       
   230     "convert a greyscale image to a device form"
       
   231 
       
   232     |f|
       
   233 
       
   234     f := Form width:width height:height fromArray:bytes on:aDevice.
       
   235     photometric == #blackIs0 ifTrue:[
       
   236 	f function:#xor.
       
   237 	f paint:(Color colorId:1).
       
   238 	f fillRectangleX:0 y:0 width:width height:height
       
   239     ].
       
   240     ^ f
       
   241 !
       
   242 
       
   243 greyImageAsMonoFormOn:aDevice
       
   244     "convert to a monochrome form - thats easy"
       
   245 
       
   246     ^ self greyImageAsFormOn:aDevice
       
   247 ! !
       
   248 
       
   249 !Depth1Image methodsFor:'converting palette images'!
       
   250 
       
   251 paletteImageAsPseudoFormOn:aDevice
       
   252     "return a pseudo-deviceForm from the palette image."
       
   253 
       
   254     |f|
       
   255 
       
   256     "
       
   257      this is easy, since Form already supports colorMaps
       
   258     "
       
   259     f := Form width:width height:height fromArray:bytes.
       
   260     f colorMap:colorMap.
       
   261     ^ f
       
   262 !
       
   263 
       
   264 paletteImageAsTrueColorFormOn:aDevice
       
   265     "since all devices must support monochrome images, and
       
   266      a 2-entry colormap is implemented by ST/X's drawForm methods,
       
   267      we can do this on all color devices as a palette image."
       
   268 
       
   269     ^ self paletteImageAsPseudoFormOn:aDevice
   290 ! !
   270 ! !
   291 
   271 
   292 !Depth1Image methodsFor:'enumerating'!
   272 !Depth1Image methodsFor:'enumerating'!
   293 
       
   294 valueAtY:y from:xLow to:xHigh do:aBlock
       
   295     "perform aBlock for each pixelValue from x1 to x2 in row y.
       
   296      The block is passed the color at each pixel.
       
   297      This method allows slighly faster processing of an
       
   298      image than using atX:y:, since some processing can be
       
   299      avoided when going from pixel to pixel. However, for
       
   300      real image processing, specialized methods should be written."
       
   301 
       
   302     |srcIndex "{ Class: SmallInteger }"
       
   303      byte     "{ Class: SmallInteger }"
       
   304      mask     "{ Class: SmallInteger }"
       
   305      x1       "{ Class: SmallInteger }"
       
   306      x2       "{ Class: SmallInteger }"
       
   307      pixelValue|
       
   308 
       
   309     "this method needs more tuning, if used heavily 
       
   310      (fetch 8 bits at once, unroll the loop over these 8 pixels)"
       
   311 
       
   312     x1 := xLow.
       
   313     x2 := xHigh.
       
   314     srcIndex := (self bytesPerRow * y) + 1.
       
   315 
       
   316     "left pixel is in high bit"
       
   317 
       
   318     srcIndex := srcIndex + (x1 // 8).
       
   319     mask := #[2r10000000 
       
   320 	      2r01000000
       
   321 	      2r00100000
       
   322 	      2r00010000
       
   323 	      2r00001000
       
   324 	      2r00000100
       
   325 	      2r00000010
       
   326 	      2r00000001] at:((x1 \\ 8) + 1).
       
   327 
       
   328     x1 to:x2 do:[:x |
       
   329 	byte := bytes at:srcIndex.
       
   330 	(byte bitAnd:mask) == 0 ifTrue:[
       
   331 	    pixelValue := 0
       
   332 	] ifFalse:[
       
   333 	    pixelValue := 1
       
   334 	].
       
   335 	aBlock value:x value:pixelValue.
       
   336 
       
   337 	mask := mask bitShift:-1.
       
   338 	mask == 0 ifTrue:[
       
   339 	    mask := 2r10000000.
       
   340 	    srcIndex := srcIndex + 1
       
   341 	]
       
   342     ]
       
   343 !
       
   344 
   273 
   345 atY:y from:xLow to:xHigh do:aBlock
   274 atY:y from:xLow to:xHigh do:aBlock
   346     "perform aBlock for each pixel from x1 to x2 in row y.
   275     "perform aBlock for each pixel from x1 to x2 in row y.
   347      The block is passed the color at each pixel.
   276      The block is passed the color at each pixel.
   348      This method allows slighly faster processing of an
   277      This method allows slighly faster processing of an
   404 	mask == 0 ifTrue:[
   333 	mask == 0 ifTrue:[
   405 	    mask := 2r10000000.
   334 	    mask := 2r10000000.
   406 	    srcIndex := srcIndex + 1
   335 	    srcIndex := srcIndex + 1
   407 	]
   336 	]
   408     ]
   337     ]
   409 ! !
   338 !
   410 
   339 
   411 !Depth1Image methodsFor:'converting greyscale images'!
   340 valueAtY:y from:xLow to:xHigh do:aBlock
   412 
   341     "perform aBlock for each pixelValue from x1 to x2 in row y.
   413 greyImageAsFormOn:aDevice
   342      The block is passed the color at each pixel.
   414     "convert a greyscale image to a device form"
   343      This method allows slighly faster processing of an
   415 
   344      image than using atX:y:, since some processing can be
   416     |f|
   345      avoided when going from pixel to pixel. However, for
   417 
   346      real image processing, specialized methods should be written."
   418     f := Form width:width height:height fromArray:bytes on:aDevice.
   347 
   419     photometric == #blackIs0 ifTrue:[
   348     |srcIndex "{ Class: SmallInteger }"
   420 	f function:#xor.
   349      byte     "{ Class: SmallInteger }"
   421 	f paint:(Color colorId:1).
   350      mask     "{ Class: SmallInteger }"
   422 	f fillRectangleX:0 y:0 width:width height:height
   351      x1       "{ Class: SmallInteger }"
   423     ].
   352      x2       "{ Class: SmallInteger }"
   424     ^ f
   353      pixelValue|
   425 !
   354 
   426 
   355     "this method needs more tuning, if used heavily 
   427 greyImageAsMonoFormOn:aDevice
   356      (fetch 8 bits at once, unroll the loop over these 8 pixels)"
   428     "convert to a monochrome form - thats easy"
   357 
   429 
   358     x1 := xLow.
   430     ^ self greyImageAsFormOn:aDevice
   359     x2 := xHigh.
   431 ! !
   360     srcIndex := (self bytesPerRow * y) + 1.
   432 
   361 
   433 !Depth1Image methodsFor:'converting palette images'!
   362     "left pixel is in high bit"
   434 
   363 
   435 paletteImageAsPseudoFormOn:aDevice
   364     srcIndex := srcIndex + (x1 // 8).
   436     "return a pseudo-deviceForm from the palette image."
   365     mask := #[2r10000000 
   437 
   366 	      2r01000000
   438     |f|
   367 	      2r00100000
   439 
   368 	      2r00010000
   440     "
   369 	      2r00001000
   441      this is easy, since Form already supports colorMaps
   370 	      2r00000100
   442     "
   371 	      2r00000010
   443     f := Form width:width height:height fromArray:bytes.
   372 	      2r00000001] at:((x1 \\ 8) + 1).
   444     f colorMap:colorMap.
   373 
   445     ^ f
   374     x1 to:x2 do:[:x |
   446 !
   375 	byte := bytes at:srcIndex.
   447 
   376 	(byte bitAnd:mask) == 0 ifTrue:[
   448 paletteImageAsTrueColorFormOn:aDevice
   377 	    pixelValue := 0
   449     "since all devices must support monochrome images, and
   378 	] ifFalse:[
   450      a 2-entry colormap is implemented by ST/X's drawForm methods,
   379 	    pixelValue := 1
   451      we can do this on all color devices as a palette image."
   380 	].
   452 
   381 	aBlock value:x value:pixelValue.
   453     ^ self paletteImageAsPseudoFormOn:aDevice
   382 
       
   383 	mask := mask bitShift:-1.
       
   384 	mask == 0 ifTrue:[
       
   385 	    mask := 2r10000000.
       
   386 	    srcIndex := srcIndex + 1
       
   387 	]
       
   388     ]
   454 ! !
   389 ! !
   455 
   390 
   456 !Depth1Image methodsFor:'magnification'!
   391 !Depth1Image methodsFor:'magnification'!
   457 
   392 
   458 magnifyRowFrom:srcBytes offset:srcStart  
   393 magnifyRowFrom:srcBytes offset:srcStart  
   558 	RETURN (self);
   493 	RETURN (self);
   559     }
   494     }
   560 %}.
   495 %}.
   561     self primitiveFailed
   496     self primitiveFailed
   562 ! !
   497 ! !
       
   498 
       
   499 !Depth1Image methodsFor:'queries'!
       
   500 
       
   501 bitsPerPixel
       
   502     "return the number of bits per pixel"
       
   503 
       
   504     ^ 1
       
   505 !
       
   506 
       
   507 bitsPerRow
       
   508     "return the number of bits in one scanline of the image"
       
   509 
       
   510     ^  width
       
   511 !
       
   512 
       
   513 bitsPerSample
       
   514     "return the number of bits per sample.
       
   515      The return value is an array of bits-per-plane."
       
   516 
       
   517     ^ #(1)
       
   518 !
       
   519 
       
   520 bytesPerRow
       
   521     "return the number of bytes in one scanline of the image"
       
   522 
       
   523     |nbytes|
       
   524 
       
   525     nbytes := width // 8.
       
   526     ((width \\ 8) ~~ 0) ifTrue:[
       
   527 	^ nbytes + 1
       
   528     ].
       
   529     ^ nbytes
       
   530 !
       
   531 
       
   532 samplesPerPixel
       
   533     "return the number of samples per pixel in the image."
       
   534 
       
   535     ^ 1
       
   536 !
       
   537 
       
   538 usedColors
       
   539     "return a collection of colors used in the receiver.
       
   540      For depth1 images, this is very easy"
       
   541 
       
   542     photometric ~~ #palette ifTrue:[
       
   543 	^ Array with:Color white with:Color black.
       
   544     ].
       
   545     ^ colorMap
       
   546 
       
   547     "
       
   548      (Image fromFile:'bitmaps/garfield.gif') usedColors
       
   549      (Image fromFile:'bitmaps/SBrowser.xbm') usedColors
       
   550     "
       
   551 !
       
   552 
       
   553 usedValues
       
   554     "return a collection of color values used in the receiver.
       
   555      For depth1 images, this is very easy"
       
   556 
       
   557     ^ #(0 1)
       
   558 ! !
       
   559 
       
   560 !Depth1Image class methodsFor:'documentation'!
       
   561 
       
   562 version
       
   563     ^ '$Header: /cvs/stx/stx/libview/Depth1Image.st,v 1.15 1995-12-07 10:42:19 cg Exp $'
       
   564 ! !