eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'Image':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: Image


Inheritance:

   Object
   |
   +--Image
      |
      +--CachedImage
      |
      +--Depth16Image
      |
      +--Depth1Image
      |
      +--Depth24Image
      |
      +--Depth2Image
      |
      +--Depth32FloatImage
      |
      +--Depth32Image
      |
      +--Depth48Image
      |
      +--Depth4Image
      |
      +--Depth64Image
      |
      +--Depth8Image

Package:
stx:libview
Category:
Graphics-Images
Version:
rev: 1.708 date: 2024/01/16 14:43:00
user: cg
file: Image.st directory: libview
module: stx stc-classLibrary: libview

Description:


this class provides representation for all kinds of images
(monochrome, greyscale and color) and may finally replace Form.
Depths of 1, 2, 4, 8, 16, 24 and 32 are supported.

An Image keeps all of its information in a device independent way,
but may be associated to a device (i.e. getting a device-specific version of it).
The data held keeps all information which was originally present,
even if the display-device has lower resolution.
Therefore, it is possible to process and manipulate images without losing
color information.

Images may be created manually (by providing a pixel array),
by screen capture, by reading a file (using an ImageReader) or
dynamically computed by a pixelFunction (functional image).

This gives you a device independent image.
For display, a device representation is required, which can be
acquired by sending the 'onDevice:aDevice' message to the image.
This creates a (possibly dithered) device-form,
representing the image using the currently available colors.

In rare cases, an explicit monochrome representation of the image is needed
(some older X servers take monochrome icons only), this can be created by sending
it the message
    'monochromeOn:aDevice'.

As this class is very old and originated at times when typical graphic diplays only
supported a limited number of colors (16 or 256), or were even monochrome b&w or grayscale
(NeXTCube or 4-plane NeXTStation).
You will find a lot of code which deals with color allocation optimizations and dithering.
Nowadays, these are hardly ever needed, and most of the time,
images will be converted to 24bit (8x8x8) or 16bit (5x5x6) truecolor, when converted to a device representation.
(see examples_dithering for this old code in action)

An image's pixel interpretation is controlled by the photometric instance variable
and (if that is #palette) a colorMap.
This is in contrast to the ST-80 way, where all of this info is in the colorMap
(and using specialized colorMaps for b&w / greyScale images).
This may change in future versions for more application compatibility.

To convert pictures from/to external file formats, image readers are used
which have the file format knowledge built in.
There are readers for most common formats available
(see ImageReader and especially subclasses such as TIFFReader, GIFReader etc.).

File formats are handled by subclasses of ImageReader, which understand
a specific format. You can add more readers, by adding an association
to the mapping maintained in the MIMETypes class.
(see the MIMETypes>>initialize and possibly the display.rc file, where this is done).

Some algorithms used here (especially dithering & color allocation) are
experimental and far from being perfect (some are very slow).
For now, the most common cases have been optimized and perform reasonably
fast - however, with uncommon depth/visualType combinations, you may
run into very slow fallback methods. If this leads to problems, you may have to
write a specially tuned (inline-C) version for that case.

The pixelFunction enables dynamically computed functional images: instead of
providing a byteArray containing pixel data, a function is used which maps
x/y coordinates to a pixel value (see examples).
For display, the bits array is used internally and filled by the function.

Much more work is needed if you plan to do heavy image processing and will
(may) be done in the future if there is a demand for it ...

Dithering (read section above) can be controlled by the DitherAlgorithm classVariable:

   DitherAlgorithm:

   nil                  a simple threshold algorithm
                        (i.e. for mono, p<0.5 -> black, p>=0.5 -> white)

   #pattern             patterned dither
                        (for p, take dithered color to fill pixel;
                         uses dithering in color-class)

   #error               error diffusion dither (Floyd-Steinberg)
                        planned - not yet implemented.


Notice:
    the set of attributes and the way they are stored originated initially
    from the need to represent tiff images.
    These turned out to use a relatively large set of attributes,
    of which many are unused in other image formats. (so it was sufficient).
    Later, some VisualWorks compatibility protocol was added (mapped palettes, for
    example), and some stuff could well be redefined in simpler ways.
    We may do that, if we are bored and there is nothing else to improve... ;-)


[instance variables:]

    width               <Integer>       the width in pixels
    height              <Integer>       the height in pixels
    bytes               <ByteArray>     the full image information
    photometric         <Symbol>        #rgb, #palette, #blackIs0 or #whiteIs0
    samplesPerPixel     <Integer>       the number of planes
    bitsPerSample       <Array>         the number of bits per plane

    colorMap            <Array>         only if photometric is #palette;
                                        maps pixel values to r/g/b values.

    device              <Workstation>   the device on which deviceForm,
                                        monoDeviceForm and lowResDeviceForm are

    deviceForm          <Form>          the device form which gives the best
                                        possible approximation of the image on
                                        device using standard colors.

    monoDeviceForm      <Form>          the device form which gives a monochrome
                                        approximation of the image on device.

    fullColorDeviceForm <Form>          the device form which gives the best
                                        possible approximation of the image on
                                        device using private colors.
                                        (not yet implemented)

    mask                <ImageMask>     an optional mask;
                                        if non-nil, only pixels for which the
                                        corresponding mask bit is non-zero
                                        are drawn.

    maskedPixelsAre0    <Boolean>       a hint for image processors and drawers
                                        if true, masked pixels are known to be
                                        zero in the pixel bytes.

    fileName            <String>        the name of the file from which the
                                        image was loaded - nil otherwise.
                                        Useful for image save functions
                                        and for the UIPainter utility.

    imageSequence                       the imageSequence, of which the
                                        instance is a frame or nil,
                                        if it's not part of a sequence.

    bitsPerPixel                        obsolete - not used in ST/X (kept for a while for subclasses)
    depth                               - these have been added in instVar-slots
    maxPixelValue                       - according to the ST-80's image class.
    rowByteSize                         - to allow loading of ST-80 images
                                        - (which are stored as instVarAt:put: expressions)

[class variables:]

    Lobby               <Registry>      keeps track of known images
                                        (for resource freeing with garbage collector)

    DitherAlgorithm     <Symbol>        defines how to dither

    NumberOfDitherColors <Integer>      defines, how many dither colors to use

    FileFormats         <Dictionary>    associates filename extensions to
                                        image reader classes (now set-up in startup-file)

    CollectGarbageWhenRunningOutOfColors
                        <Boolean>       if true, and we run out of available
                                        device colors during creation of a
                                        device image, collect garbage for
                                        possible image reclamation.
                                        If false, proceed immediately.
                                        Default is true.

    ImageNotFoundQuerySignal
                        <QuerySignal>   raised, if an image could not be loaded
                                        from a file. The parameter is the images
                                        fileName.
                                        A handler may return a replacement
                                        image or proceed with nil.
                                        If unhandled, a nil is returned from the
                                        image creation.

    BadImageFormatQuerySignal
                        <QuerySignal>   raised, if an image could not be loaded
                                        from a file due to a file error or
                                        unsupported format.
                                        A handler may return a replacement
                                        image or proceed with nil.
                                        If unhandled, a nil is returned from the
                                        image creation.

    ImageSaveErrorSignal
                        <Signal>        parent of errors below.

    FileCreationErrorSignal
                        <Signal>        file could not be created when saving an
                                        image.

    CannotRepresentImageSignal
                        <Signal>        the specified ImageReader cannot represent
                                        the given image.

    InformationLostQuerySignal
                        <Signal>        the specified ImageReader can represent
                                        the given image, but some information
                                        (typically color resolution) is lost.
                                        If unhandled, the save proceeds as usual.


caveat:
    the information in
        photometric, bitsPerPixel, bitsPerSample, samplesPerPixel, depth , colorMap and maxPixelValue
    is partially redundant and its handling stupid (not to say: braindamaged ;-).
    The only excuse is that it grew over time, had to incorporate various alien/older schemes for
    compatibility reasons (mostly coming from tiff format, which was the very first supported format).
    All of the above belongs into the single colorMap which must migrate from
    a stupid seqColl to a color-aware real colorMap.
    (we are in the process of doing so...)

todo:
    support alpha masks
    cleanup the dithering & conversion code
    cleanup the color/photometric mess

copyright

COPYRIGHT (c) 1991 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.

examples_dithering

Just for fun (see the wikipedia article 'https://en.wikipedia.org/wiki/Dither#Algorithms' on dithering) [exBegin] |image top panel image2 wrapIt| top := StandardSystemView new. top label:'Dithering Examples'. top width:1000. panel := PanelView origin:0.0@0.0 corner:1.0@1.0 in:top. panel horizontalLayout:#left. panel verticalLayout:#top. top openAndWaitUntilVisible. wrapIt := [:image :text | |imageView label view| view := View in:panel. imageView := ImageView origin:0@0 extent:image extent in:view. imageView image:image. label := Label origin:0@(image height) corner:1.0@1.0 in:view. label logo:text. view extent:(image extent + (0@30)). view realize. view realizeAllSubViews. ]. 'original image:'. image := ImageReader fromURL:'https://upload.wikimedia.org/wikipedia/commons/7/71/Michelangelo%27s_David_-_63_grijswaarden.png'. wrapIt value:image value:'Original'. 'dithered image:'. image2 := image asOrderedDitheredMonochromeImage. wrapIt value:image2 value:'Ordered'. 'dithered Arce:'. image2 := image asStevensonArceDitheredMonochromeImage. wrapIt value:image2 value:'Stephenson Arce'. 'dithered Burkes:'. image2 := image asBurkesDitheredMonochromeImage. wrapIt value:image2 value:'Burkes'. 'dithered Floyd-Steinberg:'. image2 := image asFloydSteinbergDitheredMonochromeImage. wrapIt value:image2 value:'FS b&w'. 'dithered grey depth2 ordered:'. image2 := image asOrderedDitheredGrayImageDepth:2. wrapIt value:image2 value:'Ordered gray 2bit'. 'dithered grey depth4 ordered:'. image2 := image asOrderedDitheredGrayImageDepth:4. wrapIt value:image2 value:'Ordered gray 4bit'. 'dithered grey depth2 ordered:'. image2 := image asFloydSteinbergDitheredGrayImageDepth:2. wrapIt value:image2 value:'FS gray 2bit'. 'dithered grey depth4 ordered:'. image2 := image asFloydSteinbergDitheredGrayImageDepth:4. wrapIt value:image2 value:'FS gray 4bit'. [exEnd]

examples_functionalImages

Functional images (please read 'Functional Images' by Conal Elliot, Microsoft Research). These have no underlying pixelstorage, but instead compute the pixel-value via a block. Plain x/y mapping: [exBegin] |i| i := Depth1Image extent:256@256. i pixelFunction:[:x :y | ((x // 16) bitXor:(y // 16)) odd ifTrue:1 ifFalse:[0]]. i inspect. [exEnd] Transformed x/y mapping: [exBegin] |i f| f := [:x :y | (x between:0.4 and:0.6) asInteger]. i := Depth1Image extent:256@256. i pixelFunction:f inX:(0.0 to:1.0) y:(0.0 to:1.0). i inspect. [exEnd] [exBegin] |i f| f := [:x :y | ((x between:0.4 and:0.6) or:[(y between:0.4 and:0.6)]) asInteger]. i := Depth1Image extent:256@256. i pixelFunction:f inX:(0.0 to:1.0) y:(0.0 to:1.0). i inspect. [exEnd] Image based on polar coordinate: [exBegin] |i f| f := [:x :y | ((x@y) r * 10) asInteger bitAnd:1]. i := Depth1Image extent:256@256. i pixelFunction:f inX:(-1.0 to:1.0) y:(-1.0 to:1.0). i inspect. [exEnd] Grayscale image based on polar coordinate: [exBegin] |i| i := Depth8Image extent:256@256. i photometric:#blackIs0. i pixelFunction:[:x :y | ((x@y) r * 255) truncated min:255] inX:(-1 to:1) y:(-1 to:1). i inspect. [exEnd] Taking another image as ''input'' [exBegin] |garfield f i h| garfield := Image fromFile:'bitmaps/gifImages/garfield.gif' inPackage:'stx:goodies'. h := garfield height. f := [:x :y | (garfield colorAtX:x y:h-y) rgbValue]. i := Depth24Image extent:garfield extent. i pixelFunction:f. i inspect. [exEnd]

Class protocol:

Signal constants
o  badImageFormatQuerySignal
return the (query-) signal, which is raised if some
bitmap-image could not be loaded due to an unrecognized format.
If unhandled, the image-load returns nil.
Otherwise, it returns whatever the handler proceeds with.
The exception gets either the image's fileName or an input stream
as parameter

o  cannotRepresentImageSignal
return the signal, which is raised if some
bitmap-image could not be saved in the requested format.
This happens for example, if a true color image is saved in
xpm format or a color image saved in xbm format.
Applications should either ask the class before saving
(via #canRepresent:) or handle the error and use an alternative
format then.

o  fileCreationErrorSignal
return the signal which is raised if a file could not be
created in an image-save operation.

o  imageErrorSignal
return the parent of all image signals

o  imageLoadErrorSignal
return the parent of all image load error signals

o  imageNotFoundQuerySignal
return the (query-) signal, which is raised if some
bitmap-image could not be loaded from a file.
If unhandled, the image-load returns nil.
Otherwise, it returns whatever the handler proceeds with.
The exception gets the image's fileName as parameter

o  imageSaveErrorSignal
return the parent signal of all image-save errors.

o  informationLostQuerySignal
return the (query-) signal, which is raised if some
bitmap-image is saved in a format which cannot represent
the full image (for example: the image's mask).
If unhandled, the image-save proceeds.
Otherwise, the handler may show a warn box or whatever and decide
to proceed or abort the saving.

o  noMaskButAlphaSupportedQuerySignal
return the (query-) signal, which is raised if some
bitmap-image with a mask is saved in a format which cannot represent
the mask but instead supports an alpha channel.
If unhandled, the image-save proceeds (with mask converted to alpha channel).
Otherwise, the handler may show a warn box or whatever and decide
to proceed or abort the saving.

o  noMaskSupportedQuerySignal
return the (query-) signal, which is raised if some
bitmap-image with a mask is saved in a format which cannot represent
the mask.
If unhandled, the image-save proceeds (without mask).
Otherwise, the handler may show a warn box or whatever and decide
to proceed or abort the saving.

o  unrepresentableColorSignal
return the signal, which is raised if some color is not
representable in the image (when storing a pixel).

o  unsupportedImageFormatQuerySignal
return the (query-) signal, which is raised if some
bitmap-image could not be loaded due to an unsupported format.
If unhandled, the image-load returns nil.
Otherwise, it returns whatever the handler proceeds with.
The exception gets either the image's fileName or an input stream
as parameter

cleanup
o  lowSpaceCleanup
(comment from inherited method)
ignored here - redefined in some classes to
cleanup in low-memory situations

o  releaseResourcesOnDevice: aDevice
this is sent when a display connection is closed,
to release all cached Images from that device

Usage example(s):

      self releaseResourcesOnDevice:Screen current

file reading
o  fromBase64Stream: aStream using: aReaderClass
read an image from a base64 encoded stream, given an imageReaderClass.
Use this, if you know the file's format, but it has an invalid
extension (or non-definite header),
so #fromStream: could not find out the file's format.
Return nil (or whatever a handler returned),
if the stream does not contain an appropriate image.

o  fromFile: aFileName
read an image from a file - this methods tries to find
out the file format itself (by the extension and by contents)
and lets the appropriate reader read the file.
Also, unless the path is absolute,
all bitmap directories along the searchPath are checked
for the file; thus, you can place your private images into a
separate directory, thereby overriding system bitmaps easily.
If the file is unreadable or does not contain an appropriate image,
the ImageNotFoundQuerySignal is raised, which may be handled to
proceed with some replacement image. If unhandled, nil is returned.

Usage example(s):

     Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies'
     Image fromFile:'bitmaps/gifImages/garfield.gif' inPackage:'stx:goodies'

     Image fromFile:'bitmaps/winBitmaps/a11.ico' inPackage:'stx:goodies'
     Image fromFile:'bitmaps/xpmBitmaps/countries/czech.xpm' inPackage:'stx:goodies'
     Image fromFile:'bitmaps/xpmBitmaps/countries/czech.xpm.gz' inPackage:'stx:goodies'
     Image fromFile:'Demos/bitmaps/hello_world.icon' inPackage:'stx:clients'

Usage example(s):

     Image fromFile:'fooBar'

Usage example(s):

giving a message for non-existing images:

     Image imageNotFoundQuerySignal
     handle:[:ex |
        Transcript showCR:ex description.
        ex proceedWith:nil
     ] do:[
         Image fromFile:'fooBar'
     ]

Usage example(s):

giving a replacement for non-existing images:

     Image imageNotFoundQuerySignal
     answer:(Image fromFile:'libtool/bitmaps/SmalltalkX.xbm')
     do:[
         Image fromFile:'fooBar'
     ]

o  fromFile: aFileName inPackage: aPackage
read an image for a package from a file.
The filename is assumed to be package-relative (i.e. bitmaps/filename).
This methods tries to find out the file format itself (by the extension and by contents)
and lets the appropriate reader read the file.
Also, all bitmap directories along the searchPath are checked
for the file; thus, you can place your private images into a
separate directory, thereby overriding system bitmaps easily.
If the file is unreadable or does not contain an appropriate image,
the ImageNotFoundQuerySignal is raised, which may be handled to
proceed with some replacement image. If unhandled, nil is returned.

Usage example(s):

     Image fromFile:'libtool/bitmaps/SBrowser.xbm'
     Image fromFile:'bitmaps/SBrowser.xbm' inPackage:'stx:libtool'
     Image fromFile:'garfield.gif' inPackage:'stx:goodies/bitmaps/gifImages'

o  fromFile: aFileName on: aDevice
read an image from a file and prepare a device representation.
Return nil (or whatever a handler returned),
if the file is unreadable or does not contain an appropriate image.

o  fromFile: aFileName resolution: res
read an image from a file and (if required) scale the image
as appropriate (only req'd for very high resolution displays).
Return nil (or whatever a handler returned),
if the file is unreadable or does not contain an appropriate image.

o  fromFile: aFileName resolution: dpi on: aDevice
read an image from a file and (if required) scale the image
as appropriate (only req'd with very high resolution displays).
Prepare a device representation.
Return nil (or whatever a handler returned),
if the file is unreadable or does not contain an appropriate image.

o  fromStream: aStream
read an image from a stream - this methods tries to find
out the file format itself (by contents)
and lets the appropriate reader read the file.
To do this, the stream must be positionable.
Return nil (or whatever a handler returned),
if the stream does not contain an appropriate image.

o  fromStream: aStream using: aReaderClass
read an image from a stream, given an imageReaderClass.
Use this, if you know the file's format, but it has an invalid
extension (or non-definite header),
so #fromStream: could not find out the file's format.
Return nil (or whatever a handler returned),
if the stream does not contain an appropriate image.

initialization
o  addReader: aReaderClass suffix: aSuffix
register an additional image reader.
This is provided for subclasses, to regster themself when
loaded (or from the startup scripts)

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  addReader: aReaderClass suffix: aSuffix mimeType: mimeType
register an additional image reader.
This interface is kept for backward compatibility.
The knowledge has been concentrated in MIMETypes

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  fileFormats
return the collection of supported file formats.
The returned dictionary maps file-extensions to image reader classes.

Usage example(s):

     Image fileFormats

o  flushDeviceImages
simply release all deviceForms

o  initialize
initialize class constants

o  initializeFileFormatTable
initialize a default table to map from file extension to reader class.
The mapping here is a default needed for proper operation of ST/X;
see the 'smalltalk.rc'/'display.rc' startup files for a real (full) map.

Usage example(s):

     Image initializeFileFormatTable

o  initializeMIMETable
initialize a default table to map from mime type to reader class.
The mapping here is a default needed for proper operation of ST/X;
see the 'smalltalk.rc'/'display.rc' startup files for a real (full) map.

Usage example(s):

     Image initializeMIMETable

o  update: something with: aParameter from: changedObject
flush all device specific stuff when restarted from a snapshot

instance creation
o  extent: ext
create a new image, given extent.
Assume a depth of 1, unless an explicit imageClass is the receiver.

o  extent: ext depth: d
ST-80 compatibility

o  extent: ext depth: d antiAliasedPalette: aBasicColorArray bgColor: bgColor
|colorMap aaImgArray|

colorMap := Array with:Color white with:Color blue.

aaImgArray := Depth8Image extent:300@400 depth:8 antiAliasedPalette:colorMap bgColor:Color white.
aaImgArray last
fillAntiAliasedArc:200@200
radius:80
from:0
angle:360
withColor:Color blue
antiAliasedPalette:aaImgArray first
startWith:aaImgArray second.

aaImgArray last inspect.


|colorMap aaImgArray|

colorMap := Array with:Color white with:Color black with:Color red with:Color blue.

aaImgArray := Depth8Image extent:300@400 depth:8 antiAliasedPalette:colorMap bgColor:Color white.
aaImgArray last fillAntiAliasedArc:205@195 radius:80 from:0 angle:90 withColor:Color red
colorDictionary:aaImgArray first
blendStart:aaImgArray second.
aaImgArray last fillAntiAliasedArc:200@200 radius:80 from:90 angle:270 withColor:Color blue
colorDictionary:aaImgArray first
blendStart:aaImgArray second.

aaImgArray last inspect.


o  extent: ext depth: d antiAliasedPalette: aBasicColorArray bgColor: bgColor mixedArray: mixedArray
emptyBits := ByteArray new:(newImage bytesPerRow * ext y).

Usage example(s):

        |colorMap aaImgArray|

        colorMap := Array with:Color white with:Color black with:Color red with:Color blue.

        aaImgArray := Depth8Image extent:300@400 depth:8 antiAliasedPalette:colorMap bgColor:Color white.
        aaImgArray last fillAntiAliasedArc:205@195 radius:80 from:0 angle:90 withColor:Color red
            colorDictionary:aaImgArray first
            blendStart:aaImgArray second.
        aaImgArray last fillAntiAliasedArc:200@200 radius:80 from:90 angle:270 withColor:Color blue
            colorDictionary:aaImgArray first
            blendStart:aaImgArray second.

        aaImgArray last inspect.

 ###################

        |colorMap aaImgArray|

        colorMap := Array with:Color white with:Color blue.

        aaImgArray := Depth8Image extent:300@400 depth:8 antiAliasedPalette:colorMap bgColor:Color white.
        aaImgArray last
            fillAntiAliasedArc:200@200
            radius:80
            from:0
            angle:360
            withColor:Color blue
            colorDictionary:aaImgArray first
            blendStart:aaImgArray second.

        aaImgArray last inspect.

o  extent: ext depth: d bits: bits
ST-80 compatibility; assume 32-bit padding

o  extent: ext depth: d bits: bits pad: padding
ST-80 compatibility

o  extent: ext depth: d bitsPerPixel: bpp palette: aColormap usingBits: bits
ST-80 compatibility

o  extent: ext depth: d palette: aColormap
create & return a blank image of the given size.
ST-80 compatibility

Usage example(s):

     Image extent:16@16 depth:8 palette:nil
     Image extent:16@16 depth:4 palette:nil
     Image extent:16@16 depth:2 palette:nil

o  extent: ext depth: d palette: aColormap bits: bits
ST-80 compatibility

o  extent: ext depth: d palette: aColormap bits: bits pad: padding
ST-80 compatibility

o  extent: ext fromArray: bits offset: offset
ST-80 compatibility

o  fromAlphaInImage: anImage
create & return an Image from the alpha channel ofanother image.
If I am a depth1 image, set the pixels for alpha > 127;
if I am a depth8 image, set the pixels to the alpha values.

o  fromDeviceForm: aForm maskForm: aMaskFormOrNil
create & return an image form aForm that is already on a device

o  fromForm: aForm
create & return an Image given a aForm

Usage example(s):

     |f|

     f := Form width:16 height:16.
     f clear.
     f displayLineFromX:0 y:0 toX:15 y:15.
     f inspect.
     (Image fromForm:f) inspect

Usage example(s):

     |f|

     f := Form width:16 height:16 depth:(Display depth) on:Display.
     f clear.
     f paint:(Color red).
     f displayLineFromX:0 y:0 toX:15 y:15.
     f paint:(Color green).
     f displayLineFromX:15 y:0 toX:0 y:15.
     f inspect.
     (Image fromForm:f) inspect

o  fromImage: anImage
create & return an Image given another image. This can be used to
convert an image to another depth.

o  fromImage: anImage photometric: photometricOrNil
create & return an Image given another image. This can be used to
convert an image to another depth.

Usage example(s):

     |i1 i8|

     i1 := Image fromFile:'libtool/bitmaps/SBrowser.xbm'.
     i8 := Depth8Image fromImage:i1.
     i8 inspect

o  fromSubForm: aRectangle in: aForm
create & return an subImage given a aForm

Usage example(s):

     |f|

     f := Form width:16 height:16.
     f clear.
     f displayLineFromX:0 y:0 toX:15 y:15.
     f inspect.
     (Image fromForm:f) inspect.
     (Image fromSubForm:(5@5 corner:10@10) in:f) inspect

Usage example(s):

     |f|

     f := Form width:16 height:16 depth:(Display depth) on:Display.
     f clear.
     f paint:(Color red).
     f displayLineFromX:0 y:0 toX:15 y:15.
     f paint:(Color green).
     f displayLineFromX:15 y:0 toX:0 y:15.
     f inspect.
     (Image fromForm:f) inspect.
     (Image fromSubForm:(5@5 corner:10@10) in:f) inspect

o  fromSubImage: anImage in: aRectangle
create & return an Image from a rectangular area in another image.
This can also be used to get a subimage in another depth.
As with layouts, the rectangle may contain integers (= nr of pixels) or float numbers (= relative size).
Color precision may be lost, if conversion is from a higher depth image.
For palette & rgb images, this may fail if a color cannot be represented.

Usage example(s):

     |i1 i8|

     i1 := Image fromFile:'bitmaps/gifImages/garfield.gif' inPackage:'stx:goodies'.
     i8 := Depth8Image fromSubImage:i1 in:(250@90 extent:50@50).
     i8 inspect

Usage example(s):

     |i1 i8|

     i1 := Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies'.
     i8 := Image fromSubImage:i1 in:(70@50 extent:50@50).
     i8 inspect

Usage example(s):

     |i1 i24|

     i1 := Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies'.
     i24 := Depth24Image fromSubImage:i1 in:(70@50 extent:50@50).
     i24 inspect

Usage example(s):

     |i1 i24|

     i1 := Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies'.
     i1 inspect.
     i24 := Depth24Image fromSubImage:i1 in:(0.25@0.25 extent:0.5@0.5).
     i24 inspect

o  new
create a new image. Redefined to set the photometric to
greyScale with black being 0 as default.

o  newForDepth: depth
create a new image. Redefined to set the photometric to
greyScale with black being 0 as default.

Usage example(s):

     Image newForDepth:8

o  pixelArrayNewByteSize: size

o  pixelArrayWithAll: anArray

o  width: w height: h
create a new image, given width, height.
Assume a depth of 1, unless an explicit imageClass is the receiver.

Usage example(s):

     (Depth24Image width:100 height:200) createPixelStore

o  width: w height: h depth: d
create a new image, given width, height and depth

o  width: w height: h depth: d fromArray: pixelData
create a new image, given width, height, depth and data.
Data must be a ByteArray containing correctly aligned bits for the specified
depth (8-bit padded).

Usage example(s):

     Image width:8
           height:8
           depth:1
           fromArray:#[2r11001100
                       2r00110011
                       2r11001100
                       2r00110011
                       2r11001100
                       2r00110011
                       2r11001100
                       2r00110011].

Usage example(s):

     Image width:8
           height:8
           depth:2
           fromArray:#[4r1100 4r1100
                       4r0011 4r0011
                       4r1100 4r1100
                       4r0011 4r0011
                       4r1100 4r1100
                       4r0011 4r0011
                       4r1100 4r1100
                       4r0011 4r0011].

Usage example(s):

     Image width:8
           height:8
           depth:4
           fromArray:#[16r00 16r01 16rf0 16rf1
                       16r02 16r03 16rf2 16rf3
                       16r04 16r05 16rf4 16rf5
                       16r06 16r07 16rf6 16rf7
                       16r08 16r09 16rf8 16rf9
                       16r0a 16r0b 16rfa 16rfb
                       16r0c 16r0d 16rfc 16rfd
                       16r0e 16r0f 16rfe 16rff].

Usage example(s):

     Image width:8
           height:8
           depth:16
           fromArray:#(1 1 1 1 1 1 1 1
                       2 2 2 2 2 2 2 2
                       3 3 3 3 3 3 3 3
                       4 4 4 4 4 4 4 4
                       5 5 5 5 5 5 5 5
                       6 6 6 6 6 6 6 6
                       7 7 7 7 7 7 7 7
                       8 8 8 8 8 8 8 8
                      ) asWordArray.

o  width: w height: h depth: d fromArray: pixelData pad: padding
create a new image, given width, height, depth and data.
Data must be a ByteArray containing correctly aligned bits for the specified
depth.

o  width: w height: h fromArray: anArray
create a new image, given width, height. Assume a depth of 1 of the
receiving class is Image.
Data must be a ByteArray containing correctly aligned bits for depth 1
(i.e. 8 bits per byte).

Usage example(s):

     Image width:8
           height:8
           fromArray:#[2r11001100
                       2r00110011
                       2r11001100
                       2r00110011
                       2r11001100
                       2r00110011
                       2r11001100
                       2r00110011].

o  width: w height: h photometric: photometric
create a new image, given width, height.
Assume a depth of 1, unless an explicit imageClass is the receiver.

o  width: w height: h photometric: photometric bitsPerSample: bitsPerSample
create a new image, given width, height.
Assume a depth of 1, unless an explicit imageClass is the receiver.

o  width: w height: h photometric: p depth: d fromArray: pixelData
create a new image, given width, height, depth and data.
Data must be a ByteArray containing correctly aligned bits for the specified
depth (8-bit padded).

Usage example(s):

     Image width:4
           height:4
           photometric:#blackIs0
           depth:8
           fromArray:#[0xFF 0xFF 0xFF 0xFF
                       0xFF 0x00 0x00 0xFF    
                       0xFF 0x00 0x00 0xFF
                       0xFF 0xFF 0xFF 0xFF] 

misc
o  bytesPerRowForWidth: width bitsPerPixel: bitsPerPixel
return the number of bytes in one scanline of an image.
(if there is no padding (except byte padding)

o  ditherAlgorithm
return the way we dither -
#threshold, or nil -> no dither
#pattern, or #ordered -> orderedDither (ugly, but fast)
#error or #floydSteinberg -> errorDiffusion; much better
#burkes -> errorDiffusion; even better.

o  ditherAlgorithm: aSymbol
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.

o  numberOfDitherColors: n
define how many colors (i.e. patterns) to use when
doing a pattern dither

o  orderedDitherMatrixOfSize: sz

queries
o  bytesPerRowForWidth: width depth: bitsPerPixel padding: padding
helper - return the number of bytes in one scanline of an image,
if scanlines are to be padded to padding-bits and the depth of the image is d.

Usage example(s):

     self bytesPerRowForWidth:7 depth:1 padding:8
     self bytesPerRowForWidth:7 depth:1 padding:16
     self bytesPerRowForWidth:7 depth:1 padding:32

     self bytesPerRowForWidth:15 depth:1 padding:8
     self bytesPerRowForWidth:15 depth:1 padding:16
     self bytesPerRowForWidth:15 depth:1 padding:32

o  defaultImageFileWriter
only used, if a file is saved with no particular extension
or explicit writer given.
For now, default to tiff format.
Will change to png, as soon as all mask formats are fully supported by it

o  defaultPhotometric
return the default photometric pixel interpretation.
This may be a somewhat old leftover from times, when tiff was the first image file type to be read.
Much better would be to always have some (possibly fake and virtual) colormap around, and ask that one.
However, in the meantime, many other classes depend on that, so that it should be kept as an API
- even when the internal representation will be replaced by something better in the future.

o  imageDepth
return the depth of images represented by instances of this class.
Must be redefined in concrete subclasses

** This method must be redefined in concrete classes (subclassResponsibility) **

o  imageFileSuffixes
return a collection of suffixes which are recognized as image-file suffix

Usage example(s):

     Image imageFileSuffixes

o  imageReaderClassForMIME: mimeType
return an appropriate imageReader class for a given mime type;
nil if there is none (or it did not install itself)

Usage example(s):

     Image imageReaderClassForMIME:'image/tiff'
     Image imageReaderClassForMIME:'image/x-portable-pixmap'

o  imageReaderClassForSuffix: aSuffix
marked as obsolete by Stefan Vogel at 8-Sep-2022

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  implementorForDepth: depth
return the class, which best implements images of the specified depth

o  isAbstract
Return if this class is an abstract class.
True is returned here for myself only; false for subclasses.
Abstract subclasses must redefine this again.

o  isImageFileSuffix: aSuffix
return true, if the given suffix is known to be an image files suffix

Usage example(s):

     Image isImageFileSuffix:'gif'
     Image isImageFileSuffix:'xbm'
     Image isImageFileSuffix:'foo'

o  mimeTypeFromSuffix: suffix
search my suffix information for a mime type and
return it; return nil if unknown

Usage example(s):

     Image mimeTypeFromSuffix:'gif'
     Image mimeTypeFromSuffix:'tiff'
     Image mimeTypeFromSuffix:'foobar'

screen capture
o  fromScreen
return an image of the full screen.
WARNING: this temporarily grabs the display
it may not work from within a buttonMotion
(use #fromScreen:on:grab: with a false grabArg then).

Usage example(s):

     Image fromScreen
     Image fromScreen inspect

o  fromScreen: aRectangle
return an image of a part of the screen.
WARNING: this temporarily grabs the display
it may not work from within a buttonMotion
(use #fromScreen:on:grab: with a false grabArg then).

Usage example(s):

     Image fromScreen:(0@0 corner:100@100)
     (Image fromScreen:(0@0 corner:100@100)) inspect

o  fromScreen: aRectangle on: aDevice
return an image of a part of a screen, which may be on
another display device.
WARNING: this temporarily grabs the display
it may not work from within a buttonMotion
(use #fromScreen:on:grab: with a false grabArg then).

Usage example(s):

     Image fromScreen:(0@0 corner:100@100)

Usage example(s):

get a snapshot of your friends screen ...

     |dpy2|

     dpy2 := XWorkstation new initializeFor:'idefix:0'.
     (Image fromScreen:(dpy2 bounds) on:dpy2) inspect

o  fromScreen: aRectangle on: aDisplay grab: doGrab
return an image of a part of the screen, which may be on
another Display. If the doGrab argument is true, the display
is grabbed (i.e. blocked for others) and a camera cursor is
shown while the readout is done.
WARNING: with doGrab true, this temporarily grabs the display
and it may not work from within a buttonMotion
(use with a false grabArg then).

Usage example(s):

     Image fromScreen:(0@0 corner:100@100)

o  fromScreenArea
return an image of a part of the screen;
let user specify screen area.
This is the same as #fromUser - kept for backward compatibility.
Use #fromUser for ST-80 compatibility.
WARNING: this temporarily grabs the display
it may not work from within a buttonMotion
(use #fromScreen:on:grab: with a false grabArg then).

Usage example(s):

     Image fromScreenArea
     Image fromScreenArea inspect

o  fromUser
return an image of a part of the screen; let user specify screen area.
Same as fromScreenArea, for ST-80 compatibility.
WARNING: this temporarily grabs the display
it may not work from within a buttonMotion
(use #fromScreen:on:grab: with a false grabArg then).

Usage example(s):

     Image fromUser
     Image fromUser inspect

o  fromView: aView
return an image taken from a view's contents as currently
on the screen. The returned image has the same depth and photometric
as the Display.
Notice that for invisible or partial covered views,
the returned Image is NOT correct.
You may want to raise the view before using this method.
WARNING: this temporarily grabs the display
it may not work from within a buttonMotion
(use #fromView:grab: with a false grabArg then).

Usage example(s):

     Image fromView:(Launcher allInstances first window topView)
     Image fromView:(BrowserView allInstances first topView)

o  fromView: aView grab: doGrab
return an image taken from a view's contents as currently
on the screen. If the doGrab argument is true, the display
is grabbed (i.e. blocked for others) and a camera cursor is
shown while the readout is done.
The returned image has the same depth and photometric
as the Display.
Notice that for invisible or partial covered views,
the returned Image is NOT correct.
You may want to raise the view before using this method.
WARNING: with doGrab true, this temporarily grabs the display
and it may not work from within a buttonMotion
(use with a false grabArg then).

o  fromView: aView grab: doGrab withDecoration: withDecoration
return an image taken from a view's contents as currently
on the screen, optionally with decoration included.
If the doGrab argument is true, the display
is grabbed (i.e. blocked for others) and a camera cursor is
shown while the readout is done.
The returned image has the same depth and photometric
as the Display.
Notice that for invisible or partial covered views,
the returned Image is NOT correct.
You may want to raise the view before using this method.
WARNING: with doGrab true, this temporarily grabs the display
and it may not work from within a buttonMotion
(use with a false grabArg then).

Usage example(s):

     Transcript topView raise. (Image fromView:Transcript topView grab:false withDecoration:false) inspect
     Transcript topView raise. (Image fromView:Transcript topView grab:false withDecoration:true) inspect


Instance protocol:

Compatibility-Squeak
o  boundingBox

o  colormapIfNeededForDepth: d

o  colorsFromArray: anArrayOfRGBTriples
for squeak compatibility with ColorForm:
set the colorMap from an array of rgb triples, each value being in 0..1.

Usage example(s):

     Depth8Image new
        colorsFromArray:#( (0.5 0.5 0.5) (0.25 0.0 0.0) (0.0 0.25 0.5))

o  fill: aRectangle fillColor: aColor
fill the rectangular area specified by aRectangle with the given color

o  fillBlack: aRectangle
fill the rectangular area specified by aRectangle with the black color

Usage example(s):

     |img|
     img := Image extent:100@100 depth:24.
     img photometric:#rgb.
     img data:(ByteArray new:100*100*3).
     img fillWhite:(0@0 corner:100@100).
     img fillBlack:(10@10 corner:90@90).
     img inspect.

o  fillRectangle: aRectangle color: aColor
fill the rectangular area specified by aRectangle with the given color

o  fillWhite: aRectangle
fill the rectangular area specified by aRectangle with the white color

o  isTransparentAt: aPoint

o  pixelValueAt: aPoint

Compatibility-VW
o  asCachedImage
return the receiver associated to the current screens device.
For ST-80 compatibility
(ST/X uses Image for both device- and nonDevice-images)

o  asRetainedMedium
return the receiver associated to the current screens device.
For ST-80 compatibility
(ST/X uses Image for both device- and nonDevice-images)

o  bounds: newBounds

o  containsPoint: aPoint
in st-80, images are visualComponents ...

o  convertToPalette: aColormap renderedBy: anImageRenderer
this does not really mimicri the corresponding ST-80 functionality

o  paintBasis
huh - whats that;
I guess, I have to return Color for images without a mask,
and CoverageValue for those with a mask; for now, always return Color

o  preferredBounds

o  tile: bounds from: origin in: tile rule: rule

o  valueAtPoint: aPoint put: aColorValue

accessing
o  bitsPerSample
return the number of bits per sample.
The return value is an array of bits-per-plane.

o  colorMap
return the colormap

o  colorMap: newColorMapArg
set the colorMap; this also sets the photometric to a useful default.

o  colorMapFromArray: anArray
set the colorMap by reading colors from an array with rgb-byte values.
The (byte-)Array argument should be of the form:
#( red0 green0 blue0 red1 green1 blue1 ... redN greenN blueN)
where each component must be a byteValue in 0..255.

o  colorMapFromRGBValueArray: anArray
set the colorMap by reading colors from an array with rgb-integer values.
The (integer-)Array argument should be of the form:
#( rgb0 rgb1 ... rgbN)
where each element must be an rgbValue in 0..FFFFFF.

o  container: aVisualContainer
ignored here - added to allow images to be used like
VisualComponents (later, Image should inherit from it)

o  depth
return the depth of the image

o  device
return the device, the receiver is associated with.
Return nil, if the image is unassigned.
Please use graphicsDevice for ST80 compatibility.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  drawableId
return the id of the image on the device.
Return nil, if the image is unassigned.

o  effectiveColorMap
return an actual or computed colormap

o  extent
return the image's extent

o  fileName
the fileName or URL from which this image was loaded (if known);
for information only; useful in the inspector

o  fileName: aFilenameOrURL
set the fileName (or URL);
useful to document where an image came from
(especially in the inspector)

o  fullColorId
return the id of the full color image on the device.
Return nil, if the image is unassigned.

o  graphicsDevice
same as #device - for ST-80 compatibility

o  height
return the height of the image

o  id
Obsolete, use #drawableId!

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  imageSequence
return the frameSequence of which this image is a part of;
nil if it is not part of a sequence.

o  imageSequence: aCollection
private entry for imageReaders - set the frameSequence of which
this image is a part of

o  mask

o  mask: anotherImage
set the image's mask - currently, this may be nil or a Depth1Image.
(it is planned to support alpha information in a Depth8 maskImage in
the near future).
For depth1 masks: each pixel of the image where a corresponding
1-bit is present in the mask will be drawn;
0-bit mask pixels lead to transparent pixels.

For depth8 masks: (future):
each pixel specifies the alpha value (0..255),
which specifies the transparency of that pixel.
0 means completely transparent, 255 means completely
opaque. The 1-plane mask is a special case of this,
interpreting a 0 as a 0 alpha value and 1's as an
alpha value of 255.

o  maskedPixelsAre0
return true if masked pixels have been cleared to zero

o  maskedPixelsAre0: aBoolean
set/clear the flag which states if masked pixels
have been set to zero. Knowing this to be true allows
faster drawing of the image later; (however, not setting
it will still produce correct output).
This flag is typically set by image readers.

o  metaData

o  metaData: aDictionaryLike
Modified (format): / 25-05-2023 / 13:12:58 / cg

o  monochromeId
return the id of the monochrome image on the device.
Return nil, if the image is unassigned.

o  orientation
non nil, if there was metadata (edif) info present.
If nil is returned, assume topLeft (i.e. 'normal')

o  palette
return the colormap; ST-80 compatibility

o  palette: aColormap
set the colormap; ST-80 compatibility

o  photometric
return the photometric, a symbol such as #palette, #rgb etc.
This may be a somewhat old leftover from times, when tiff was the first image file type to be read.
Much better would be to always have some (possibly fake and virtual) colormap around, and ask that one.
However, in the meantime, many other classes depend on that, so that it should be kept as an API
- even when the internal representation will be replaced by something better in the future.

o  samplesPerPixel
return the number of samples per pixel in the image.

o  setColorMap: newColorMap
Modified (format): / 03-02-2017 / 16:39:48 / cg

o  width
return the width of the image

accessing-pixels
o  at: aPoint
WARNING: for now, this returns a pixel's color
(backward compatibility with ST/X)
In the future, this will return a pixel value (ST-80 compatibility)
Use #colorAt: - for future compatibility.

retrieve the pixel at aPoint; return a color.
Pixels start at 0@0 for upper left pixel, end at
(width-1)@(height-1) for lower right pixel.
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  at: aPoint put: aColorOrPixel
WARNING: for now, this expects a pixel's color
(backward compatibility with ST/X)
In the future, this will expect a pixel value (ST-80 compatibility)
Use #colorAt:put: - for future compatibility.

set the pixel at aPoint to aColor.
Pixels start at 0@0 for the upper left pixel, end at
(width-1)@(height-1) for lower right pixel.
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

o  atImageAndMask: aPoint put: aColorOrPixelOrNil
set the pixel at x/y to aColor.
If aColor is a mask color (i.e. Color noColor) the mask pixel will be set to 0 (transparent),
otherwise to 1. Nil is treated like noColor.
(used by the bitmap editor)

o  atImageAndMask: aPoint putValue: aPixelValueOrNil
set the pixel at x/y to aColor.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

o  atPoint: aPoint
ST-80 compatibility: return the pixelValue at:aPoint.

o  atPoint: aPoint put: aPixelValue
ST-80 compatibility: set the pixelValue at:aPoint.

o  atX: x y: y
WARNING: for now, this returns a pixel's color
(backward compatibility with ST/X)
In the future, this will return a pixel value (ST-80 compatibility)
Use #colorAt: - for future compatibility.

Retrieve a pixel at x/y; return a color.
Pixels start at 0@0 for upper left pixel, end at
(width-1)@(height-1) for lower right pixel.
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  atX: x y: y put: aColor
WARNING: for now, this expects a pixel's color
(backward compatibility with ST/X)
In the future, this will expect a pixel value (ST-80 compatibility)
Use #colorAt:put: - for future compatibility.

set the pixel at x/y to aColor.
Pixels start at 0@0 for the upper left pixel, end at
(width-1)@(height-1) for the lower right pixel.
This method checks if the color can be stored in the image.
(i.e. if the receiver is a palette image, the color must be present in there).
You should not use this method for image-processing, it is very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

o  atX: x y: y putValue: aPixelValue
set the pixel at x/y to aPixelValue.
The interpretation of the pixelValue depends on the photometric
and the colormap. (see also: Image>>atX:y:put:)
Pixels start at 0@0 for the upper left pixel, end at
(width-1) @ (height-1) for the lower right pixel.
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  bits
return the raw image data (pixel data);
depending on the photometric, this has to be interpreted as monochrome,
greyscale, palette or rgb data.
It is also packed to be dense, so a 4 bitPerSample palette image
will store 2 pixels per byte, whereas a 2-bitPerPixel image will store
4 pixels per byte.

o  colAt: x
retrieve an array filled with pixel values from a single column.
(eg. a vertical span)
Notice: row/column coordinates start at 0.
The interpretation of the pixel values depends on the photometric.
This is a slow fallBack method, which works with any depth;
concrete image subclasses should redefine this for more performance.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     (i colAt:0) inspect

o  colAt: x into: aPixelBuffer
fill aBuffer with pixel values retrieved from a single column.
(eg. a vertical span)
Notice: row/column coordinates start at 0.

o  colAt: x into: aPixelBuffer startingAt: startIndex
fill aBuffer with pixel values retrieved from a single column.
(eg. a vertical span)
Notice: row/column coordinates start at 0.
This is a slow fallBack method, which works with any depth;
concrete image subclasses should redefine this for more performance.

o  colAt: x putAll: pixelArray
store a single column's pixels from bits in the argument;
(eg. a vertical span)
Notice: row/column coordinates start at 0.
This is a slow fallBack method, which works with any depth;
concrete image subclasses should redefine this for more performance.

o  colAt: x putAll: pixelArray startingAt: startIndex
store a single row's pixels from bits in the pixelArray argument.
(eg. a vertical span)
Notice: row/column coordinates start at 0.
This is a slow fallBack method, which works with any depth;
concrete image subclasses should redefine this for more performance.

o  colorAt: aPoint
retrieve a pixel at x/y; return a color.
Pixels start at 0@0 for upper left pixel, end at
(width-1)@(height-1) for lower right pixel.
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

o  colorAt: aPoint put: aColor

o  colorAtX: x y: y
retrieve a pixel at x/y; return a color.
Pixels start at 0@0 for upper left pixel, end at
(width-1)@(height-1) for lower right pixel.
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

o  colorAtX: x y: y put: aColor
set the pixel at x/y to aColor.
Pixels start at 0@0 for the upper left pixel, end at
(width-1)@(height-1) for the lower right pixel.
This method checks if the color can be stored in the image.
(i.e. if the receiver is a palette image, the color must be present in there).
You should not use this method for image-processing, it is very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

o  data
for backward compatibility - will vanish

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  data: aByteArray
for backward compatibility - will vanish

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  maskAt: aPoint
retrieve the maskValue at aPoint - an integer number which is
0 for masked pixels (invisible), 1 for unmasked (visible).
For images without mask, 1 is returned for all pixels.

o  maskAt: aPoint put: maskValue
set the maskValue at aPoint - an integer number which is
0 for masked pixels (invisible), 1 for unmasked (visible).

o  maskAtX: x y: y
retrieve the maskValue at aPoint - an integer number which is
0 for masked pixels (invisible), 1 for unmasked (visible).
For images without mask, 1 is returned for all pixels.

o  maskAtX: x y: y put: maskValue
set the maskValue at aPoint - an integer number which is
0 for masked pixels (invisible), 1 for unmasked (visible).

o  pixelAt: aPoint
retrieve a pixel at x/y; return a pixel value.
Pixels start at 0@0 for upper left pixel, end at
(width-1)@(height-1) for lower right pixel.
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

o  pixelAt: aPoint put: aPixelValue
set the pixel at x/y to aPixelValue.
The interpretation of the pixelValue depends on the photometric
and the colormap. (see also: Image>>atX:y:put:)
Pixels start at 0@0 for the upper left pixel, end at
(width-1) @ (height-1) for the lower right pixel.
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

o  pixelAtX: x y: y
retrieve the pixelValue at aPoint; return a pixel (an integer number).
Pixels start at 0/0 for upper left pixel, and end at
width-1@height-1 for lower right pixel.
The returned number's interpretation depends on the photometric
and the colormap. (see also Image>>at: and Image>>atX:y:)
You should not use this method for image-processing of
big images, it's very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

** This method must be redefined in concrete classes (subclassResponsibility) **

o  pixelAtX: x y: y put: aPixelValue
set the pixel at x/y to aPixelValue.
The interpretation of the pixelValue depends on the photometric
and the colormap. (see also: Image>>atX:y:put:)
Pixels start at 0@0 for the upper left pixel, end at
(width-1) @ (height-1) for the lower right pixel.
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

** This method must be redefined in concrete classes (subclassResponsibility) **

o  rgbValueAt: aPoint
retrieve a pixel's rgb value at x/y;
return a 24bit rgbValue (rgb, red is MSB),
or 32bit for alpha images (argb, alpha is MSB).
Pixels start at 0@0 for the upper left pixel,
and end at (width-1)@(height-1) for the lower right pixel.

o  rgbValueAtX: x y: y
retrieve a pixel's rgb value at x/y;
return a 24bit rgbValue (rgb, red is MSB),
or 32bit for alpha images (argb, alpha is MSB).
Pixels start at 0@0 for the upper left pixel,
and end at (width-1)@(height-1) for the lower right pixel.

o  rgbValueAtX: x y: y put: newRGBValue
expects a 24bit rgbValue (rgb, red is MSB),
or 32bit for alpha images (argb, alpha is MSB).

o  rowAt: y
retrieve an array filled with pixel values from a single row.
(eg. a horizontal span)
Notice: row/column coordinates start at 0.
The interpretation of the pixel values depends on the photometric.
This is a slow fallBack method, which works with any depth;
concrete image subclasses should redefine this for more performance.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     (i rowAt:0) inspect

Usage example(s):

     |i|

     i := Image fromFile:'libtool/bitmaps/SBrowser.xbm'.
     (i rowAt:0) inspect

o  rowAt: y into: aPixelBuffer
fill aBuffer with pixel values retrieved from a single row.
(eg. a horizontal span)
The interpretation of the pixel values depends on the photometric.
Notice: row/column coordinates start at 0.

o  rowAt: y into: aPixelBuffer startingAt: startIndex
fill aBuffer with pixel values retrieved from a single row.
(eg. a horizontal span)
The interpretation of the pixel values depends on the photometric.
Notice: row/column coordinates start at 0.
This is a slow fallBack method, which works with any depth;
concrete image subclasses should redefine this for more performance.

o  rowAt: y putAll: pixelArray
store a single row's pixels from bits in the argument;
(eg. a horizontal span)
The interpretation of the pixel values depends on the photometric.
Notice: row/column coordinates start at 0.
This is a slow fallBack method, which works with any depth;
concrete image subclasses should redefine this for more performance.

o  rowAt: y putAll: pixelArray startingAt: startIndex
store a single row's pixels from bits in the pixelArray argument;
(eg. a horizontal span)
The interpretation of the pixel values depends on the photometric.
Notice: row/column coordinates start at 0.
This is a slow fallBack method, which works with any depth;
concrete image subclasses should redefine this for more performance.

o  valueAt: aPoint
WARNING: for now, this returns a pixel's value
(backward compatibility with ST/X)
In the future, this will return a color (ST-80 compatibility)
Use #pixelAt: - for future compatibility.

Retrieve the pixelValue at aPoint; return an integer number.
Pixels start at 0@0 for upper left pixel, end at
width-1@height-1 for lower right pixel.
The returned numbers interpretation depends on the photometric
and the colormap. (see also Image>>at: and Image>>atX:y:)
You should not use this method for image-processing, its
very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

o  valueAtX: x y: y
WARNING: for now, this returns a pixel's value
(backward compatibility with ST/X)
In the future, this will return a color (ST-80 compatibility)
Use #pixelAt: - for future compatibility.

Retrieve the pixelValue at aPoint; return an integer number.
Pixels start at 0/0 for upper left pixel, and end at
width-1@height-1 for lower right pixel.
The returned numbers interpretation depends on the photometric
and the colormap. (see also Image>>at: and Image>>atX:y:)
You should not use this method for image-processing of
big images, its very slow ...
(it is meant to access individual pixels - for example, in a bitmap editor)

accessing-private
o  bits: aByteArrayOrNil
set the raw pixel data.
With a nil argument, a pixel byte array of the correct size is allocated.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation
(it does not care for colormaps and/or cached device image flushing).

o  bits: aByteArrayArg colorMap: clrMapArg
set the raw data.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation
(it does not care for colormaps and/or cached device image flushing).

o  bits: aByteArrayArg colorMap: clrMapArg mask: maskArg
set the raw data.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation
(it does not care for colormaps and/or cached device image flushing).

o  bits: aByteArrayArg colorMapFromArray: clrMapArg
set the raw data.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation
(it does not care for colormaps and/or cached device image flushing).

o  bits: aByteArrayArg colorMapFromArray: clrMapArg mask: maskArg
set the raw data.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation
(it does not care for colormaps and/or cached device image flushing).

o  bits: aByteArrayArg mask: maskArg
set the raw data.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation
(it does not care for colormaps and/or cached device image flushing).

o  bitsPerSample: aCollection
set the number of bits per sample.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  depth: d
set the depth of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  extent: anExtent
set the image's extent.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  hasAlphaChannel

o  height: aNumber
set the height of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  photometric: aSymbol
set the photometric interpretation of the pixel values.
The argument, aSymbol is one of:
#blackIs0, #whiteIs0, #palette, #rgb, #rgba
See TIFF documentation, from which the photometric concept is borrowed.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  samplesPerPixel: aNumber
set the array of samples per pixel.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  width: aNumber
set the width of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  width: w height: h
set the width and height of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  width: w height: h depth: d
set the width, height and depth of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  width: w height: h depth: d fromArray: bits
set the width, height, depth and pixels of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  width: w height: h depth: d palette: aColormap
set the width, height and depth of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  width: w height: h photometric: p
set the width, height and photometric of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  width: w height: h photometric: p samplesPerPixel: spp bitsPerSample: bps colorMap: cm bits: pixels
set all relevant internal state of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

o  width: w height: h photometric: p samplesPerPixel: spp bitsPerSample: bps colorMap: cm bits: pixels mask: m
set all relevant internal state of the image.

This interface is only to be used when initializing
instances or by image readers. Calling for a change of an
existing image may confuse later pixel interpretation.

comparing
o  = anImage
(comment from inherited method)
return true if the receiver and the arg have the same structure.
Notice:
This method is partially open coded (inlined) by the compiler(s)
identical objects are always considered equal.
redefining it may not work as expected.

o  hash
Image fromScreen hash

conversion helpers
o  rgbColormapFor: aDevice
helper for conversion to rgb format

converting
o  anyImageAsTrueColorFormOn: aDevice
general fallback to return a true-color device-form for the receiver.

o  asBase64PNGSize: size
generate a base64 encoded PNG of myself;
if size is nil, the original receiver is encoded;
otherwise I am scaled to the given size first and then encoded

Usage example(s):

     (Image fromScreen:(0@0 corner:100@100)) asBase64PNGSize:nil

o  asDepth24Image
return a new image with my pixels in depth24.
If the receiver's depth is already 24 bits/pixel, return it

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     i asDepth24Image.

o  asFormOn: aDevice
get a device form, with best possible approximation.
remember it in case someone asks again.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     (i asFormOn:Display) inspect.

o  asGrayFormOn: aDevice
get a gray device form

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/claus.gif'.
     (i asGrayFormOn:Display) inspect.

o  asGrayFormOn: aDevice dither: aDitherAlgorithm
get a greyscale device form, using aDitherAlgorithm.

o  asGrayImageDepth: depthArg
get a gray image from the receiver.
If required, DitherAlgorithm is applied

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     (i asGrayImageDepth:16).
     (i asGrayImageDepth:4).

o  asGrayImageDepth: depth dither: aDitherAlgorithm
get a greyscale image, using aDitherAlgorithm.

o  asImageWithDepth: depth
return a new image with another depth. Notice that this
may raise an error, if the depth is smaller than the receiver's depths
and the number of colors is greater than the number of possible colors
for the new depth - i.e. you should use this only to convert to a higher depth.
In the other case, use one of the dithering converters

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     (i asImageWithDepth:24) inspect.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     (i asImageWithDepth:4) inspect.

o  asMonochromeFormOn: aDevice
get a monochrome device form

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     (i asMonochromeFormOn:Display) inspect.

o  asMonochromeFormOn: aDevice dither: aDitherAlgorithm
get a monochrome device form, using aDitherAlgorithm.

o  asPseudoFormQuickOn: aDevice
return a pseudo-deviceForm from the image.
Fail if any color is not available (i.e. do not dither).

Usage example(s):

     (
        (((Depth4Image
             width:4
             height:4
             fromArray:#[
                            16r01 16r23
                            16r45 16r67
                            16r89 16rab
                            16rcd 16ref
                        ]))
               magnifiedBy:30
         )
          asPseudoFormQuickOn:Display
      ) inspect

o  clearMaskedPixels
assuming that I already have a device representation
in deviceForm, clear any masked pixels.
This will allow faster drawing in the future.

o  exactOn: aDevice
for compatibility with color protocol - here, the same as #onDevice.

o  exactOrNearestOn: aDevice
for compatibility with color protocol - here, the same as #onDevice.

o  fromAlphaInImage: anImage
setup the receiver from the alpha channel of another image.
WARNING:
This implementation is a slow fallback (the loop over the
source pixels is very slow). If this method is used heavily, you
may want to redefine it in concrete subclasses for common source images.

o  fromForm: aForm
setup the receiver from a form

o  fromImage: anImage
setup the receiver from another image.
Color precision may be lost, if conversion is from a higher depth image.
WARNING:
This implementation is a slow fallback (the loop over the
source pixels is very slow). If this method is used heavily, you
may want to redefine it in concrete subclasses for common source images.

o  fromImage: anImage photometric: photometricOrNil
setup the receiver from another image and optionally set the photometric.
Color precision may be lost, if conversion is from a higher depth image.
WARNING:
This implementation is a slow fallback (the loop over the
source pixels is very slow). If this method is used heavily, you
may want to redefine it in concrete subclasses for common source images.

Usage example(s):

     |i i2 i4 i8 i16 i24|

     i := GenericToolbarIconLibrary desktop32x32Icon2.
     i inspect.
     i2 := Depth2Image fromImage:i.
     i2 inspect.
     i4 := Depth4Image fromImage:i.
     i4 inspect.
     i8 := Depth8Image fromImage:i.
     i8 inspect.
     i16 := Depth16Image fromImage:i.
     i16 inspect.
     i24 := Depth24Image fromImage:i.
     i24 inspect.

Usage example(s):

     |i i24|

     i := Image fromFile:'bitmaps/gifImages/garfield.gif' inPackage:'stx:goodies'.
     Transcript showCR:(
        Time millisecondsToRun:[
            i24 := Depth24Image fromImage:i.
        ]
     ).
     i24 inspect.

Usage example(s):

     |i i24|

     i := Image fromFile:'bitmaps/gifImages/garfield.gif' inPackage:'stx:goodies'.
     MessageTally spyOn:[
        i24 := Depth24Image fromImage:i.
     ]

o  fromSubImage: anImage in: aRectangle
setup the receiver from another image, extracting a rectangular area.
As with layouts, the rectangle may contain integers (= nr of pixels) or float numbers (= relative size).
Color precision may be lost, if conversion is from a higher depth image.
For palette & rgb images, this may fail if a color cannot be represented.

Usage example(s):

     |i i2 i4 i8 i16 i24|

     i := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     i inspect.
     i4 := Depth4Image fromSubImage:i in:(300@160 corner:340@200).
     i4 inspect.
     i8 := Depth8Image fromSubImage:i in:(300@160 corner:340@200).
     i8 inspect.
     i24 := Depth24Image fromSubImage:i in:(300@160 corner:340@200).
     i24 inspect.

o  fromSubImage: anImage inX: x y: y width: w height: h
setup the receiver from another image, extracting a rectangular area.
Color precision may be lost, if conversion is from a higher depth image.
For palette & rgb images, this may fail if a color cannot be represented.

WARNING:
This implementation is a slow fallback (the loop over the
source pixels is very slow). If this method is used heavily, you
may want to redefine it in concrete subclasses for the common case of
of creating a subImage with the same depth & palette.

Usage example(s):

     |i i2 i4 i8 i16 i24|

     i := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     i inspect.
     i4 := Depth4Image fromSubImage:i in:(300@160 corner:340@200).
     i4 inspect.
     i8 := Depth8Image fromSubImage:i in:(300@160 corner:340@200).
     i8 inspect.
     i24 := Depth24Image fromSubImage:i in:(300@160 corner:340@200).
     i24 inspect.

o  monochromeOn: aDevice
return a monochrome device image of the receiver for aDevice.
(monochrome, even if device supports colors)

o  nearestOn: aDevice
for compatibility with color protocol - here, the same as #onDevice.

o  on: aDevice
return an image with the same pixels as the receiver, but
associated to aDevice. If the receiver is not yet bound to
a device, this will be the receiver. Otherwise, a new image
is returned.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  onDevice: aDevice
return an image with the same pixels as the receiver, but
associated to aDevice. If the receiver is not yet bound to
a device, this will be the receiver. Otherwise, a new image
is returned.

converting - dithering
o  asBurkesDitheredMonochromeImage
return a burkes dithered monochrome image from the receiver image.
Depending on the image's contents, this may or may not look better than
a floyd-steinberg dithered image.
Notice that floyd-steinberg dithering is faster; both because less
error diffusion is done and due to being specially tuned.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i inspect.
     i asFloydSteinbergDitheredMonochromeImage inspect.
     i asBurkesDitheredMonochromeImage inspect.
     i asOrderedDitheredMonochromeImage inspect.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     i inspect.
     i asFloydSteinbergDitheredMonochromeImage inspect.
     i asBurkesDitheredMonochromeImage inspect.
     i asOrderedDitheredMonochromeImage inspect.

Usage example(s):

     |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.

o  asDitheredImageUsing: colors
return a dithered image from the picture,
using colors in colors for dithering.

o  asDitheredImageUsing: colors depth: d
return a dithered image from the picture,
using colors in colors for dithering.

o  asErrorDitheredMonochromeImage
return an error-diffusion dithered monochrome image from the receiver image.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i inspect.
     i asErrorDitheredMonochromeImage inspect.
     i asOrderedDitheredMonochromeImage inspect.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     i inspect.
     i asErrorDitheredMonochromeImage inspect.
     i asOrderedDitheredMonochromeImage inspect.

Usage example(s):

     |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.

o  asFloydSteinbergDitheredDepth8FormOn: aDevice colors: fixColors
return a floyd-steinberg dithered pseudoForm from the picture.
Use the colors in the fixColors array.
By passing the ditherColors as extra array, this method can
also be used to dither an 8bit image into a smaller number of colors,
for example to create dithered Depth4Images from Depth8Images.

o  asFloydSteinbergDitheredDepth8FormOn: aDevice colors: fixColors nRed: nRed nGreen: nGreen nBlue: nBlue
return a floyd-steinberg dithered pseudoForm from the palette picture.
Use the colors in the fixColors array, which must be fixR x fixG x fixB
colors assigned to aDevice, such as the preallocated colors of the
Color class.
By passing the ditherColors as extra array, this method can
also be used to dither an 8bit image into a smaller number of colors,
for example to create dithered Depth4Images from Depth8Images.

o  asFloydSteinbergDitheredGrayFormOn: aDevice
return a dithered depth-x grey form from the receiver image.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     (i asFloydSteinbergDitheredGrayFormOn:Display) inspect

Usage example(s):

     |i|

     i := Image fromFile:'bitmaps/granite.tiff'.
     (i asFloydSteinbergDitheredGrayFormOn:Display) inspect

o  asFloydSteinbergDitheredGrayImageDepth: newDepth
return a floyd-steinberg dithered image from the receiver image.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:1) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:2) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:4) inspect.

Usage example(s):

     |i|

     i := Depth24Image width:4 height:1
          fromArray:#[
            16rFF 16r00 16r00   16rFF 16r00 16r00  16rFF 16r00 16r00  16rFF 16r00 16r00
            16rFF 16r00 16r00   16rFF 16r00 16r00  16rFF 16r00 16r00  16rFF 16r00 16r00
            16rFF 16r00 16r00   16rFF 16r00 16r00  16rFF 16r00 16r00  16rFF 16r00 16r00
            16rFF 16r00 16r00   16rFF 16r00 16r00  16rFF 16r00 16r00  16rFF 16r00 16r00].
     i := i magnifiedBy:4@1.
     i inspect.

     (i asFloydSteinbergDitheredGrayImageDepth:1) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:2) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:4) inspect.

Usage example(s):

     |i|

     i := Depth24Image width:4 height:6
          fromArray:#[
            16r00 16r00 16r00   16r00 16r00 16r80  16r00 16r00 16rff  16r00 16r80 16r00
            16r00 16r80 16r80   16r00 16rFF 16r00  16r00 16rFF 16r80  16r00 16rFF 16rFF
            16r80 16r00 16r00   16r80 16r00 16r80  16r80 16r00 16rff  16r80 16r80 16r00
            16r80 16r80 16r80   16r80 16rFF 16r00  16r80 16rFF 16r80  16r80 16rFF 16rFF
            16rFF 16r00 16r00   16rFF 16r00 16r80  16rFF 16r00 16rff  16rFF 16r80 16r00
            16rFF 16r80 16r80   16rFF 16rFF 16r00  16rFF 16rFF 16r80  16rFF 16rFF 16rFF].
     i := i magnifiedBy:30.
     i inspect.

     (i asFloydSteinbergDitheredGrayImageDepth:1) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:2) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:4) inspect.

Usage example(s):

     |i|

     i := Image fromFile:'granite.tiff'.
     i inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:1) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:2) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:4) inspect.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     i inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:1) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:2) inspect.
     (i asFloydSteinbergDitheredGrayImageDepth:4) inspect.

Usage example(s):

     |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.

o  asFloydSteinbergDitheredMonochromeFormOn: aDevice
return a dithered moncohrome form from the receiver image.

Usage example(s):

     |i f|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     (i asFloydSteinbergDitheredMonochromeFormOn:Display) inspect.

Usage example(s):

     |i f|

     i := Depth2Image width:8 height:8
          fromArray:#[
                        4r0000 4r0000
                        4r0000 4r0000
                        4r1111 4r1111
                        4r1111 4r1111
                        4r2222 4r2222
                        4r2222 4r2222
                        4r3333 4r3333
                        4r3333 4r3333
                     ].
     (i asFloydSteinbergDitheredMonochromeFormOn:Display) inspect.

o  asFloydSteinbergDitheredMonochromeImage
return a floyd-steinberg dithered monochrome image from the receiver image.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i inspect.
     i asFloydSteinbergDitheredMonochromeImage inspect.
     i asBurkesDitheredMonochromeImage inspect.
     i asOrderedDitheredMonochromeImage inspect.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     i inspect.
     i asFloydSteinbergDitheredMonochromeImage inspect.
     i asBurkesDitheredMonochromeImage inspect.
     i asOrderedDitheredMonochromeImage inspect.

Usage example(s):

     |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.

o  asFloydSteinbergDitheredPseudoFormUsing: colors on: aDevice
return a floyd-steinberg dithered pseudoForm from the picture,
using colors in colors for dithering.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     (i asFloydSteinbergDitheredPseudoFormUsing:(Color getPrimaryColorsOn:Display) on:Display) inspect


     |i|

     Color allocateColorsIn:Color standardDitherColorsForDepth8 on:Display.

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     (i asFloydSteinbergDitheredPseudoFormUsing:Color standardDitherColorsForDepth8 on:Display) inspect

o  asOrderedDitheredGrayFormOn: aDevice
return a dithered depth-x grey form from the receiver image.
Uses an 8x8 dithermatrix.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     (i asOrderedDitheredGrayFormOn:Display) inspect

o  asOrderedDitheredGrayImageDepth: newDepth
return a dithered depth-x grey image from the receiver image.
Uses an 8x8 dithermatrix.

Usage example(s):

     |i i1 i2 i4 i8|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     i1 := i asOrderedDitheredGrayImageDepth:1.
     i1 inspect.

     i2 := i asOrderedDitheredGrayImageDepth:2.
     i2 inspect.

     i4 := i asOrderedDitheredGrayImageDepth:4.
     i4 inspect.

     i8 := i asOrderedDitheredGrayImageDepth:8.
     i8 inspect.

Usage example(s):

     |i i1 i2 i4 i8|
     i := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     i1 := i asOrderedDitheredGrayImageDepth:1.
     i1 inspect.

     i2 := i asOrderedDitheredGrayImageDepth:2.
     i2 inspect.

     i4 := i asOrderedDitheredGrayImageDepth:4.
     i4 inspect.

     i8 := i asOrderedDitheredGrayImageDepth:8.
     i8 inspect.

     i2 := i8 asOrderedDitheredGrayImageDepth:2.
     i2 inspect.

o  asOrderedDitheredMonochromeFormOn: aDevice
return a dithered monochrome form from the grey image.
Uses a 4x4 dithermatrix.

o  asOrderedDitheredMonochromeFormOn: aDevice ditherMatrix: ditherMatrix ditherWidth: dW
return a dithered monochrome form from the image.
Uses the passed ditherMatrix and ditherWidth.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     (i asOrderedDitheredMonochromeFormOn:Display) inspect


     |i|

     i := Image fromFile:'goodies/bitmaps/granite.tiff'.
     (i asOrderedDitheredMonochromeFormOn:Display) inspect


     |i|

     i := (Image fromFile:'goodies/bitmaps/PasteButton.tiff') magnifiedBy:10.
     (i asOrderedDitheredMonochromeFormOn:Display) inspect

o  asOrderedDitheredMonochromeImage
return a dithered monochrome image from the receiver image.
Uses a 4x4 dithermatrix.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     i asOrderedDitheredMonochromeImage inspect


     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     i asOrderedDitheredMonochromeImage inspect


     |i|

     i := (Image fromFile:'doc/online/pictures/PasteButton.gif') magnifiedBy:10.
     i asOrderedDitheredMonochromeImage inspect


     |i|

     i := (Image fromFile:'goodies/bitmaps/gifImages/blue-ball.gif') magnifiedBy:1.
     i asOrderedDitheredMonochromeImage inspect


     |i|

     i := Image fromFile:'libwidg3/bitmaps/granite.tiff'.
     i asOrderedDitheredMonochromeImage inspect

o  asOrderedDitheredMonochromeImageWithDitherMatrix: ditherMatrix ditherWidth: dW
return a dithered monochrome image from the receiver image.
Uses the passed ditherMatrix and ditherWidth.

Usage example(s):

thresholding at:0.5 (all above 0.5 becomes white):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     i
        asOrderedDitheredMonochromeImageWithDitherMatrix:(ByteArray new:16 withAll:8)
        ditherWidth:4

Usage example(s):

thresholding at: 0.25 (all above 0.25 becomes white):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     i
        asOrderedDitheredMonochromeImageWithDitherMatrix:(ByteArray new:16 withAll:3)
        ditherWidth:4

Usage example(s):

thresholding at: 0.75 (all above 0.75 becomes white):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     i
        asOrderedDitheredMonochromeImageWithDitherMatrix:(ByteArray new:16 withAll:11)
        ditherWidth:4

o  asStevensonArceDitheredMonochromeImage
return a stevenson-arce dithered monochrome image from the receiver image.
Depending on the image's contents, this may or may not look better than
a floyd-steinberg dithered image.
Notice that floyd-steinberg dithering is faster; both because less
error diffusion is done and due to being specially tuned.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i inspect.
     i asFloydSteinbergDitheredMonochromeImage inspect.
     i asBurkesDitheredMonochromeImage inspect.
     i asStevensonArceDitheredMonochromeImage inspect.
     i asOrderedDitheredMonochromeImage inspect.
     (i asThresholdMonochromeImage:0.5) inspect

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/claus.gif'.
     i inspect.
     i asFloydSteinbergDitheredMonochromeImage inspect.
     i asBurkesDitheredMonochromeImage inspect.
     i asStevensonArceDitheredMonochromeImage inspect.
     i asOrderedDitheredMonochromeImage inspect.

Usage example(s):

     |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.

converting - thresholding
o  asNearestPaintDepth8FormOn: aDevice colors: fixColors
return a nearest paint pseudoForm from the palette picture.
Use the colors in the fixColors array.
By passing the ditherColors as extra array, this method can
also be used to dither an 8bit image into a smaller number of colors,
for example to create dithered Depth4Images from Depth8Images.

o  asNearestPaintDepth8FormOn: aDevice colors: fixColors nRed: nRed nGreen: nGreen nBlue: nBlue
return a nearest paint pseudoForm from the palette picture.
Use the colors in the fixColors array, which must be fixR x fixG x fixB
colors assigned to aDevice, such as the preallocated colors of the
Color class.
By passing the ditherColors as extra array, this method can
also be used to dither an 8bit image into a smaller number of colors,
for example to create dithered Depth4Images from Depth8Images.

o  asNearestPaintImageDepth: d colors: colors
return a threshold image from the receiver picture, using colors in colors.

o  asThresholdGrayFormOn: aDevice
return a thresholded grey form from the receiver image.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/claus.gif'.
     (i asThresholdGrayFormOn:Display) inspect.

o  asThresholdGrayImageDepth: newDepth
return a thresholded depth-x grey image from the receiver image.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     (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.

o  asThresholdMonochromeFormOn: aDevice
return a threshold monochrome form from the image.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/claus.gif'.
     i inspect.
     (i asThresholdMonochromeFormOn:Display) inspect


     |i|

     i := (Image fromFile:'goodies/bitmaps/a11.ico') magnifiedBy:10.
     i inspect.
     (i asThresholdMonochromeFormOn:Display) inspect


     |i|

     i := Image fromFile:'goodies/bitmaps/granite.tiff'.
     i inspect.
     (i asThresholdMonochromeFormOn:Display) inspect


     |i|

     i := (Image fromFile:'goodies/bitmaps/PasteButton.tiff') magnifiedBy:10.
     i inspect.
     (i asThresholdMonochromeFormOn:Display) inspect

o  asThresholdMonochromeImage
return a threshold monochrome image from the image.
Threshold means: brightness < 0.5 -> black / otherwise white

Usage example(s):

     |i i2|

     i := Image fromFile:'goodies/bitmaps/claus.gif'.
     i2 := i asThresholdMonochromeImage


     |i i2|

     i := (Image fromFile:'/cdrom/icons/a/a11.ico') magnifiedBy:10.
     i2 := i asThresholdMonochromeImage


     |i i2|

     i := Image fromFile:'goodies/bitmaps/granite.tiff'.
     i2 := i asThresholdMonochromeImage


     |i i2|

     i := (Image fromFile:'goodies/bitmaps/PasteButton.tiff') magnifiedBy:10.
     i2 := i asThresholdMonochromeImage

o  asThresholdMonochromeImage: thresholdBrighness
return a threshold monochrome image from the image.
The argument (0..1) gives the threshold value;
Threshold means: brightness < threshold -> black / otherwise white

Usage example(s):

     |i|

     i := Image width:4 height:4 depth:4
                fromArray:#[ 16r01 16r23
                             16r45 16r67
                             16r89 16rab
                             16rcd 16ref ].
     i := i magnifiedBy:30.
     i inspect.
     (i asThresholdMonochromeImage:0.125) inspect.
     (i asThresholdMonochromeImage:0.25) inspect.
     (i asThresholdMonochromeImage:0.5) inspect.
     (i asThresholdMonochromeImage:0.75) inspect.
     (i asThresholdMonochromeImage:1) inspect.

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/claus.gif'.
     i inspect.
     (i asThresholdMonochromeImage:0.125) inspect.
     (i asThresholdMonochromeImage:0.25) inspect.
     (i asThresholdMonochromeImage:0.5) inspect.
     (i asThresholdMonochromeImage:0.625) inspect.
     (i asThresholdMonochromeImage:0.75) inspect.

converting greyscale images
o  anyImageAsFormOn: aDevice
return a (usually truecolor) deviceForm from an arbitrary image.

o  anyImageAsPseudoFormOn: aDevice
return a (usually truecolor) deviceForm from an arbitrary image.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  grayImageAsFormOn: aDevice
return a grey-deviceForm from the grey image.

o  grayImageAsPseudoFormOn: aDevice
return an 8-bit pseudo Form from the grey image

o  grayImageAsTrueColorFormOn: aDevice
return a true-color device-form for the grey-image receiver.
TODO: the pixel loops ought to be implemented as inline primitive code ...

o  greyImageAsFormOn: aDevice
marked as obsolete by exept MBP at 20-09-2021

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  greyImageAsPseudoFormOn: aDevice
marked as obsolete by exept MBP at 20-09-2021

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  greyImageAsTrueColorFormOn: aDevice
marked as obsolete by exept MBP at 20-09-2021

** This is an obsolete interface - do not use it (it may vanish in future versions) **

converting palette images
o  paletteImageAsFormOn: aDevice
return a device-form for the palette-image receiver

o  paletteImageAsPseudoFormOn: aDevice
return a pseudo-deviceForm from the palette image.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  paletteImageAsTrueColorFormOn: aDevice
return a true-color device-form for the palette-image receiver.

converting rgb images
o  asDitheredTrueColor8FormOn: aDevice
convert an rgb image to a dithered depth8-form on aDevice.
Return the device-form.
This method is only valid for trueColor displays.

o  compressColorMap
calculates a new color map for the image, using only used colors

o  copyPixels32AlphaHighTo24From: anImage
tuned helper to copy pixels from a 32bit rgba (alpha in high byte)
to me as a 24bit non-alpha rgb image

o  copyPixels32AlphaLowTo24From: anImage
tuned helper to copy pixels from a 32bit argb (alpha in low byte)
to me as a 24bit non-alpha rgb image

o  rgbImageAsFormOn: aDevice
convert am rgb image to a device-form on aDevice.
Return the device-form.

o  rgbImageAsPseudoFormOn: aDevice
return a pseudocolor form from the rgb-picture

** This method must be redefined in concrete classes (subclassResponsibility) **

o  rgbImageAsTrueColorFormOn: aDevice
return a truecolor form from the rgb-picture.

Usage example(s):

'Image [warning]: unimplemented trueColor depth in rgbImageAsTrueColorFormOn: ' errorPrint. self bitsPerPixel errorPrintCR.

copying
o  skipInstvarIndexInDeepCopy: index
a helper for deepCopy; only indices for which this method returns
false are copied in a deep copy.

copying-private
o  postCopy
redefined to also copy the pixels and the colorMap
and clear out any device handles in the copy.

displaying
o  asImage
ST-80 compatibility

o  displayFilledOn: aGC
display the receiver as an opaque image.
This allows Images to be wrapped by a FillingWrapper

o  displayOn: aGCOrStream
draw the receiver in the graphicsContext, aGC.
Smalltalk-80 compatibility

o  displayOn: aGC x: x y: y
draw the receiver in the graphicsContext, aGC.
Smalltalk-80 compatibility

Usage example(s):

     (Image fromScreen:(0@0 corner:100@100)) displayOn:Transcript window graphicsContext

o  displayOn: aGC x: x y: y opaque: opaque
draw the receiver in the graphicsContext, aGC.
Smalltalk-80 compatibility

o  displayOpaqueOn: aGC at: aPoint
draw the receiver in the graphicsContext, aGC.
Smalltalk-80 compatibility

o  displayOpaqueOn: aGC x: x y: y
draw the receiver in the graphicsContext, aGC.
Smalltalk-80 compatibility

o  displayStrokedOn: aGC
display the receiver as an non opaque image.
This allows Images to be wrapped by a StrokingWrapper

dither helpers
o  burkesDitheredMonochromeBits
return the bitmap for a dithered monochrome bitmap from the image.
Works for any source depths / photometric.
TODO: move to separate dither helper class

o  floydSteinbergDitheredDepth8BitsColors: colors
return a floyd-steinberg dithered bitmap from the receiver picture,
which must be a depth-8 image.
This method expects an array of colors to be used for dithering
(which need not be a colorCubes colors).

o  floydSteinbergDitheredDepth8BitsColors: colors map: aMapOrNil
return a floyd-steinberg dithered bitmap from the receiver picture,
which must be a depth-24 image.
This method expects an array of colors to be used for dithering
(which need not be a colorCubes colors).

o  floydSteinbergDitheredDepth8BitsColors: fixColors nRed: nRed nGreen: nGreen nBlue: nBlue
return a floyd-steinberg dithered bitmap from the receiver picture,
which must be a depth-8 image.
This is a special-cased dither method for 8-bit palette images being displayed on
an 8-bit pseudoColor display, AND fixColor dithering is used.
Use the colors in the fixColors array, which must be fixR x fixG x fixB
colors assigned to aDevice, such as the preallocated colors of the
Color class.
By passing the ditherColors as extra array, this method can
also be used to dither an 8bit image into a smaller number of colors,
for example to create dithered Depth4Images from Depth8Images.

o  floydSteinbergDitheredGrayBitsDepth: depth
return the bits for dithering a gray image from the image.
Works for any source depths / photometric,
but possibly slow since each pixel is processed individually.
Redefined by some subclasses for more performance (D8Image/D24Image)

o  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)

o  nearestPaintDepth8BitsColors: fixColors nRed: nRed nGreen: nGreen nBlue: nBlue
return a nearest paint bitmap from the receiver picture,
which must be a depth-8 image.
This is a special-cased dither method for 8-bit palette images being displayed on
an 8-bit pseudoColor display, AND fixColor dithering is used.
Use the colors in the fixColors array, which must be fixR x fixG x fixB
colors assigned to aDevice, such as the preallocated colors of the
Color class.

o  nfloydSteinbergDitheredDepth8BitsColors: colors
return a floyd-steinberg dithered bitmap from the receiver picture,
which must be a depth-8 image.
This method expects an array of colors to be used for dithering
(which need not be a colorCubes colors).

o  orderedDitheredGrayBitsDepth: depth
return the bitmap for a dithered depth-bitmap from the image

o  orderedDitheredGrayBitsWithDitherMatrix: 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)

o  orderedDitheredMonochromeBits
return the bitmap for a dithered monochrome bitmap from the image;
using a default ditherMatrix.

o  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)

o  stevensonArceDitheredMonochromeBits
return the bitmap for a dithered monochrome bitmap from the image.
Works for any source depths / photometric.
TODO: move to separate dither helper class

drawing
o  displayArcOrigin: origin corner: corner from: startAngle angle: angle withColor: aColor
draw part of a circle/ellipse with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window

Usage example(s):

     |cm i|

     cm :=  Array with:Color white with:Color black with:Color red.

     i := Depth8Image extent:300@400 depth:8 palette:cm.
     i displayArcOrigin:100@100 corner:200@200 from:0 angle:90 withColor:Color red.
     i inspect.

o  displayArcOrigin: origin corner: corner from: startAngle angle: angle withValue: aPixelValueOrNil
draw part of a circle/ellipse with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

Usage example(s):

     |cm i|

     cm :=  Array with:Color white with:Color black with:Color red.

     i := Depth8Image extent:300@400 depth:8 palette:cm.
     i displayArcOrigin:100@100 corner:200@200 from:0 angle:90 withColor:Color red.
     i inspect.

o  drawEllipse: aRectangle with: aColorOrPixelValue
draw a circle/ellipse with some pixel value or color.
By using a tempForm, we assure that the same pixel algorithm is used as in a window

o  drawEllipse: aRectangle withColor: aColor
draw a circle/ellipse with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i drawEllipse:(0@0 corner:80@100) withColor:Color red.
     i inspect.

o  drawEllipse: aRectangle withColor: aColor lineWidth: lw
draw a circle/ellipse with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i drawEllipse:(0@0 corner:80@100) withColor:Color red.
     i inspect.

o  drawEllipse: aRectangle withValue: aPixelValueOrNil
draw a circle/ellipse with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i drawEllipse:(0@0 corner:80@100) withColor:Color red.
     i inspect.

o  drawEllipse: aRectangle withValue: aPixelValueOrNil lineWidth: lineWidthOrNil
draw a circle/ellipse with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i drawEllipse:(0@0 corner:80@100) withColor:Color red.
     i inspect.

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i drawEllipse:(0@0 corner:80@100) withColor:Color red lineWidth:4.
     i inspect.

o  drawLineFrom: startPoint to: endPoint with: aColorOrPixelValue
draw a line with some pixel value.
This is in no way tuned, as normally, display-forms are used to draw.
The only use for this is when we have to generate images in a headless webService
(such as the HumanReadableImageGenerator)

Usage example(s):

     |i|

     i := Depth1Image extent:100@100 depth:1 palette:nil.
     i photometric:#blackIs0.
     i drawLineFrom:5@5 to:94@5 withColor:1.
     i drawLineFrom:94@5 to:94@94 withColor:1.
     i drawLineFrom:94@94 to:5@94 withColor:1.
     i drawLineFrom:5@94 to:5@5 withColor:1.
     i drawLineFrom:10@10 to:90@90 withColor:1.
     i drawLineFrom:90@10 to:10@90 withColor:1.
     i inspect.

o  drawLineFrom: startPoint to: endPoint withColor: aColorOrPixelValue
draw a line with some pixel value.
This is in no way tuned, as normally, display-forms are used to draw.
The only use for this is when we have to generate images in a headless webService
(such as the HumanReadableImageGenerator)

Usage example(s):

     |i|

     i := Depth1Image extent:100@100 depth:1 palette:nil.
     i photometric:#blackIs0.
     i drawLineFrom:5@5 to:94@5 withColor:1.
     i drawLineFrom:94@5 to:94@94 withColor:1.
     i drawLineFrom:94@94 to:5@94 withColor:1.
     i drawLineFrom:5@94 to:5@5 withColor:1.
     i drawLineFrom:10@10 to:90@90 withColor:1.
     i drawLineFrom:90@10 to:10@90 withColor:1.
     i inspect.

o  drawLineFrom: p1 to: p2 withColor: aColor lineWidth: lineWidthOrNil
draw a line with some color.
By using a tempForm, we assure that the same pixel algorithm is used as in a window.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

o  drawLineFrom: p1 to: p2 withColor: aColor lineWidth: lineWidthOrNil arrowStyle: arrowStyleOrNil
draw a line with some color.
By using a tempForm, we assure that the same pixel algorithm is used as in a window.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

o  drawLineFrom: startPoint to: endPoint withValue: aPixelValueOrNil
draw a line with some pixel value.
This is in no way tuned, as normally, display-forms are used to draw.
The only use for this is when we have to generate images in a headless webService
(such as the HumanReadableImageGenerator) or in the image editor.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

Usage example(s):

     |i|

     i := Depth1Image extent:100@100 depth:1 palette:nil.
     i photometric:#blackIs0.
     i drawLineFrom:5@5 to:94@5 withColor:1.
     i drawLineFrom:94@5 to:94@94 withColor:1.
     i drawLineFrom:94@94 to:5@94 withColor:1.
     i drawLineFrom:5@94 to:5@5 withColor:1.
     i drawLineFrom:10@10 to:90@90 withColor:1.
     i drawLineFrom:90@10 to:10@90 withColor:1.
     i inspect.

o  drawLineFrom: p1 to: p2 withValue: aPixelValueOrNil lineWidth: lineWidthOrNil
draw a line with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i drawLineFrom:0@0 to:80@100 withColor:Color red.
     i inspect.

o  drawLineFrom: p1 to: p2 withValue: aPixelValueOrNil lineWidth: lineWidthOrNil arrowStyle: arrowStyleOrNil
draw a line with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor).
arrowStyleOrNil is #start, #end or nil

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i drawLineFrom:0@0 to:80@100 withColor:Color red lineWidth:5.
     i inspect.

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i drawLineFrom:0@0 to:80@100 withColor:Color red lineWidth:2 arrowStyle:#start.
     i inspect.

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i drawLineFrom:0@50 to:80@100 withColor:Color red lineWidth:3 arrowStyle:#end.
     i inspect.

o  drawRectangle: aRectangle with: aColorOrPixelValue
draw a rectangle with some pixel value.
By using #atImageAndMask:put: it also works on images with mono masks.

Usage example(s):

     |i|

     i := Depth1Image extent:100@100 depth:1 palette:nil.
     i photometric:#blackIs0.
     i drawRectangle:(10@10 corner:90@90) withColor:1.
     i inspect.

o  drawRectangle: aRectangle withColor: aColor
draw a rectangle with some pixel value.
By using #atImageAndMask:put: it also works on images with mono masks.

Usage example(s):

     |i|

     i := Depth1Image extent:100@100 depth:1 palette:nil.
     i photometric:#blackIs0.
     i drawRectangle:(10@10 corner:90@90) withColor:1.
     i inspect.

o  drawRectangle: aRectangle withValue: aPixelValueOrNil
draw a rectangle with some pixel value.
By using #atImageAndMask:put: it also works on images with mono masks.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

Usage example(s):

     |i|

     i := Depth1Image extent:100@100 depth:1 palette:nil.
     i photometric:#blackIs0.
     i drawRectangle:(10@10 corner:90@90) withColor:1.
     i inspect.

o  fillAntiAliasedArc: origin radius: r from: startAngle angle: angle withColor: aColor colorDictionary: colorDictionary blendStart: blendStart
fill par tof an antialiased circle/ellipse with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window.
Compare the output of the example code at the end to the output from fillArc:radius:from:angle:withColor:

Usage example(s):

        |aaImgArray|

        aaImgArray := Depth8Image extent:200@200 depth:8 antiAliasedPalette:{ Color white . Color black  . Color red . Color blue} bgColor:Color white.
        aaImgArray last fillAntiAliasedArc:105@95 radius:80 from:0 angle:90 withColor:Color red
            colorDictionary:aaImgArray first
            blendStart:aaImgArray second.
        aaImgArray last fillAntiAliasedArc:100@100 radius:80 from:90 angle:270 withColor:Color blue
            colorDictionary:aaImgArray first
            blendStart:aaImgArray second.

        aaImgArray last inspect.

o  fillArc: origin radius: r from: startAngle angle: angle withColor: aColorOrIndex
fill part of a circle/ellipse with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window

Usage example(s):

     |i|

     i := Depth8Image extent:200@200 depth:8 palette:{ Color white . Color black  . Color red . Color blue}.
     i fillArc:105@95 radius:80 from:0 angle:90 withColor:Color red.
     i fillArc:100@100 radius:80 from:90 angle:270 withColor:Color blue.
     i inspect.

o  fillEllipse: aRectangle with: aColorOrPixelValue
fill a circle/ellipse with some pixel value or color.
By using a tempForm, we assure that the same pixel algorithm is used as in a window

o  fillEllipse: aRectangle withColor: aColor
fill a circle/ellipse with some color.
By using a tempForm, we assure that the same pixel algorithm is used as in a window

Usage example(s):

     |i|

     i := Depth8Image extent:100@100 depth:8 palette:{ Color white . Color black  . Color red }.
     i fillEllipse:(0@0 corner:80@100) withColor:Color red.
     i inspect.

o  fillEllipse: aRectangle withValue: aPixelValueOrNil
fill a circle/ellipse with some pixel value.
By using a tempForm, we assure that the same pixel algorithm is used as in a window.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

Usage example(s):

     |i|

     i := Depth8Image extent:300@400 depth:8 palette:{ Color white . Color black  . Color red }.
     i fillEllipse:(0@0 corner:80@100) withColor:Color red.
     i inspect.

o  fillRectangle: aRectangle with: aColorOrPixelValue
fill a rectangular area with some or pixel value.

o  fillRectangle: aRectangle withColor: aColor
fill a rectangular area with some color.

o  fillRectangle: aRectangle withValue: aPixelValueOrNil
fill a rectangular area with some pixel value.
May be redefined in concrete subclasses for more performance, if req'd.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

o  fillRectangleX: x y: y width: w height: h with: aColorOrPixelValue
fill a rectangular area with a aColor

o  fillRectangleX: x y: y width: w height: h withColor: aColor
fill a rectangular area with a aColor

o  fillRectangleX: x y: y width: w height: h withValue: aPixelValueOrNil
fill a rectangular area with some pixel value.
May be redefined in concrete subclasses for more performance, if req'd.
If aPixelValueOrNil is nil, the mask pixel will be set to 0 (transparent),
otherwise to 1. (used by the bitmap editor)

o  floodFillAt: aPoint with: aColorOrPixelValue
fill a area with aColor like a flood up to surrounded pixels having different colors.
By using #atImageAndMask:put: it also works on images with mono masks.
Currently returns a collection of all pixels which have been modified (needed by imageEditor?),
but that should be changed to avoid huge massdata creation (instead, call a block for each)

o  floodFillAt: aPoint withColor: aColor
fill a area with aColor like a flood up to surrounded pixels having different colors.
By using #atImageAndMask:put: it also works on images with mono masks.
Currently returns a collection of all pixels which have been modified (needed by imageEditor?),
but that should be changed to avoid huge massdata creation (instead, call a block for each)

o  floodFillAt: aPoint withValue: aPixelValueOrNil
fill a area with aColor like a flood up to surrounded pixels having different colors.
By using #atImageAndMask:put: it also works on images with mono masks.
Currently returns a collection of all pixels which have been modified (needed by imageEditor?),
but that should be changed to avoid huge massdata creation (instead, call a block for each)

o  floodFillAt: aPoint withValue: aPixelValueOrNil maxDeviationInLight: maxLightError maxDeviationInHue: maxHueError
fill an area with aColor like a flood up to surrounded pixels having different colors.
If maxLightError/maxLueError are zero, the flood fills only pixels with the same value as the pixel at aPoint;
otherwise, a slight error (fraction) in light/hue is allowd, and pixels with a nearby color are also filled.
By using #atImageAndMask:put: it also works on images with mono masks.
Currently returns a collection of all pixels which have been modified (needed by imageEditor?),
but that should be changed to avoid huge massdata creation (instead, call a block for each)

Usage example(s):

allDetectedPixelCoordinates := mask floodFillAt: aPoint withColor: Color white.

o  rectangle: aRectangle withColor: aColor
draw a rectangle with some pixel value.
By using #atImageAndMask:put: it also works on images with mono masks.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

encoding & decoding
o  skippedInJSONEncoding
( an extension from the stx:goodies/communication package )
return the names of inst-slots which are to be skipped when generating a jsonEncoding;
(to skip the ones with default or irrelevant values.)

enumerating
o  atY: y from: x1 to: x2 do: aBlock
perform aBlock for each pixel from x1 to x2 in row y.
The block is passed the color at each pixel.
The code here provides a generic and slow implementation, and
should be redefined in concrete subclasses, to avoid some processing
when going from pixel to pixel (i.e. the byte-index and mask computations
and also the color allocation).

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  colorsAtX: x from: y1 to: y2 do: aBlock
perform aBlock for each pixel from y1 to y2 in col x.
The block is passed the color at each pixel.
The code here provides a generic and slow implementation, and
should be redefined in concrete subclasses, to avoid some processing
when going from pixel to pixel (i.e. the byte-index and mask computations
and also the color allocation).

o  colorsAtY: y from: x1 to: x2 do: aBlock
perform aBlock for each pixel from x1 to x2 in row y.
The block is passed the color at each pixel.
The code here provides a generic and slow implementation, and
should be redefined in concrete subclasses, to avoid some processing
when going from pixel to pixel (i.e. the byte-index and mask computations
and also the color allocation).

o  colorsFromX: xStart y: yStart toX: xEnd y: yEnd do: aBlock
perform aBlock for each color in a rectangular area of the image.
Notice that x and y coordinates start at 0@0 for the upper left corner.
The block is passed the x and y coordinates and pixelValue at each pixel.
The code here provides a generic and slow implementation, and
should be redefined in concrete subclasses, to avoid some processing
when going from pixel to pixel (i.e. the byte-index and mask computations,
and especially, the color allocations).

o  rgbValuesAtY: y from: x1 to: x2 do: aBlock
perform aBlock for each rgbValue from x1 to x2 in row y.
rgbValues are of the form rrggbb (i.e. red is in the high byte).

Notice the difference between rgbValue and pixelValue: rgbValues are always
the rgb bytes; pixelvalues depend on the photometric interpretation, and may be
indices into a colormap or be non-byte-sized rgb values.

Notice that x and y coordinates start at 0@0 for the upper left corner.
The block is passed the x coordinate and the pixelValue at each pixel.
(see also Image>>atY:from:to:do:).
The code here provides a generic and slow implementation, and
should be redefined in concrete subclasses, to avoid some processing
when going from pixel to pixel (i.e. the byte-index and mask computations).

o  rgbValuesFromX: xStart y: yStart toX: xEnd y: yEnd do: aBlock
perform aBlock for each rgbValue in a rectangular area of the image.
rgbValues are of the form rrggbb (i.e. the redByte is in the high byte).

Notice the difference between rgbValue and pixelValue: rgbValues are always
the rgb bytes; pixelvalues depend on the photometric interpretation, and may be
indices into a colormap or be non-byte-sized rgb values.

Notice that x and y coordinates start at 0@0 for the upper left corner.
The block is passed the x and y coordinates and pixelValue at each pixel.
The code here provides a generic and slow implementation, and
should be redefined in concrete subclasses, to avoid some processing
when going from pixel to pixel (i.e. the byte-index and mask computations).

o  valueAtY: y from: x1 to: x2 do: aBlock
perform aBlock for each pixelValue from x1 to x2 in row y.
Obsolete - remains for backward compatibility.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  valuesAtY: y from: x1 to: x2 do: aBlock
WARNING: this enumerates pixel values which need photometric interpretation
Do not confuse with #rgbValuesAtY:from:to:do:

Perform aBlock for each pixelValue from x1 to x2 in row y.

Notice the difference between rgbValue and pixelValue: rgbValues are always
the rgb bytes; pixelvalues depend on the photometric interpretation, and may be
indices into a colormap or be non-byte-sized rgb values.

Notice that x and y coordinates start at 0@0 for the upper left corner.
The block is passed the x coordinate and the pixelValue at each pixel.
(see also Image>>atY:from:to:do:).
The code here provides a generic and slow implementation, and
should be redefined in concrete subclasses, to avoid some processing
when going from pixel to pixel (i.e. the byte-index and mask computations).

o  valuesFromX: xStart y: yStart toX: xEnd y: yEnd do: aBlock
WARNING: this enumerates pixel values which need photometric interpretation
Do not confuse with #rgbValuesAtY:from:to:do:

Perform aBlock for each pixelValue in a rectangular area of the image.

Notice the difference between rgbValue and pixelValue: rgbValues are always
the rgb bytes; pixelvalues depend on the photometric interpretation, and may be
indices into a colormap or be non-byte-sized rgb values.

Notice that x and y coordinates start at 0@0 for the upper left corner.
The block is passed the x and y coordinates and pixelValue at each pixel.
The code here provides a generic and slow implementation, and
should be redefined in concrete subclasses, to avoid some processing
when going from pixel to pixel (i.e. the byte-index and mask computations).

finalization
o  finalizationLobby
answer the registry used for finalization.
Images have their own Registry

o  finalize
some Image has been collected - nothing to do.

The only reason we register Images is, that we can release
their device resources when a GraphicsDevice is closed.

(#releaseResourcesOnDevice: at class side).

image manipulations
o  applyPixelValuesTo: pixelFunctionBlock in: aRectangle into: newImage
helper for withPixelFunctionAppliedToValues:
enumerate pixelValues and evaluate the block for each.
Could be redefined by subclasses for better performance.

o  applyPixelValuesTo: pixelFunctionBlock into: newImage
helper for withPixelFunctionAppliedToValues:
enumerate pixelValues and evaluate the block for each.

o  blendWith: aColor
return a new image which is blended with some color.
The receiver must be a palette image (currently).
CAVEAT: this only works with palette images (i.e. not for rgb or greyScale).
CAVEAT: Need an argument, which specifies by how much it should be lighter.

Usage example(s):

     (Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') blendWith:Color red) inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') blendWith:Color white) inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') blendWith:Color black) inspect

o  colorMapProcessing: aBlock
a helper for all kinds of colormap manipulations.
The argument, aBlock is called for every colormap entry,
and the returned value will replace the original entry in the map.
For non-palette images, aBlock is called for every pixel value
(instead of colormap values), and the returned color is stored back
into the image).
See examples in Image>>copyWithColorMapProcessing:

o  copyWithColorMapProcessing: aBlock
a helper to create & return new images based on the receiver with
some colorMap processing. The receiver is copied, and the copied image's
colormap is modified by replacing entries with the result of the processing block,
which is called with the original color values.
The block is supposed to return a color.
CAVEAT: this only works with palette images (i.e. not for rgb or greyScale)

Usage example(s):

     leave red component only:

     (Image fromFile:'goodies/bitmaps/gifImages/claus.gif')
        copyWithColorMapProcessing:[:clr | Color red:(clr red) green:0 blue:0]

Usage example(s):

     make it reddish:

     (Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif')
        copyWithColorMapProcessing:[:clr | Color red:((clr red * 2) min:100) green:clr green blue:clr blue]

o  createMask
create a mask filled with ones (i.e. all pixels opaque)

o  createMaskForPixelValue: pixelValue
create or modify the mask to be off wherever the pixelValue appears.
If there is already a mask, pixels which are already masked remain so.
This is a helper for image readers which use a pixel index as mask,
instead of a separate mask plane.

This is a slow fallback, if it turns out to be timing relevant,
redefine in concrete image classes (especially Depth8Image)

o  darkened
return a new image which is slightly darker than the receiver.
The receiver must be a palette image (currently).
CAVEAT: this only works with palette images (i.e. not for rgb or greyScale).
CAVEAT: Need an argument, which specifies by how much it should be darker.

Usage example(s):

     (Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') inspect
     (Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') darkened inspect

o  easyRotateBitsInto: destinationImage angle: degrees
helper for rotation - does the actual pixel shuffling.
by degrees clockwise. Here, only 90, 180 and 270 degrees
are implemented. Hard angles are done in #hardRotate:.
The code here is depth-independent (but not too fast);
can be redefined in subclasses for more performance

o  flipHorizontal
destructively inplace horizontal flip

Usage example(s):

     (Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') flipHorizontal inspect

o  flipVertical
inplace vertical flip

Usage example(s):

     (Image fromFile:'goodies/bitmaps/gifImages/garfield.gif') flipVertical inspect

o  hardAntiAliasedMagnifiedBy: scalePoint
return a new image magnified and antiAliased by scalePoint, aPoint.
This converts into a depth24Image before doing the antiAlias-magnify.
It is definitely slower than the non antiAliasing/integral magnification methods.

Usage example(s):

     |i i1 i2|
     
     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     Transcript showCR:(
        Time millisecondsToRun:[
            i1 := i hardMagnifiedBy:3
        ]
     ).    
     i1 inspect.

     Transcript showCR:(
        Time millisecondsToRun:[
            i2 := i hardAntiAliasedMagnifiedBy:3
        ]
     ).    
     i2 inspect.

o  hardMagnifiedBy: scaleArg
return a new image magnified by scalePoint, aPoint.
This is the general magnification method, handling non-integral values.
It is slower than the integral magnification method.

Notice: this is a naive algorithm, which simply samples the pixel value
at the corresponding original pixel's point, without taking neighbors into
consideration (i.e. it does not compute an average of those pixels).
As a consequence, this will generate bad shrunk images when the original contains
sharp lines.
Also notice: this might need inline C code forperformance

Usage example(s):

     |i|
     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     Time millisecondsToRun:[
         i := i hardMagnifiedBy:0.5@0.5
     ].
     i

o  hardMagnifiedBy: scaleArg smooth: smoothBoolean
return a new image magnified by scalePoint, aPoint.
This is the general magnification method, handling non-integral values.
It is slower than the integral magnification method.

If smoothBoolean is true, an improved algorithm is used,
which averages the pixels if shrinking or interpolates if expanding
(i.e. it smoothens when resampling) and this should generate nicer shrunk
images when the original contains sharp lines.

If it is false, a naive subsampling is performed, which is much faster,
but produces ugly magnifications (and especially: ugly shrunk versions)

o  hardRotated: degrees
return a new image from the old one, by rotating the image
degrees clockwise (around its center).
Warning: the returned image will be larger than the original image.

o  hardSmoothingMagnifiedBy: scaleArg
return a new image magnified by scalePoint, aPoint.
This is the general magnification method, handling non-integral values.
It is slower than the integral magnification method,
and slower than the old hardMagnifiedBy: method.

Notice: this is an improved algorithm, which averages the pixels if shrinking
or interpolates if expanding.
As a consequence, this should generate nicer shrunk images when the original contains sharp lines.

Usage example(s):

     |i|
     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i := i asGrayImageDepth:8.
     i := Depth24Image fromImage:i.
     
     Time millisecondsToRun:[
         i := i hardSmoothingMagnifiedBy:0.2 
     ].
     i inspect

Usage example(s):

     |i|
     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i := Depth24Image fromImage:i.

     Time millisecondsToRun:[
         i := i hardSmoothingMagnifiedBy:0.3 
     ].
     i inspect

Usage example(s):

     |i|
     i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i colorMap:((i colorMap asArray) , { Color red . Color green . Color blue}).
     i fillRectangle:(0@0 corner:50@50) withColor:Color red.
     i fillRectangle:(50@0 corner:100@50) withColor:Color green.
     i fillRectangle:(100@0 corner:150@50) withColor:Color blue.
     i := Depth32Image fromImage:i.
     'i := Depth24Image fromImage:i.'.
     Time millisecondsToRun:[
         i := i hardSmoothingMagnifiedBy:0.3 
     ].
     i inspect

o  lightened
return a new image which is slightly brighter than the receiver.
The receiver must be a palette image (currently).
CAVEAT: this only works with palette images (i.e. not for rgb or greyScale).
CAVEAT: Need an argument, which specifies by how much it should be lighter.

Usage example(s):

     (Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') inspect
     (Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') lightened inspect
     (Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') darkened inspect
     (Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') darkened darkened inspect

Usage example(s):

     |i|
     i := Image fromFile:'~/Documents/eads/airbus/logos/Airbus_logo_2017_512px.png'.
     i lightened

o  magnifiedBy: scale
return a new image magnified by scalePoint, aPoint.
If non-integral magnify is asked for, pass the work on to 'hardMagnifyBy:'
while simple (integral) magnifications are handled here.

Usage example(s):

     (Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif') inspect.
     ((Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif') magnifiedBy:1@2) inspect.

o  magnifiedBy: scale smooth: smooth
return a new image magnified by scalePoint, aPoint.
If non-integral magnify is asked for, pass the work on to 'hardMagnifyBy:'
while simple (integral) magnifications are handled here.

Usage example(s):

     ((Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') 
        magnifiedBy:1@2 smooth:false)

o  magnifiedPreservingRatioTo: anExtent
return a new image magnified to fit into anExtent,
preserving the receiver's width/height ratio.
(i.e. not distorting the image).
See also #magnifiedTo: and #magnifiedBy:

Usage example(s):

     ((Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') magnifiedPreservingRatioTo:100@100)

    in contrast to:

     ((Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') magnifiedTo:100@100)

o  magnifiedPreservingRatioTo: anExtent smooth: smoothBoolean
return a new image magnified to fit into anExtent,
preserving the receiver's width/height ratio.
(i.e. not distorting the image).
See also #magnifiedTo: and #magnifiedBy:

Usage example(s):

     ((Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') magnifiedPreservingRatioTo:100@100)

    in contrast to:

     ((Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') magnifiedTo:100@100)

o  magnifiedTo: anExtent
return a new image magnified to have the size specified by extent.
This may distort the image if the argument's ratio is not the image's ratio.
See also #magnifiedPreservingRatioTo: and #magnifiedBy:

Usage example(s):

     ((Image fromFile:'goodies/bitmaps/gifImages/garfield.gif') magnifiedTo:100@100)

    in contrast to:

     ((Image fromFile:'goodies/bitmaps/gifImages/garfield.gif') magnifiedPreservingRatioTo:100@100)

o  magnifiedTo: anExtent smooth: aBoolean
return a new image magnified to have the size specified by extent.
This may distort the image if the argument's ratio is not the image's ratio.
See also #magnifiedPreservingRatioTo: and #magnifiedBy:

Usage example(s):

     (Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') magnifiedTo:100@100 smooth:true

    in contrast to:

     (Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') magnifiedTo:100@100 smooth:false

    and:
     ((Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') magnifiedPreservingRatioTo:100@100)
    and:
     ((Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') magnifiedPreservingRatioTo:100@100 smooth:true)

o  mixed: amount with: aColor
return a new image which is blended with some color;
amount determines how much of the blending color is applied (0..)
where 0 means: blending color pure.
The receiver must be a palette image (currently).
CAVEAT: this only works with palette images (i.e. not for rgb or greyScale).
CAVEAT: Need an argument, which specifies by how much it should be lighter.

Usage example(s):

     (Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') mixed:0.0 with:Color red) inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') mixed:0.1 with:Color red) inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') mixed:0.25 with:Color red) inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') mixed:0.5 with:Color red) inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') mixed:1 with:Color red) inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') mixed:2 with:Color red) inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') mixed:10 with:Color red) inspect
     ((Smalltalk bitmapFromFileNamed:'gifImages/claus.gif' inPackage:'stx:goodies') mixed:20 with:Color red) inspect

o  negative
return a new image which is a negative of the receiver.
The receiver must be a palette image (currently).

Usage example(s):

     (Image fromFile:'goodies/bitmaps/gifImages/claus.gif') inspect
     (Image fromFile:'goodies/bitmaps/gifImages/claus.gif') negative inspect

o  rotated: degrees
return a new image from the old one, by rotating the image degrees clockwise.
Notice that the resulting image has a different extent.
If rotation is heavily used, the workHorse methods
(#easyRotateBitsInto:angle: and #hardRotated:) may
be redefined in concrete image subclasses.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     i inspect.
     (i rotated:45) inspect.
     (i rotated:90) inspect.
     (i rotated:180) inspect.
     (i rotated:270) inspect.

Usage example(s):

     |i|

     i := Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif'.
     i := Depth24Image fromImage:i.
     i inspect.
     (i rotated:45) inspect.
     (i rotated:90) inspect.
     (i rotated:180) inspect.
     (i rotated:270) inspect.

Usage example(s):

     |i|

     i := Smalltalk imageFromFileNamed:'../../goodies/bitmaps/xpmBitmaps/misc_icons/BOOK.xpm' inPackage:'stx:goodies'.
     i inspect.
     (i rotated:90) inspect.
     (i rotated:180) inspect.
     (i rotated:270) inspect.

o  slightlyDarkened
return a new image which is slightly darker than the receiver.
The receiver must be a palette image (currently).
CAVEAT: this only works with palette images (i.e. not for rgb or greyScale).
CAVEAT: Need an argument, which specifies by how much it should be lighter.

o  slightlyLightened
return a new image which is slightly brighter than the receiver.
The receiver must be a palette image (currently).
CAVEAT: this only works with palette images (i.e. not for rgb or greyScale).
CAVEAT: Need an argument, which specifies by how much it should be lighter.

o  smoothingMagnifiedBy: scale
return a new image magnified by scalePoint, aPoint.
If non-integral magnify is asked for, pass the work on to 'hardMagnifyBy:'
while simple (integral) magnifications are handled here.

o  smoothingMagnifiedPreservingRatioTo: anExtent
return a new image magnified to fit into anExtent,
preserving the receiver's width/height ratio.
(i.e. not distorting the image).
See also #magnifiedTo: and #magnifiedBy:

o  threeDProjected: fraction1 and: fraction2
return a 3D-projected version.
Not really 3D, but good enough to create screenshots for webpages...
TODO: kick out this q&d hack, and write something real...

Usage example(s):

     |i|

     i := Smalltalk imageFromFileNamed:'../../goodies/bitmaps/gifImages/garfield.gif' inPackage:'stx:goodies'.
     i := Depth24Image fromImage:i.
     (i threeDProjected:0.1 and:0.3) inspect.
     (i threeDProjected:0.1 and:0.1) inspect.

Usage example(s):

     |i|

     Transcript topView raiseDeiconified.
     i := Image fromView:Transcript topView.
     i := Depth24Image fromImage:i.
     (i threeDProjected:0.1 and:0.2) inspect.

o  withColorResolutionReducedBy: numBits
return a new image with the same picture as the receiver,
but reduced colorResolution.
That is, the lower numBits are cleared in the r/g/b color components.
If anything fails, return nil.

o  withPixelFunctionApplied: pixelFunctionBlock
return a new image from the old one,
by applying a pixel processor on the pixel colors.

Notice: this method is relatively slow - either apply pixel values
(#withPixelFunctionAppliedToPixels:) or redefine this method in
a concrete subclass.
(read `Beyond photography, by Gerard J. Holzmann;
ISBM 0-13-074410-7)
See blurred / oilPainted as examples ...)

o  withPixelFunctionApplied: pixelFunctionBlock in: aRectangle
return a new image from the old one,
by applying a pixel processor on the pixel colors.

Notice: this method is relatively slow - either apply pixel values
(#withPixelFunctionAppliedToPixels:) or redefine this method in
a concrete subclass.
(read `Beyond photography, by Gerard J. Holzmann;
ISBM 0-13-074410-7)
See blurred / oilPainted as examples ...)

o  withPixelFunctionAppliedToPixels: pixelFunctionBlock
return a new image from the old one, by applying a pixel processor
on the pixel values.
(read `Beyond photography, by Gerard J. Holzmann;
ISBM 0-13-074410-7)
See blurred / oilPainted as examples ...)

o  withPixelFunctionAppliedToPixels: pixelFunctionBlock in: aRectangle
return a new image from the old one, by applying a pixel processor
on the pixel values.
(read `Beyond photography, by Gerard J. Holzmann;
ISBM 0-13-074410-7)
See blurred / oilPainted as examples ...)

initialization
o  createPixelStore
instantiate the underlying pixel storage (a byteArray)

o  initialize
(comment from inherited method)
just to ignore initialize to objects which do not need it

inspecting
o  inspector2TabDisplayObject
( an extension from the stx:libtool package )
we do not want this for images

o  inspector2TabImage
( an extension from the stx:libtool package )
an extra tab showing the image;
Q: is this needed? (the displayObject tab already shows this)

o  inspector2TabImageCreatorClass
( an extension from the stx:libtool package )
ToolbarIconLibrary systemBrowserIcon inspect

o  inspectorExtraAttributes
( an extension from the stx:libtool package )
extra (pseudo instvar) entries to be shown in an inspector.

o  inspectorExtraMenuOperations
( an extension from the stx:libtool package )
extra operation-menu entries to be shown in an inspector.
Answers a collection of pairs containing aString and action aBlock.
aString is the label of the menu item.
aBlock is evaluated when the menu item is selected.

instance release
o  close
release device resources; destroy any device-resources

o  release
release device resources

o  releaseFromDevice
release device resources

o  restored
flush device specifics after a snapin or binary restore.
Also to flush any cached device forms, after drawing into the pixel store

misc ui support
o  inspectorClass
( an extension from the stx:libtool package )
redefined to launch an ImageInspector
(instead of the default InspectorView).

obsolete
o  applyPixelValuesTo: pixelFunctionBlock into: newImage in: aRectangle
helper for withPixelFunctionAppliedToValues:
enumerate pixelValues and evaluate the block for each.
To be redefined by subclasses for better performance.

o  magnifyBy: scale
obsolete: has been renamed to magnifiedBy: for ST-80 compatibility
and name consistency ...

** This is an obsolete interface - do not use it (it may vanish in future versions) **

pixel copying
o  bitBltFrom: anImage function: function x: srcX y: srcY toX: dstX y: dstY width: w height: h
operates on pixel values.
Any mask is left unchanged.
Function can be
#and, #or and #xor
#min, #max
#over (copy if not zero)

WARNING:
This is a q@d hack to support the minimum needed for the QRCode generator.

This implementation is a very very slow fallback general algorithm
(the loop over the source pixels is very slow).
If this method is used heavily, you may want to redefine it in
concrete subclasses for the common case of copying from an Image
with the same depth & palette.
If you do heavy image processing, specialized versions are req'd
for other cases, rewriting the inner loops as inline C-code.

o  copyFrom: anImage x: srcX y: srcY toX: dstX y: dstY width: w height: h
replace a rectangular area by pixels from another image.
The source's colors must be present in the destination's
colorMap - otherwise, an error will be reported.
Any mask is copied from the source.

WARNING:
This implementation is a very slow fallback general algorithm
(the loop over the source pixels is very slow).
If this method is used heavily, you may want to redefine it in
concrete subclasses for the common case of of copying from an Image
with the same depth & palette.
If you do heavy image processing, specialized versions are even req'd
for other cases, rewriting the inner loops as inline C-code.

Usage example(s):

     |i1 i8 i4|

     i8 := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i8 inspect.
     i1 := Image fromFile:'../../libtool/bitmaps/SBrowser.xbm'.
     i1 inspect.

     i4 := Depth4Image fromImage:i8.
     i4 copyFrom:i1 x:0 y:0 toX:20 y:20 width:20 height:20.
     i4 inspect.

o  copyFrom: anImage x: srcX y: srcY toX: dstX y: dstY width: w height: h masked: maskedCopy
replace a rectangular area by pixels from another image.
The sources colors must be present in the destinations
colorMap - otherwise, an error will be reported.

WARNING:
This implementation is a very slow fallback general algorithm
(the loop over the source pixels is very slow).
If this method is used heavily, you may want to redefine it in
concrete subclasses for the common case of of copying from an Image
with the same depth & palette.
If you do heavy image processing, specialized versions are even req'd
for other cases, rewriting the inner loops as inline C-code.

Usage example(s):

     |i1 i8 i4|

     i8 := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     i8 inspect.
     i1 := Image fromFile:'../../goodies/bitmaps/xbmBitmaps/TicTacToe.xbm'.
     i1 inspect.

     i4 := Depth4Image fromImage:i8.
     i4 copyFrom:i1 x:0 y:0 toX:20 y:20 width:20 height:20.
     i4 inspect.

o  copyMaskedFrom: anImage x: srcX y: srcY toX: dstX y: dstY width: w height: h
replace a rectangular area by pixels from another image.
The sources colors must be present in the destinations
colorMap - otherwise, an error will be reported.
Only unmasked pixels are copied from the source.

WARNING:
This implementation is a very slow fallback general algorithm
(the loop over the source pixels is very slow).
If this method is used heavily, you may want to redefine it in
concrete subclasses for the common case of of copying from an Image
with the same depth & palette.
If you do heavy image processing, specialized versions are even req'd
for other cases, rewriting the inner loops as inline C-code.

o  subImageIn: aRectangle
create and return a new image consisting of a subArea of myself

Usage example(s):

     |i|

     i := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     i inspect.
     (i subImageIn:(300@160 corner:340@200)) inspect

Usage example(s):

     |i|

     i := Image fromFile:'/Volumes/tmp/fillimage.ok.png'.
     i inspect.
     (i subImageIn:(0@0 corner:i width@i height)) inspect

pixel functions
o  computeBitsFromPixelFunction
compute the bits from the pixelfunction

o  pixelFunction

o  pixelFunction: aTwoArgFunction
set the pixel function. This is used to define a functional image,
where pixel values are computed via a function instead of coming
from a bits array (although a pixel array could also be seen as
a pixel function).
The pixelFunction will map (x E [0 .. width]) x (y E [0 .. height]) -> pixel

Usage example(s):

     |i|
     i := Depth1Image extent:256@256.
     i pixelFunction:[:x :y | ((x // 16) bitXor:(y // 16)) odd asInteger].
     i inspect.

Usage example(s):

     |i|
     i := Depth8Image extent:256@256.
     i photometric:#blackIs0.
     i pixelFunction:[:x :y | x  ].
     i inspect.

o  pixelFunction: aTwoArgFunction inX: xInterval y: yInterval
set the pixel function and a viewport.
This is used to define a functional image,
where pixel values are computed via a function instead of coming
from a bits array.
The pixelFunction will map (x E xInterval) x (y E yInterval) -> pixel

Usage example(s):

     |i|
     i := Depth8Image extent:256@256.
     i photometric:#blackIs0.
     i pixelFunction:[:x :y | ((x@y) r * 255) truncated min:255] inX:(-1 to:1) y:(-1 to:1).
     i inspect.

printing & storing
o  storeOn: aStream
append a printed representation of the receiver to aStream,
from which a copy of it can be reconstructed.

private
o  bestSupportedImageFormatFor: aDevice
scan through the image formats as supported by aDevice,
and return the best to use when the receiver is to be represented
on it. The best format is the one with the same number or more bits per
pixel. Here, the smallest format found which can represent enough pixels is taken.

o  colormapFromImage: anImage
setup the receiver's colormap from another image.
Color precision may be lost, if conversion is from a higher depth
image. This does not convert any pixel values; it is non-public helper
for fromImage:/fromSubImake:

o  colormapFromImage: anImage photometric: photometricOrNil
setup the receiver's colormap from another image.
Color precision may be lost, if conversion is from a higher depth
image. This does not convert any pixel values; it is non-public helper
for fromImage:/fromSubImake:

o  fromDeviceForm: aForm maskForm: aMaskFormOrNil

o  grayByteMapForRange: range
return a collection to map from pixelValues to greyLevels
in the range 0..range.
Range must be < 256 (for elements to fit into a ByteArray).
The values are rounded towards the nearest pixel.

Usage example(s):

     Depth8Image new grayByteMapForRange:256

     Depth8Image new grayByteMapForRange:64
     Depth4Image new grayByteMapForRange:64

     Depth4Image new grayByteMapForRange:1

o  grayMapForRange: range
return a collection to map from pixelValues to greyLevels
in the range 0..range. The brightness values are not rounded.

Usage example(s):

     Depth8Image new grayMapForRange:64
     Depth4Image new grayMapForRange:64

     Depth16Image new grayMapForRange:1
     Depth4Image new grayMapForRange:1
     Depth2Image new grayMapForRange:1

o  greyByteMapForRange: range
marked as obsolete by exept MBP at 20-09-2021

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  greyMapForRange: range
marked as obsolete by exept MBP at 20-09-2021

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  magnifyRowFrom: srcBytes offset: srcStart into: dstBytes offset: dstStart factor: mX
magnify a single pixel row - can only magnify by integer factors,
can only magnify 1,2,4,8 and 24 bit-per-pixel images. But this is done fast.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  makeDeviceGrayPixmapOn: aDevice depth: depth fromArray: bits
given the bits of a grey/color bitmap, 8-bit padded and
pixels interpreted as greyValues, 0 is black,
create a device form for it

o  makeDeviceMonochromeBitmapOn: aDevice fromArray: monoBits
given the bits of a monochrome bitmap, 8-bit padded and
0-bits as black, create a device form for it

o  makeDevicePixmapOn: aDevice depth: depth fromArray: bits
given the bits of a grey/color bitmap, 8-bit padded and
pixels interpreted as in the devices colormap,
create a device form for it

o  repairPhotometric
kludge: repair a 'should not happen' situation...

queries
o  alphaBitsOf: pixel
if the receiver is an rgb-image:
return the alpha component of a pixelValue as integer 0..maxAlphaValue.
MaxAlphaValue is of course the largest integer representable by the number
of alpha bits i.e. (1 bitShift:bitsAlpha)-1.
This has to be redefined by subclasses.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  alphaMaskForPixelValue
return the mask used with translation from pixelValues to alphaBits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  alphaShiftForPixelValue
return the shift amount used with translation from pixelValues to alphaBits.
That is the number of bits to shift the alpha value into the pixel value.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  ascentOn: aGC
I will not draw myself above the baseline

o  averageColor
return the average color of the image.
This usually only makes sense for textures and patterns
(i.e. to compute shadow & light colors for viewBackgrounds).
Notice that for the above purpose, it is usually ok to process
a subImage - i.e. use Image>>averageColorIn: on a smaller rectangle

o  averageColorIn: aRectangle
return the image's average color in an area.
The implementation below is slow - so you may want to
create tuned versions for DepthXImage if you plan to do
heavy image processing ...
(also, creating tuned versions of the enumeration messages helps a lot)

o  bitsPerPixel
return the number of bits per pixel

o  bitsPerRow
return the number of bits in one scanline of the image

o  blackComponentOfCMYK: pixel
if the receiver is a cmyk-image:
return the black component scaled to a percentage (0 .. 100) of a pixelValue.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  blueBitsOf: pixel
if the receiver is an rgb-image:
return the blue bits of a pixelValue as integer 0..maxBlueValue.
MaxGreenValue is of course the largest integer representable by the number
of blue bits i.e. (1 bitShift:bitsBlue)-1.
This has to be redefined by subclasses.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  blueComponentOf: pixel
if the receiver is an rgb-image:
return the blue component scaled to a percentage (0 .. 100) of a pixelValue.
This has to be redefined by subclasses.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  blueMaskForPixelValue
return the mask used with translation from pixelValues to blueBits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  blueShiftForPixelValue
return the shift amount used with translation from pixelValues to blueBits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  bounds
return my bounds (added to make images usable as VisualComponents)

o  brightness
return the (average) brightness of the image as number in 0..1.
This usually only makes sense for textures and patterns
(i.e. to compute shadow & light colors for viewBackgrounds).
Notice that for the above purpose, only a subimage is inspected here

o  bytesPerRow
return the number of bytes in one scanline of the image

o  bytesPerRowPaddedTo: padding
return the number of bytes in one scanline of the image,
if scanlines are to be padded to padding-bits.

o  center
for compatibility with GC protocol - return the centerPoint

o  chromaBlueOfYCbCr: pixel
if the receiver is an YCbCr-image:
return the blue-chroma (Cb) component, scaled to (0 .. 1)

** This method must be redefined in concrete classes (subclassResponsibility) **

o  chromaRedOfYCbCr: pixel
if the receiver is an YCbCr-image:
return the red-chroma (Cr) component, scaled to (0 .. 1)

** This method must be redefined in concrete classes (subclassResponsibility) **

o  colorFromValue: pixelValue
given a pixel value, return the corresponding color.
Pixel values start with 0.
The implementation below is generic and slow
- this method is typically redefined in subclasses.

o  cyanComponentOfCMY: pixel
if the receiver is a cmy-image:
return the cyan component scaled to a percentage (0 .. 100) of a pixelValue.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  cyanComponentOfCMYK: pixel
if the receiver is a cmyk-image:
return the cyan component scaled to a percentage (0 .. 100) of a pixelValue.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  greenBitsOf: pixel
if the receiver is an rgb-image:
return the green bits of a pixelValue as integer 0..maxGreenValue.
MaxGreenValue is of course the largest integer representable by the number
of green bits i.e. (1 bitShift:bitsGreen)-1.
This has to be redefined by subclasses.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  greenComponentOf: pixel
if the receiver is an rgb-image:
return the green component scaled to a percentage (0..100) of a pixelValue.
This has to be redefined by subclasses.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  greenMaskForPixelValue
return the mask used with translation from pixelValues to greenBits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  greenShiftForPixelValue
return the shift amount used with translation from pixelValues to greenBits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  heightOn: aGC
return my height, if displayed on aGC;
since my height is independent of the device (the number of pixels),
return the pixel-height

o  isDithered
for compatibility with color protocol

o  isGrayscaleImage

o  isImage
return true, if the receiver is some kind of image;
true is returned here - the method is redefined from Object.

o  isImageOrForm
return true, if the receiver is some kind of image or form;
true is returned here - the method is redefined from Object.

o  isMask

o  lumaOfYCbCr: pixel
if the receiver is an YCbCr-image:
return the luma (Y) component, scaled to (0 .. 1)

** This method must be redefined in concrete classes (subclassResponsibility) **

o  magentaComponentOfCMY: pixel
if the receiver is a cmy-image:
return the magenta component scaled to a percentage (0 .. 100) of a pixelValue.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  magentaComponentOfCMYK: pixel
if the receiver is a cmyk-image:
return the magenta component scaled to a percentage (0 .. 100) of a pixelValue.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  maskedUsedValues
return a collection of pixel values used in the receiver,
which are not masked (i.e. opaque).
Notice that the interpretation of the pixels depends on the photometric
of the image.
This is a general and therefore slow implementation; subclasses
may want to redefine this method for more performance.
This goes through the pixels and collects unmasked pixel values as present in the image
(as opposed to #usedValues, which ignores any mask,
and usedColors, which looks at the colorMap if present)

Usage example(s):

     ToolbarIconLibrary error32x32Icon usedValues size 114
     ToolbarIconLibrary error32x32Icon maskedUsedValues size 113
     ToolbarIconLibrary error32x32Icon clearMaskedPixels usedValues size  
     ToolbarIconLibrary error32x32Icon clearMaskedPixels maskedUsedValues size

o  nColorsUsed

o  numAlphaBits
alpha in low bits

o  numBlueBits
alpha in low bits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  numGreenBits
alpha in low bits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  numRedBits
alpha in low bits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  pixelArraySpecies
return the kind of pixel-value container in rowAt:/rowAt:put: methods

o  realColorMap
return a collection usable as a real colormap of the image.
For palette images, this is the internal colormap;
for other photometrics (which do not have a real colormap), synthesize one.
This is different from #colorMap, which returns nil for non palette images.

o  realUsedColors
return a collection of colors which are really used in the receiver.
This goes through the pixels and adds up colors as present in the image
(as opposed to #usedColors, which looks at the colorMap if present)

o  realUsedValues
return a collection of color values used in the receiver.
Notice that the interpretation of the pixels depends on the photometric
of the image.
This is a general and therefore slow implementation; subclasses
may want to redefine this method for more performance.
This goes through the pixels and collects pixel values as present in the image
(as opposed to #usedColors, which looks at the colorMap if present)

o  redBitsOf: pixel
if the receiver is an rgb-image:
return the red component of a pixelValue as integer 0..maxRedValue.
MaxRedValue is the largest integer representable by the number
of red bits i.e. (1 bitShift:bitsRed)-1.
This has to be redefined by subclasses.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  redComponentOf: pixel
if the receiver is an rgb-image:
return the red component scaled to a percentage (0..100) of a pixelValue.
This has to be redefined by subclasses.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  redMaskForPixelValue
return the mask used with translation from pixelValues to redBits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  redShiftForPixelValue
return the shift amount used with translation from pixelValues to redBits

** This method must be redefined in concrete classes (subclassResponsibility) **

o  rgbFromValue: pixelValue
given a pixel value, return the corresponding 24bit rgbValue (rrggbb, red is MSB).
Pixel value is in 0..2^depth - 1.
The implementation below is generic and slow
- this method is typically redefined in subclasses.

Usage example(s):

     (self basicNew
        bitsPerSample:#(8 8 8);
        photometric:#YCbCr;
        samplesPerPixel:3;
        yourself
     ) rgbFromValue: 16r7F1010

     (self basicNew
        bitsPerSample:#(8 8 8);
        photometric:#YCbCr;
        samplesPerPixel:3;
        yourself
     ) rgbFromValue: 16rFF1010

     (self basicNew
        bitsPerSample:#(8 8 8);
        photometric:#YCbCr;
        samplesPerPixel:3;
        yourself
     ) rgbFromValue: 16rFF0000

o  usedColors
return a collection of colors used in the receiver.
This looks at the colorMap only if present.
(as opposed to #realUsedColors, which goes through the pixels of the bitmap)

Usage example(s):

     (Image fromFile:'goodies/bitmaps/gifImages/garfield.gif') usedColors
     (Image fromFile:'libtool/bitmaps/SBrowser.xbm') usedColors

o  usedColorsMax: nMax
return a collection of colors used in the receiver;
This looks at the colorMap only if present
(as opposed to #realUsedColors, which goes through the pixels of the bitmap).
However, stop looking for more, if more than nMax colors have been found
(useful when searching rgb images).

o  usedValues
return a collection of color values used in the receiver.
Notice that the interpretation of the pixels depends on the photometric
of the image.
This is a general and therefore slow implementation; subclasses
may want to redefine this method for more performance.

Usage example(s):

     (Image fromFile:'goodies/bitmaps/gifImages/garfield.gif') usedValues
     (Image fromFile:'lib tool/bitmaps/SBrowser.xbm') usedValues

o  valueFromColor: color
given a color, return the corresponding pixel value.
Non-representable colors return nil.

o  valueFromRGB: rgb
given a color as rgb-value, with 8 bits per component,
return the corresponding pixel value.
The red component is in the high 8 bits.
Non-representable colors return nil.

Usage example(s):

     |img|
     img := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     img valueFromRGB:16r55AAFF.

o  valueFromRedBits: redBits greenBits: greenBits blueBits: blueBits
given the rgb bits, each in 0..maxXXXValue (i.e. according to
r/g/b channels number of bits, return the corresponding pixel value.
For now, only useful with RGB images

o  widthOn: aGC
return my width, if displayed on aGC;
since my width is independent of the device (the number of pixels),
return the pixel-width

o  yellowComponentOfCMY: pixel
if the receiver is a cmy-image:
return the yellow component scaled to a percentage (0 .. 100) of a pixelValue.

** This method must be redefined in concrete classes (subclassResponsibility) **

o  yellowComponentOfCMYK: pixel
if the receiver is a cmyk-image:
return the yellow component scaled to a percentage (0 .. 100) of a pixelValue.

** This method must be redefined in concrete classes (subclassResponsibility) **

saving on file
o  bytesForFileUsing: readerClass
return the contents of a file if saved by readerClass.
That is: an imageWriter is created to generate the bytes
as if written to a file.
No actual file is created, but the bytes are returned

Usage example(s):

     |anImage|

     anImage := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     anImage bytesForFileUsing:TIFFReader.
     anImage bytesForFileUsing:PNGReader.

o  saveOn: aFileName
save the image in aFileName. The suffix of the filename controls the format.
Currently, not all formats may be supported
(see ImageReader subclasses implementing save:onFile:).
May raise a signal, if the image cannot be written by the reader.

Usage example(s):

     |image|

     image := Image fromFile:'goodies/bitmaps/RCube.tiff'.
     image saveOn:'myImage.tiff'.
     image saveOn:'myImage.xbm'.
     image saveOn:'myImage.xpm'.
     image saveOn:'myImage.xwd'.

o  saveOn: aFileName quality: qualityPercentOrNil
save the image in aFileName. The suffix of the filename controls the format.
Currently, not all formats may be supported
(see ImageReader subclasses implementing save:onFile:).
May raise a signal, if the image cannot be written by the reader.

Usage example(s):

     |image|

     image := Image fromFile:'banner1.xpm'.
     image saveOn:'myImage.tiff'.
     image saveOn:'myImage.xpm'.
     (image asImageWithDepth:1) saveOn:'myImage.xbm'.
     image saveOn:'myImage.xwd'.

o  saveOn: aFileName quality: qualityPercentOrNil using: readerClass
save the receiver using the representation class
(which is usually a concrete subclasses of ImageReader).
May raise a signal, if the image cannot be written by the reader.

Usage example(s):

     |anImage|

     anImage := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     anImage saveOn:'myImage.tiff' using:TIFFReader.

Usage example(s):

     |anImage|

     anImage := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     anImage saveOn:'myImage.xbm' using:XBMReader.

Usage example(s):

     |anImage|

     anImage := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     Image cannotRepresentImageSignal handle:[:ex |
        self warn:'cannot save the image in this format'
     ] do:[
        anImage saveOn:'myImage.xbm' using:XBMReader.
     ]

Usage example(s):

     |anImage|

     anImage := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     anImage saveOn:'myImage.xpm' using:XPMReader.

Usage example(s):

     |anImage|

     anImage := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     anImage saveOn:'myImage.gif' using:GIFReader.

o  saveOn: aFileName using: readerClass
save the receiver using the representation class
(which is usually a concrete subclasses of ImageReader).
May raise a signal, if the image cannot be written by the reader.

Usage example(s):

     |anImage|

     anImage := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     anImage saveOn:'myImage.tiff' using:TIFFReader.
     (Depth24Image fromImage:anImage) saveOn:'myImage.jpg' using:JPEGReader.
     anImage saveOn:'myImage50.tiff' quality:50 using:TIFFReader.
     (Depth24Image fromImage:anImage) saveOn:'myImage50.jpg' quality:50 using:JPEGReader.

Usage example(s):

     |anImage|

     anImage := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     anImage saveOn:'myImage.xbm' using:XBMReader.

Usage example(s):

     |anImage|

     anImage := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     Image cannotRepresentImageSignal handle:[:ex |
        self warn:'cannot save the image in this format'
     ] do:[
        anImage saveOn:'myImage.xbm' using:XBMReader.
     ]

Usage example(s):

     |anImage|

     anImage := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     anImage saveOn:'myImage.xpm' using:XPMReader.

Usage example(s):

     |anImage|

     anImage := Image fromFile:'goodies/bitmaps/gifImages/garfield.gif'.
     anImage saveOn:'myImage.gif' using:GIFReader.

o  saveOnStream: aWriteStream quality: qualityPercentOrNil using: readerClass
save the receiver using the representation class
(which is usually a concrete subclasses of ImageReader).
May raise a signal, if the image cannot be written by the reader.

Usage example(s):

     |anImage tmpStream|

     anImage := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     tmpStream := FileStream newTemporaryWithSuffix:'png'.
     anImage saveOnStream:tmpStream quality:50 using:PNGReader.
     tmpStream close.
     tmpStream fileName

o  saveOnStream: aWriteStream using: readerClass
save the receiver using the representation class
(which is usually a concrete subclasses of ImageReader).
May raise a signal, if the image cannot be written by the reader.

Usage example(s):

     |anImage tmpStream|

     anImage := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
     tmpStream := FileStream newTemporaryWithSuffix:'png'.
     anImage saveOnStream:tmpStream using:PNGReader.
     tmpStream close.
     tmpStream fileName

screen capture
o  from: aDrawable in: aRectangle
read an image from aDrawable.
This may be a device Form, a view or the rootView.
If it's a view or rootView, it must be completely visible (or have
the backingStore option turned on). Otherwise, only the clipped contents
is returned. This is a common helper for form-to-image conversion,
and to read hardcopy images from the screen.

o  fromScreen: aRectangle
read an image from the display screen.
WARNING: this temporarily grabs the display
it may not work from within a buttonMotion
(use #fromScreen:on:grab: with a false grabArg then).

o  fromScreen: aRectangle on: aDevice
read an image from aDevices display screen.
Since I have no other displays, only the MonoChrome, StaticGrey
and PseudoColor cases have been tested ...
(especially True- and DirectColor may be wrong).
Late note: 24bit rgb now also works.
WARNING: this temporarily grabs the display
it may not work from within a buttonMotion
(use #fromScreen:on:grab: with a false grabArg then).

Usage example(s):

     Image fromScreen:((0 @ 0) corner:(100 @ 100)) on:Display
     Image fromScreen:((0 @ 0) corner:(500 @ 500)) on:Display

o  fromScreen: aRectangle on: aDevice grab: doGrab
read an image from aDevice's display screen.
If the doGrab argument is true, the display
is grabbed (i.e. blocked for others) and a camera cursor is
shown while the readout is done.
Since I have no other displays, only the MonoChrome, StaticGrey
and PseudoColor cases have been tested ...
(especially True- and DirectColor may be wrong).
Late note: 24bit rgb now also works.
WARNING: with doGrab true, this temporarily grabs the display
and it may not work from within a buttonMotion
(use with a false grabArg then).

Usage example(s):

     Image fromScreen:((100@100) corner:(200@200)) on:Display grab:false
     Image fromScreen:((100@100) corner:(200@200)) on:Display grab:true

o  photometricFromScreen: aDevice
read aDevice's display photometric and set my colormap for it.
This must be used after an image's bits have been read from the screen
or from an offScreen bitmap, for correct pixel interpretation.

virtual anti-aliased
o  virtualAntiAliasedAlongXvertical: bottomOrTop horizontal: leftOrRight form: tempForm color: aColor xRun: xRun yRun: yRun colorDictionary: colorDictionary blendStart: blendStart

o  virtualAntiAliasedAlongYhorizontal: leftOrRight vertical: bottomOrTop form: tempForm color: aColor xRun: xRun yRun: yRun colorDictionary: colorDictionary blendStart: blendStart


Examples:


reading from a file (many formats are supported): (notice that the bitmaps directory is searched for along the system path - therefore, you may add your own bitmap directory to the beginning of the path and thus override any default bitmaps, or make certain that your application finds its bitmaps - even if they are in a separate directory)
    (Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') inspect
Boy, was I young, when writing ST/X... ;-)
    (Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif') inspect
    ((Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif') rotated:90) inspect
    ((Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif') rotated:45) inspect
    ((Image fromFile:'../../goodies/bitmaps/gifImages/claus.gif') rotated:25) inspect
better use package relative file names:
    (Image fromFile:'bitmaps/gifImages/garfield.gif' inPackage:'stx:goodies') inspect
various file formats are supported:
    (Image fromFile:'bitmaps/xpmBitmaps/misc_icons/SmalltalkX_clr.xpm' inPackage:'stx:goodies') inspect
    (Image fromFile:'bitmaps/winBitmaps/okSmily_up.bmp' inPackage:'stx:goodies') inspect
drawing
    |imageClass image|

    imageClass := Image implementorForDepth:24.
    image      := imageClass width: 100 height: 50.
    image bits:(ByteArray new:(image bytesPerRow*50)).
    image fillRectangle:(0@0 extent:100@50) withColor:Color yellow.
    image drawRectangle:(10@10 extent:20@20) withColor:Color red.
    image fillRectangle:(40@20 extent:20@20) withColor:Color green.
The following examples demonstrate various depth and colorMap variations ... inline image: default: depth=1 & #blackIs0
    (Image
        width:8 height:8
        fromArray:#( 2r11111111
                     2r10000001
                     2r10000001
                     2r10000001
                     2r10000001
                     2r10000001
                     2r10000001
                     2r11111111 )
    ) edit
with #whiteIs0 photometric
    ((Image width:8 height:8
           fromArray:#( 2r11111111
                        2r10000001
                        2r10000001
                        2r10000001
                        2r10000001
                        2r10000001
                        2r10000001
                        2r11111111 ))
        photometric:#whiteIs0
    ) edit
with a colorMap
    ((Image width:8 height:8
           fromArray:#( 2r11111111
                        2r10000001
                        2r10000001
                        2r10000001
                        2r10000001
                        2r10000001
                        2r10000001
                        2r11111111 ))
        colorMap:(Array with:(Color red)
                        with:(Color yellow))
    ) edit
a depth4 greyScale image: (default photometric is #blackIs0)
    (Depth4Image
         width:8
         height:4
         fromArray:#[
                        16r00 16r11 16r22 16r33
                        16r44 16r55 16r66 16r77
                        16r88 16r99 16raa 16rbb
                        16rcc 16rdd 16ree 16rff
                    ]
    ) edit
the same, magnified:
    ((Depth4Image
         width:4
         height:4
         fromArray:#[
                        16r01 16r23
                        16r45 16r67
                        16r89 16rab
                        16rcd 16ref
                    ])
        magnifiedBy:30
    ) edit
the following has the same effect:
    ((Image
         width:4
         height:4
         depth:4
         fromArray:#[
                        16r01 16r23
                        16r45 16r67
                        16r89 16rab
                        16rcd 16ref
                    ])
        magnifiedBy:30
    ) edit
with reverse grey-interpretation:
    ((Depth4Image
         width:4
         height:4
         fromArray:#[
                        16r01 16r23
                        16r45 16r67
                        16r89 16rab
                        16rcd 16ref
                    ])
        photometric:#whiteIs0;
        magnifiedBy:30
    ) edit
with 1-bit-per-pixel rgb interpretation:
    ((Depth4Image
         width:4
         height:4
         fromArray:#[
                        16r01 16r23
                        16r45 16r67
                        16r89 16rab
                        16rcd 16ref
                    ])
        photometric:#rgb;
        samplesPerPixel:3;
        bitsPerSample:#(1 1 1);
        magnifiedBy:30
    ) edit
with 1/2/1 rgb interpretation:
    ((Depth4Image
         width:4
         height:4
         fromArray:#[
                        16r01 16r23
                        16r45 16r67
                        16r89 16rab
                        16rcd 16ref
                    ])
        photometric:#rgb;
        samplesPerPixel:3;
        bitsPerSample:#(1 2 1);
        magnifiedBy:30
    ) edit
a 2/2/0 rgb image (i.e. no blue):
     |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 edit.
a 0/0/4 rgb image (i.e. no red or green):
     |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 edit.
a 2plane greyscale image:
    ((Depth2Image
         width:4
         height:4
         fromArray:#[
                        4r0123
                        4r1230
                        4r2301
                        4r3012
                    ])
        magnifiedBy:30
    ) edit
a 2plane greyscale image:
    ((Depth2Image
         width:4
         height:4
         fromArray:#[
                        4r0110
                        4r1221
                        4r1221
                        4r0110
                    ])
        magnifiedBy:30
    ) edit
with colors:
    ((Depth2Image
         width:4
         height:4
         fromArray:#[
                        4r0123
                        4r1230
                        4r2301
                        4r3012
                    ])
        colorMap:(Array with:(Color black)
                        with:(Color red)
                        with:(Color green)
                        with:(Color blue));
        magnifiedBy:30
    ) edit
depth4 image with 1/1/1 rgb interpretation:
    ((Depth4Image
         width:4
         height:4
         fromArray:#[
                        16r44 16r44
                        16r22 16r22
                        16r11 16r11
                        16r00 16r00
                    ])
        photometric:#rgb;
        samplesPerPixel:3;
        bitsPerSample:#(1 1 1);
        magnifiedBy:30
    ) edit
depth4 image with 1/2/1 rgb interpretation:
    ((Depth4Image
         width:4
         height:4
         fromArray:#[
                        16rCC 16r44
                        16rAA 16r22
                        16r99 16r11
                        16r88 16r00
                    ])
        photometric:#rgb;
        samplesPerPixel:3;
        bitsPerSample:#(1 2 1);
        magnifiedBy:30
    ) edit
depth8 image with 3/3/2 rgb interpretation:
    ((Depth8Image
         width:16
         height:16
         fromArray:(ByteArray withAll:(0 to:16rFF)))
        photometric:#rgb;
        samplesPerPixel:3;
        bitsPerSample:#(3 3 2);
        magnifiedBy:10
    ) edit
depth8 image with 2/2/2 rgb interpretation:
    ((Depth8Image
         width:8
         height:8
         fromArray:(ByteArray withAll:(0 to:16r3F)))
        photometric:#rgb;
        samplesPerPixel:3;
        bitsPerSample:#(2 2 2);
        magnifiedBy:10
    ) edit
    ((Depth8Image
         width:4
         height:4
         fromArray:#[
                16r30 16r0C  16r03 16r3F
                16r20 16r08  16r02 16r2A
                16r10 16r04  16r01 16r15
                16r00 16r00  16r00 16r00
                    ])
        photometric:#rgb;
        samplesPerPixel:3;
        bitsPerSample:#(2 2 2);
        magnifiedBy:30
    ) edit
trueColor image: remember: bytes are MSB
    ((Depth16Image
         width:4
         height:5
         fromArray:#[
                2r01111100 2r00000000  2r00000011 2r11100000  2r00000000 2r00011111  2r01111111 2r11111111
                2r00111100 2r00000000  2r00000001 2r11100000  2r00000000 2r00001111  2r00111101 2r11101111
                2r00011100 2r00000000  2r00000000 2r11100000  2r00000000 2r00000111  2r00011100 2r11100111
                2r00001100 2r00000000  2r00000000 2r01100000  2r00000000 2r00000001  2r00001100 2r01100011
                2r00000100 2r00000000  2r00000000 2r00100000  2r00000000 2r00000001  2r00000100 2r00100001
                    ])
        photometric:#rgb;
        samplesPerPixel:3;
        bitsPerSample:#(5 5 5);
        magnifiedBy:30
    ) edit
    ((Depth24Image
         width:4
         height:4
         fromArray:#[
                16rFF 16r00 16r00  16rFF 16r00 16r00  16rFF 16r00 16r00  16rFF 16r00 16r00
                16r00 16rFF 16r00  16r00 16rFF 16r00  16r00 16rFF 16r00  16r00 16rFF 16r00
                16r00 16r00 16rFF  16r00 16r00 16rFF  16r00 16r00 16rFF  16r00 16r00 16rFF
                16rFF 16rFF 16rFF  16rFF 16rFF 16rFF  16rFF 16rFF 16rFF  16rFF 16rFF 16rFF
                    ])
        photometric:#rgb;
        samplesPerPixel:3;
        bitsPerSample:#(8 8 8);
        magnifiedBy:30
    ) edit
32bit trueColor image:
    ((Depth32Image
         width:4
         height:4
         fromArray:#[
                16rFF 16r00 16r00 16r00  16rFF 16r00 16r00 16r00  16rFF 16r00 16r00 16r00  16rFF 16r00 16r00 16r00
                16r00 16rFF 16r00 16r00  16r00 16rFF 16r00 16r00  16r00 16rFF 16r00 16r00  16r00 16rFF 16r00 16r00
                16r00 16r00 16rFF 16r00  16r00 16r00 16rFF 16r00  16r00 16r00 16rFF 16r00  16r00 16r00 16rFF 16r00
                16rFF 16rFF 16rFF 16r00  16rFF 16rFF 16rFF 16r00  16rFF 16rFF 16rFF 16r00  16rFF 16rFF 16rFF 16r00
                    ])
        photometric:#rgb;
        samplesPerPixel:4;
        bitsPerSample:#(8 8 8 8);
        magnifiedBy:30
    ) edit
storing - only a subset of formats (TIFF, XBM, XPM) currently support storing:
    |img|

    img := Image fromFile:'bitmaps/winBitmaps/okSmily_up.bmp' inPackage:'stx:goodies'.
    img saveOn:'myImage.tiff'.
    (Image fromFile:'myImage.tiff') inspect.
    img saveOn:'myImage.gif'.
    (Image fromFile:'myImage.gif') inspect.
magnifying (any factor):
    ((Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies')
        magnifiedTo:(48@48))
            inspect
    ((Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies')
        magnifiedBy:0.7)
            inspect
rotating (any angle in degrees clockwise):
    ((Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies')
        rotated:90)
            inspect
    (((Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies')
        magnifiedBy:0.3@0.7) rotated:270)
            inspect
    (((Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies')
        ) rotated:30)
            inspect
negative:
    ((Image fromFile:'bitmaps/gifImages/claus.gif' inPackage:'stx:goodies')
        negative)
            inspect
depth32 image with 8+8+8+8 argb interpretation:
    ((Depth32Image
         width:4 height:4
         fromArray:#[
            255 255 0 0       255 255 0 0       255 255 0 0       255 255 0 0
            255 0 255 0       255 0 255 0       255 0 255 0       255 0 255 0
            255 0 0 255       255 0 0 255       255 0 0 255       255 0 0 255
            255 255 255 255   255 255 255 255   255 255 255 255   255 255 255 255 ])
        photometric:#argb;
        samplesPerPixel:4;
        bitsPerSample:#(8 8 8 8);
        magnifiedBy:10
    ) edit
depth32 image with 8+8+8+8 rgba interpretation:
    ((Depth32Image
         width:4 height:4
         fromArray:#[
            255 0 0 255       255 0 0 255       255 0 0 255       255 0 0 255
            0 255 0 255       0 255 0 255       0 255 0 255       0 255 0 255
            0 0 255 255       0 0 255 255       0 0 255 255       0 0 255 255
            255 255 255 255   255 255 255 255   255 255 255 255   255 255 255 255 ])
        photometric:#rgba;
        samplesPerPixel:4;
        bitsPerSample:#(8 8 8 8);
        magnifiedBy:10
    ) edit
conversion:
    |d32Image d24Image|

    d32Image := (Depth32Image
         width:4 height:4
         fromArray:#[
            255 0 0 255       255 0 0 255       255 0 0 255       255 0 0 255
            0 255 0 255       0 255 0 255       0 255 0 255       0 255 0 255
            0 0 255 255       0 0 255 255       0 0 255 255       0 0 255 255
            255 255 255 255   255 255 255 255   255 255 255 255   255 255 255 255 ])
        photometric:#rgba;
        samplesPerPixel:4;
        bitsPerSample:#(8 8 8 8);
        magnifiedBy:10.
    d32Image inspect.
    d24Image := Depth24Image fromImage:d32Image.
    d24Image inspect.


ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Mon, 18 Nov 2024 04:44:18 GMT