"{ Encoding: utf8 }"
"
COPYRIGHT (c) 1997-1998 by eXept Software AG
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.
"
"{ Package: 'stx:libtool2' }"
"{ NameSpace: Smalltalk }"
ResourceSpecEditor subclass:#ImageEditor
instanceVariableNames:'imageEditView colorMapMode editMode mouseKeyColorMode
selectedColorIndex postOpenAction imageSeqNr drawingColormap
lastShiftUsedWrap lastGrabbedScreenArea
allowedToChangeImageDimensionAndDepth savedImage savedFile'
classVariableNames:'DefaultRelativeSizes LastColormapMode LastDirectory
LastSizeString LastURL MaskClipboard LastDepth
LastNumThresholdGrayColors LastMagnifyTo LastMagnifyBy
LastMagnifySmoothing'
poolDictionaries:''
category:'Interface-UIPainter'
!
!ImageEditor class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1997-1998 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
Image Editor allows you to create, design, modify or just inspect images.
It is also used subclasses as a tool to post-process captured screen images and
bitmaps in expecco.
The actual drawing functionality is found in ImageEditView;
the code here (an appModel) provides nice menus, previews, colormap manipulation etc.
[start with:]
ImageEditor open
ImageEditor openOnClass:Icon andSelector:#startIcon
(Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif') edit
(Image fromScreen:(0@0 corner:100@100)) edit
[see also:]
ImageEditView Image
[author:]
Thomas Zwick, eXept Software AG
Claus Gittinger, eXept Software AG
"
! !
!ImageEditor class methodsFor:'instance creation'!
openLoadingImageWith:aBlock modal:modalBoolean
"opens an Image Editor on anImage.
Returns the editor (to access its attributes)"
|editor|
editor := self new.
editor allButOpen.
aBlock value:editor.
modalBoolean ifTrue:[
editor openWindowModal.
] ifFalse:[
editor openWindow.
].
^ editor
"Modified (comment): / 07-03-2017 / 16:36:16 / cg"
!
openModalOnClass: aClass andSelector: aSelector
"opens a modal Image Editor on aClass and aSelector.
Returns the real name of the edited resource method (in case, user changed it)."
|imageEditor imageEditView className resourceClass resourceSelector|
imageEditor := self new.
aClass isClass ifTrue: [className := aClass name].
aClass isString ifTrue: [className := aClass].
aClass isNil ifTrue: [className := ''].
imageEditor postOpenAction: [
imageEditView := imageEditor imageEditView.
imageEditor loadFromOrPrepareForClass: aClass andSelector: aSelector
].
imageEditor openModal.
resourceClass := imageEditView resourceClass.
resourceSelector := imageEditView resourceSelector.
(resourceClass isNil or:[resourceSelector isNil]) ifTrue:[^ nil].
^ Array with:resourceClass with:resourceSelector
"
self openModalOnClass: self andSelector: #leftMouseKeyIcon
"
!
openModalOnFile:aFileName
"opens an Image Editor on aFileName.
Returns the editor (to access its attributes)"
^ self openOnFile:aFileName modal:true
"
self openModalOnFile: '../../goodies/bitmaps/gifImages/back.gif'
"
"Modified: / 07-03-2017 / 16:36:32 / cg"
!
openModalOnImage:anImage
"opens a modal Image Editor on an image.
Returns the modified image or nil if unsaved/unchanged"
|imageEditor imageEditView newImage|
imageEditor := self new.
imageEditor allowedToChangeImageDimensionAndDepth:false.
imageEditor postOpenAction: [
imageEditView := imageEditor imageEditView.
imageEditor loadFromImage: anImage
].
imageEditor openModal.
newImage := imageEditor savedImage.
^ newImage
!
openOnClass:aClass andSelector:aSelector
"opens an Image Editor on aClass and aSelector.
Returns the editor (to access its attributes)"
^ self openOnClass:aClass andSelector:aSelector modal:false
"
self openOnClass:self andSelector:#leftMouseKeyIcon
self openOnClass:self andSelector:nil
"
"Modified: / 07-03-2017 / 16:36:58 / cg"
!
openOnClass:aClass andSelector:aSelector modal:modal
"opens an Image Editor on aClass and aSelector.
Returns the editor (to access its attributes)"
^ self
openLoadingImageWith:[:editor |
editor loadFromClass:(aClass theNonMetaclass) andSelector:aSelector
]
modal:modal.
"
self openOnClass:self andSelector:#leftMouseKeyIcon modal:true
self openOnClass:self andSelector:nil
"
"Created: / 07-03-2017 / 16:34:36 / cg"
!
openOnFile:aFileName
"opens an Image Editor on aFileName.
Returns the editor (to access its attributes)"
^ self openOnFile:aFileName modal:false
"
self openOnFile: '../../goodies/bitmaps/gifImages/back.gif'
"
"Modified: / 07-03-2017 / 16:37:33 / cg"
!
openOnFile:aFileName modal:modal
"opens an Image Editor on aFileName.
Returns the editor (to access its attributes)"
^ self
openLoadingImageWith:[:editor |
editor loadFromFile:aFileName.
]
modal:modal.
"
self openOnFile: '../../goodies/bitmaps/gifImages/back.gif' modal:false
self openOnFile: '../../goodies/bitmaps/gifImages/back.gif' modal:true
"
"Created: / 07-03-2017 / 16:33:12 / cg"
!
openOnImage:anImage
"opens an Image Editor on anImage.
Returns the editor (to access its attributes)"
^ self
openLoadingImageWith:[:editor | editor loadFromImage: anImage ]
modal:false
"
self openOnImage: Icon startIcon
"
"Modified: / 07-03-2017 / 16:37:57 / cg"
! !
!ImageEditor class methodsFor:'accessing'!
listOfColorMaps
"returns the list of default color maps for a new image"
|colorMap|
(colorMap := OrderedCollection new)
add: Color black;
add: Color white;
add: Color red;
add: Color green;
add: Color blue;
add: Color cyan;
add: Color yellow;
add: Color magenta;
add: (Color redByte: 127 greenByte: 0 blueByte: 0);
add: (Color redByte: 0 greenByte: 127 blueByte: 0);
add: (Color redByte: 0 greenByte: 0 blueByte: 127);
add: (Color redByte: 0 greenByte: 127 blueByte: 127);
add: (Color redByte: 127 greenByte: 127 blueByte: 0);
add: (Color redByte: 127 greenByte: 0 blueByte: 127);
add: (Color redByte: 127 greenByte: 127 blueByte: 127);
add: (Color redByte: 170 greenByte: 170 blueByte: 170).
0 to: 5 do: [:r|
0 to: 5 do: [:g|
0 to: 5 do: [:b|
colorMap add: (Color redByte: (r*255//5) ceiling greenByte: (g*255//5) ceiling blueByte: (b*255//5) ceiling)
]
]
].
1 to: 25 do: [:g|
colorMap add: (Color redByte: (g*255//26) ceiling greenByte: (g*255//26) ceiling blueByte: (g*255//26) ceiling)
].
^ Dictionary new
at: #depth32 put:(FixedPalette redShift:16 redMask:16rFF greenShift:8 greenMask:16rFF blueShift:0 blueMask:16rFF);
at: #depth24 put:(FixedPalette redShift:16 redMask:16rFF greenShift:8 greenMask:16rFF blueShift:0 blueMask:16rFF);
at: #masked24 put:(FixedPalette redShift:16 redMask:16rFF greenShift:8 greenMask:16rFF blueShift:0 blueMask:16rFF);
at: #depth16 put:(FixedPalette redShift:11 redMask:16r1F greenShift:5 greenMask:16r3F blueShift:0 blueMask:16r1F);
at: #masked16 put:(FixedPalette redShift:11 redMask:16r1F greenShift:5 greenMask:16r3F blueShift:0 blueMask:16r1F);
at: #depth8 put: colorMap;
at: #masked8 put: colorMap;
at: #depth4 put: (colorMap copyFrom: 1 to: 16);
at: #masked4 put: (colorMap copyFrom: 1 to: 16);
at: #depth2 put: (colorMap copyFrom: 1 to: 4);
at: #masked2 put: (colorMap copyFrom: 1 to: 4);
at: #depth1 put: (colorMap copyFrom: 1 to: 2);
at: #masked1 put: (colorMap copyFrom: 1 to: 2);
yourself
!
listOfDefaultSizes
"returns the list of default sizes for a new image"
^ #('8x8' '16x16' '22x22' '32x32' '48x48' '64x64')
"Modified: / 31.7.1998 / 01:57:34 / cg"
!
namesOfColorMaps
^ Dictionary new
at: #depth32 put: '32-plane (rgba)';
at: #depth24 put: '24-plane';
at: #masked24 put: '24-plane + mask';
at: #depth16 put: '16-plane';
at: #masked16 put: '16-plane + mask';
at: #depth8 put: ' 8-plane';
at: #masked8 put: ' 8-plane + mask';
at: #depth4 put: ' 4-plane';
at: #masked4 put: ' 4-plane + mask';
at: #depth2 put: ' 2-plane';
at: #masked2 put: ' 2-plane + mask';
at: #depth1 put: ' 1-plane';
at: #masked1 put: ' 1-plane + mask' ;
yourself
! !
!ImageEditor class methodsFor:'help specs'!
helpPairs
"This resource specification was automatically generated
by the UIHelpTool of ST/X."
"Do not manually edit this!! If it is corrupted,
the UIHelpTool may not be able to read the specification."
"
UIHelpTool openOnClass:ImageEditor
"
<resource: #help>
^ #(
#drawingColor1
'The color associated to the left mouse button.\Also the color used in fill operations'
#drawingColor2
'The color associated to the right mouse button.\Also the second color used in gradient fill operations'
#drawingAlpha
'The alpha value (in percent) to be used in edit operations.\If the "mask"-color is selected, only the alpha value will be changed.\Otherwise, the selected color plus this alpha value will be used for drawing'
#autoCropAll
'Find and remove all borders'
#autoCropBottom
'Find and remove bottom border'
#autoCropLeft
'Find and remove left border'
#autoCropRight
'Find and remove right border'
#autoCropTop
'Find and remove top border'
#colorMap
'ColorMap functions'
#colorMap1
'Convert to depth-1 image'
#colorMap1M
'Convert to depth-1 image plus mask'
#colorMap2
'Convert to depth-2 image'
#colorMap24
'Convert to depth-24 image (rgb)'
#colorMap2M
'Convert to depth-2 image plus mask'
#colorMap32
'Convert to depth-32 image (rgba)'
#colorMap4
'Convert to depth-4 image'
#colorMap4M
'Convert to depth-4 image plus mask'
#colorMap8
'Convert to depth-8 image'
#colorMap8M
'Convert to depth-8 image plus mask'
#colorMapTable
'Shows a list of used colors of the image'
#compressColormap
'Remove unneeded entries from the colorMap'
#cropAll
'Crop (cut off) all four sides by the amounts entered into the above fields.'
#cropBottom
'Cut off the specified number of pixels at the bottom'
#cropBySelectingArea
'Select new area in the right detail view.'
#cropLeft
'Cut off the specified number of pixels at the left'
#cropManual
'Specify border(s) to remove.'
#cropRight
'Cut off the specified number of pixels at the right'
#cropTop
'Cut off the specified number of pixels at the top'
#cropubImage
'Select a subarea as the image''s new dimension'
#drawModeBox
'Rectangle Drawing Mode'
#drawModeCircle
'Circle Drawing Mode'
#drawModeCopy
'Area Copy Mode'
#drawModeCropSubImage
'Select and extract a subimage'
#drawModeFill
'Flood Fill Mode'
#drawModeFilledBox
'Filled Rectangle Drawing Mode'
#drawModeFilledCircle
'Filled Circle Drawing Mode'
#drawModeMaskOutsideCircle
'Mask everything outside a Circle'
#drawModeMaskOutsideRectangle
'Mask everything outside a Rectangle'
#drawModePaste
'Paste-Over Mode (only paste pixels; keep mask as is)'
#drawModePasteUnder
'Paste-Under Mode (only paste previously masked pixels)'
#drawModePasteWithMask
'Paste-with-Mask Mode (both pixel and mask are pasted)'
#drawModePoint
'Point Drawing Mode'
#drawModeSpecial
'Special operations (select rectangle, then choose operation)'
#drawModeSpray
'Spray Drawing Mode'
#edit3DProjection
'Generate a 3D projection'
#editFlipHorizontal
'Flip the image horizontally'
#editFlipVertical
'Flip the image vertically'
#editMagnifyImage
'Magnify the image'
#editNegate
'Invert the images colors'
#editResize
'Resize the image (preserving the old image)'
#editRotate
'Rotate the image'
#fileEditMask
'Load Mask from a File'
#fileGrabImageFromScreen
'Pick an image from the screen (specify area)'
#fileGrabImageFromWindow
'Pick an image from a window on the screen (click on window)'
#fileLoadFromClass
'Select and load an image from a resource method'
#fileLoadFromFile
'Select and load an image from a file'
#fileLoadFromURL
'Load an image from the net, given its URL'
#fileNewImage
'Create a new image'
#fileNewImageFromClipboard
'Create a new image and initialize it from the clipboard'
#fileNewMaskFromClipboard
'Paste the image in the clipboard as a mask. Must be a depth-1 image'
#filePrint
'Print the image on a postscript printer'
#filePrint
'Print'
#fileSave
'Save the image'
#fileSaveAs
'Save the image to a file'
#fileSaveButtonImageAs
'Save an image of a button with the image to a file (for html use)'
#fileSaveMaskAs
'Save the mask of the image to a file'
#fileSaveMethod
'Save the image as resource method in the current class and selector'
#fileSaveMethodAs
'Save the image as resource method in a class'
#floodFillMaxError
'Specify the max. allowed deviation from the clicked pixel in a flood-fill operation.\Pixels where the hue/light values differ less than that fraction\will be included in the fill.\The range must be between 0 and 1. With 0, only areas with exactly the same pixel will be filled.\With 1, every other pixel is included.\\When filling gradiented areas, start with small values, such as 0.05, and increase slowly (undo and try with higher value).\This is especially useful when masking background areas from screenshots.'
#magnificationNumber
'Shows the current magnification'
#magnifyImageDown
'Decrease magnification'
#magnifyImageUp
'Increase magnification'
#mouseKeyColorMode
'Toggle between left and right mouse button color'
#nextImageInSequence
'Go to the next image in the animated gif image sequence.'
#previewView
'Shows a preview of the image'
#previousImageInSequence
'Go to the previous image in the animated gif image sequence.'
#settingsGridMagnification
'Change the grid magnification of the edit view'
#xdrawModeBox
'Rectangle'
#xdrawModeCopy
'Copy'
#xdrawModeFill
'Flood-fill'
#xdrawModeFilledBox
'Filled rectangle'
#xdrawModePaste
'Paste'
#xdrawModePasteUnder
'Paste under'
#xdrawModePasteWithMask
'Paste with Mask'
#xdrawModePoint
'Point'
#xfileGrabImage
'Pick from screen'
#xfileLoadFromClass
'Load from method...'
#xfileLoadFromFile
'Load from file...'
#xfileNewImage
'New image'
#xfileSaveAs
'Save to file...'
#xfileSaveMaskAs
'Save mask to file...'
#xfileSaveMethod
'Save as method'
#xfileSaveMethodAs
'Save as Method...'
)
"Modified: / 07-12-2017 / 15:32:58 / cg"
!
helpSpec
<resource: #programHelp>
^super helpSpec addPairsFrom:(self helpPairs)
"Modified: / 16-02-2017 / 12:30:55 / cg"
! !
!ImageEditor class methodsFor:'image specs'!
brighterIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self brighterIcon inspect
ImageEditor openOnClass:self andSelector:#brighterIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class brighterIcon'
ifAbsentPut:[(Depth8Image width:14 height:14) bits:(ByteArray fromPackedString:'
@PDA@PDA@PDA@PDA@PG%9^W%9^W%;>?/;>?/;>W%9^W%9^W/;>?/;>?/9^W%9^W%A [/;>?/;>?%9^W%9^TFA.?/;>?/;>W%9^W%9PXF;>?/;>?/9^W%A XF
A XFA [/;>?%9^TFA XFA XFA.?/;>W%9^W%9PXF;>?/;>?/9^W%9^W%A [/;>?/;>?%9^W%9^TFA.?/;>?/;>W%9^W%9^W/;>?/;>?/9^W%9^W%9^?/;>?/
;><A@PDA@PDA@PDA@PDA@P@a')
colorMapFromArray:#[88 88 88 0 0 0 255 0 0 0 255 0 0 0 255 0 255 255 255 255 127 255 0 255 127 0 0 0 127 0 0 0 127 0 127 127 127 127 0 127 0 127 127 127 127 170 170 170 0 0 51 0 0 102 0 0 153 0 0 204 0 51 0 0 51 51 0 51 102 0 51 153 0 51 204 0 51 255 0 102 0 0 102 51 0 102 102 0 102 153 0 102 204 0 102 255 0 153 0 0 153 51 0 153 102 0 153 153 0 153 204 0 153 255 0 204 0 0 204 51 0 204 102 0 204 153 0 204 204 0 204 255 0 255 51 0 255 102 0 255 153 0 255 204 51 0 0 51 0 51 51 0 102 51 0 153 51 0 204 51 0 255 51 51 0 51 51 51 51 51 102 51 51 153 51 51 204 51 51 255 51 102 0 51 102 51 51 102 102 51 102 153 51 102 204 51 102 255 51 153 0 51 153 51 51 153 102 51 153 153 51 153 204 51 153 255 51 204 0 51 204 51 51 204 102 51 204 153 51 204 204 51 204 255 51 255 0 51 255 51 51 255 102 51 255 153 51 255 204 51 255 255 102 0 0 102 0 51 102 0 102 102 0 153 102 0 204 102 0 255 102 51 0 102 51 51 102 51 102 102 51 153 102 51 204 102 51 255 102 102 0 102 102 51 102 102 102 102 102 153 102 102 204 102 102 255 102 153 0 102 153 51 102 153 102 102 153 153 102 153 204 102 153 255 102 204 0 102 204 51 102 204 102 102 204 153 102 204 204 102 204 255 102 255 0 102 255 51 102 255 102 102 255 153 102 255 204 102 255 255 153 0 0 153 0 51 153 0 102 153 0 153 153 0 204 153 0 255 153 51 0 153 51 51 153 51 102 153 51 153 153 51 204 153 51 255 153 102 0 153 102 51 153 102 102 153 102 153 153 102 204 153 102 255 153 153 0 153 153 51 153 153 102 153 153 153 153 153 204 153 153 255 153 204 0 153 204 51 153 204 102 153 204 153 153 204 204 153 204 255 153 255 0 153 255 51 153 255 102 153 255 153 153 255 204 153 255 255 204 0 0 204 0 51 204 0 102 204 0 153 204 0 204 204 0 255 204 51 0 204 51 51 204 51 102 204 51 153 204 51 204 204 51 255 204 102 0 204 102 51 204 102 102 204 102 153 204 102 204 204 102 255 204 153 0 204 153 51 204 153 102 204 153 153 204 153 204 204 153 255 204 204 0 204 204 51 204 204 102 204 204 153 204 204 204 204 204 255 204 255 0 204 255 51 204 255 102 204 255 153 204 255 204 204 255 255 255 0 51 255 0 102 255 0 153 255 0 204 255 51 0 255 51 51 255 51 102 255 51 153 255 51 204 255 51 255 255 102 0 255 102 51 255 102 102 255 102 153 255 102 204 255 102 255 255 153 0 255 153 51 255 153 102 255 153 153 255 153 204 255 153 255 255 204 0 255 204 51 255 204 102 255 204 153 255 204 204 255 204 255 255 255 51 255 255 102 255 255 153 255 255 204 255 255 255 9 9 9 19 19 19 29 29 29 39 39 39 49 49 49 58 58 58 68 68 68 78 78 78 98 98 98 107 107 107 117 117 117 137 137 137 147 147 147 156 156 156 166 166 166]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@C??O?<??3??O?<??3??O?<??3??O?<??0@@@@a'); yourself); yourself]
!
circleIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self circleIcon inspect
ImageEditor openOnClass:self andSelector:#circleIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class circleIcon'
ifAbsentPut:[(Depth1Image width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@QAAD@@@C@X@@@@@@@CLA @@@Q@AD@@@@@a')
colorMapFromArray:#[0 0 0 127 127 127]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@_@CF@PDC@XH@ BB@HLA PD@1 A<@@@@@a'); yourself); yourself]
!
copyIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self copyIcon inspect
ImageEditor openOnClass:self andSelector:#copyIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class copyIcon'
ifAbsentPut:[
(Depth2Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 2 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@** @@J)UUTB*Z*)@*&**PJ)**$B*Z*)@*&**PJ)**$@@Z*)@@F**P@AUUT@@@@@@b');
colorMapFromArray:#[ 0 0 0 0 0 128 255 255 255 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'@@C? O>@??3??O?<??3??O?<??3??@_<A?0@@@@a');
yourself);
yourself
]
!
cropSubImageIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self cropSubImageIcon inspect
ImageEditor openOnClass:self andSelector:#cropSubImageIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class cropSubImageIcon'
ifAbsentPut:[(Depth2Image width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@J**@@BUU @@%UX@@IUV@@BUU @@%UX@@J**@@@@@@@@@@@@@@@@@@b')
colorMapFromArray:#[0 0 0 255 255 255 127 127 127 0 255 0]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'??2@AH@D.@R?9K?$''>R_9I?$''?R_=HA4 @S??@@a'); yourself); yourself]
!
darkerIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self darkerIcon inspect
ImageEditor openOnClass:self andSelector:#darkerIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class darkerIcon'
ifAbsentPut:[(Depth8Image width:14 height:14) bits:(ByteArray fromPackedString:'
@PDA@PDA@PDA@PDA@PG/;>?/;>?/9^W%9^W%9^?/;>?/;>?%9^W%9^W%;>?/;>?/;>W%9^W%9^W/;>?/;>?/9^W%9^W%9^?/;>?/;>?%9^W%9^W%;>?/A XF
A XFA [%9^W/;><FA XFA XFA.W%9^?/;>?/;>?%9^W%9^W%;>?/;>?/;>W%9^W%9^W/;>?/;>?/9^W%9^W%9^?/;>?/;>?%9^W%9^W%;>?/;>?/;>W%9^W%
9^TA@PDA@PDA@PDA@PDA@P@a')
colorMapFromArray:#[88 88 88 0 0 0 255 0 0 0 255 0 0 0 255 0 255 255 255 255 127 255 0 255 127 0 0 0 127 0 0 0 127 0 127 127 127 127 0 127 0 127 127 127 127 170 170 170 0 0 51 0 0 102 0 0 153 0 0 204 0 51 0 0 51 51 0 51 102 0 51 153 0 51 204 0 51 255 0 102 0 0 102 51 0 102 102 0 102 153 0 102 204 0 102 255 0 153 0 0 153 51 0 153 102 0 153 153 0 153 204 0 153 255 0 204 0 0 204 51 0 204 102 0 204 153 0 204 204 0 204 255 0 255 51 0 255 102 0 255 153 0 255 204 51 0 0 51 0 51 51 0 102 51 0 153 51 0 204 51 0 255 51 51 0 51 51 51 51 51 102 51 51 153 51 51 204 51 51 255 51 102 0 51 102 51 51 102 102 51 102 153 51 102 204 51 102 255 51 153 0 51 153 51 51 153 102 51 153 153 51 153 204 51 153 255 51 204 0 51 204 51 51 204 102 51 204 153 51 204 204 51 204 255 51 255 0 51 255 51 51 255 102 51 255 153 51 255 204 51 255 255 102 0 0 102 0 51 102 0 102 102 0 153 102 0 204 102 0 255 102 51 0 102 51 51 102 51 102 102 51 153 102 51 204 102 51 255 102 102 0 102 102 51 102 102 102 102 102 153 102 102 204 102 102 255 102 153 0 102 153 51 102 153 102 102 153 153 102 153 204 102 153 255 102 204 0 102 204 51 102 204 102 102 204 153 102 204 204 102 204 255 102 255 0 102 255 51 102 255 102 102 255 153 102 255 204 102 255 255 153 0 0 153 0 51 153 0 102 153 0 153 153 0 204 153 0 255 153 51 0 153 51 51 153 51 102 153 51 153 153 51 204 153 51 255 153 102 0 153 102 51 153 102 102 153 102 153 153 102 204 153 102 255 153 153 0 153 153 51 153 153 102 153 153 153 153 153 204 153 153 255 153 204 0 153 204 51 153 204 102 153 204 153 153 204 204 153 204 255 153 255 0 153 255 51 153 255 102 153 255 153 153 255 204 153 255 255 204 0 0 204 0 51 204 0 102 204 0 153 204 0 204 204 0 255 204 51 0 204 51 51 204 51 102 204 51 153 204 51 204 204 51 255 204 102 0 204 102 51 204 102 102 204 102 153 204 102 204 204 102 255 204 153 0 204 153 51 204 153 102 204 153 153 204 153 204 204 153 255 204 204 0 204 204 51 204 204 102 204 204 153 204 204 204 204 204 255 204 255 0 204 255 51 204 255 102 204 255 153 204 255 204 204 255 255 255 0 51 255 0 102 255 0 153 255 0 204 255 51 0 255 51 51 255 51 102 255 51 153 255 51 204 255 51 255 255 102 0 255 102 51 255 102 102 255 102 153 255 102 204 255 102 255 255 153 0 255 153 51 255 153 102 255 153 153 255 153 204 255 153 255 255 204 0 255 204 51 255 204 102 255 204 153 255 204 204 255 204 255 255 255 51 255 255 102 255 255 153 255 255 204 255 255 255 9 9 9 19 19 19 29 29 29 39 39 39 49 49 49 58 58 58 68 68 68 78 78 78 98 98 98 107 107 107 117 117 117 137 137 137 147 147 147 156 156 156 166 166 166]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@C??O?<??3??O?<??3??O?<??3??O?<??0@@@@a'); yourself); yourself]
!
defaultIcon
<resource: #programImage>
^ ToolbarIconLibrary startImageEditorIcon
!
editIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self editIcon inspect
ImageEditor openOnClass:self andSelector:#editIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class editIcon'
ifAbsentPut:[(Depth8Image width:15 height:16) bits:(ByteArray fromPackedString:'
@@@@@@@3V41AJ0T@@@@@@@@@@B1(TD4>EP@@@@@@@@@@@CA!!S4X2D@@@@@@@@@@@LV)XTTHX@@@@@@@@@@@@K6UTS$LR@@@@@@@@@@@9OE9VRQ8@@@@@@@@@
@@@8Z5%WR!!P@@@@@@@@@@B8;X5)RG2@@@@@@@@@@@CY-W51SF @@@@@@@@@@@B5)XE4%E0@@@@@@@@@@@B%,Y3TO@@@@@@@@@@@@@BM,M04@@@@@@@@@@@@@
@@ IDP@@@@@@@@@@@@@@@@\K@@@@@@@@@@@@@@@@@A,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')
colorMapFromArray:#[0 0 0 0 137 0 0 206 0 87 87 87 133 60 36 145 109 112 155 31 0 160 115 98 161 124 106 163 140 130 166 46 5 169 113 95 174 218 230 182 93 58 183 59 8 186 100 65 192 147 138 193 129 103 193 132 116 195 100 52 195 120 93 197 82 32 204 208 220 205 177 176 207 90 27 210 109 64 210 140 105 213 175 169 213 217 227 215 172 138 220 114 42 222 120 43 222 209 212 223 137 33 223 153 96 226 180 137 228 90 9 228 142 66 232 174 56 234 184 145 240 178 78 241 195 142 241 212 187 242 102 12 242 177 95 245 202 137 245 209 172 247 181 30 247 183 8 247 198 128 248 122 26 248 194 1 248 198 0 248 201 137 248 203 113 248 214 181 249 193 57 249 210 160 250 206 0 253 222 69 253 226 47 254 116 14 254 128 21 254 136 5 254 141 47 254 144 8 254 147 36 254 147 47 254 158 0 254 158 1 254 159 21 254 161 10 254 162 0 254 165 54 254 165 69 254 167 2 254 167 5 254 171 10 254 176 36 254 177 17 254 178 11 254 181 24 254 184 75 254 184 94 254 187 34 254 191 0 254 191 42 254 191 54 254 194 26 254 197 55 254 201 65 254 203 3 254 203 78 254 203 97 254 207 47 254 209 81 254 212 90 254 213 16 254 214 81 254 216 73 254 219 0 254 220 37 254 223 0 254 225 166 254 226 7 254 226 119 254 231 26 254 231 65 254 231 201 254 239 98]
mask:((Depth1Image width:15 height:16) bits:(ByteArray fromPackedString:'A>@O0@?@G8@_ C<@O0A?@G8@_ A<@G @\@A @D@@@@@b'); yourself); yourself]
!
emptyIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self emptyIcon inspect
ImageEditor openOnClass:self andSelector:#emptyIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class emptyIcon'
ifAbsentPut:[(Depth4Image width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@b')
colorMapFromArray:#[0 0 0]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a'); yourself); yourself]
!
emptyIcon2
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self emptyIcon2 inspect
ImageEditor openOnClass:self andSelector:#emptyIcon2
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class emptyIcon2'
ifAbsentPut:[(Depth4Image width:28 height:14) bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@a')
colorMapFromArray:#[0 0 0]
mask:((Depth1Image width:28 height:14) bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@b'); yourself); yourself]
!
fillCircleIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self fillCircleIcon inspect
ImageEditor openOnClass:self andSelector:#fillCircleIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class fillCircleIcon'
ifAbsentPut:[(Depth1Image width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@QA@@@@@B@H@@@@@@@CH@ @@@@@AD@@@@@a')
colorMapFromArray:#[0 0 0 127 127 127]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@_@C>@_<C?8O? ?>C?8O? _<@? A<@@@@@a'); yourself); yourself]
!
fillDiagonalGradientRectIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self fillDiagonalGradientRectIcon inspect
ImageEditor openOnClass:self andSelector:#fillDiagonalGradientRectIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class fillDiagonalGradientRectIcon'
ifAbsentPut:[(Depth4Image width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@QDQDQD@@@DQDQDQ@@@ADH"H"H@@@QBH"H"@@@DP"L3L0@@ADH#L3L@@@QBH3DQ@@@DP"L1DP@@ADH#LQD@@@@@@@@@
@@@@@@@@@@@b')
colorMapFromArray:#[0 0 0 255 0 0 127 0 0 191 0 0 91 0 0]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@C?0O?@?<C?0O?@?<C?0O?@?<C?0@@@@@@@a'); yourself); yourself]
!
fillGradientRectIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self fillGradientRectIcon inspect
ImageEditor openOnClass:self andSelector:#fillGradientRectIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class fillGradientRectIcon'
ifAbsentPut:[
(Depth4Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#[ 4 ]);
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ADQDQDQ@@@QDQDQDP@@BH"H"H"@@@"H"H"H @@L3L3L3L@@CL3L3L3@@@QDQDQDP@@DQDQDQD@@@@@@@@@
@@@@@@@@@@@b');
colorMapFromArray:#[ 0 0 0 255 0 0 127 0 0 191 0 0 63 0 0 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'@@@@@C?0O?@?<C?0O?@?<C?0O?@?<C?0@@@@@@@a');
yourself);
yourself
]
!
fillHorizontalGradientRectIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self fillHorizontalGradientRectIcon inspect
ImageEditor openOnClass:self andSelector:#fillHorizontalGradientRectIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class fillHorizontalGradientRectIcon'
ifAbsentPut:[(Depth4Image width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@ADH#LQD@@@QBH3DQ@@@DP"L1DP@@ADH#LQD@@@QBH3DQ@@@DP"L1DP@@ADH#LQD@@@QBH3DQ@@@DP"L1DP@@ADH#LQD@@@@@@@@@
@@@@@@@@@@@b')
colorMapFromArray:#[0 0 0 255 0 0 127 0 0 191 0 0 91 0 0]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@C?0O?@?<C?0O?@?<C?0O?@?<C?0@@@@@@@a'); yourself); yourself]
!
fillIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self fillIcon inspect
ImageEditor openOnClass:self andSelector:#fillIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class fillIcon'
ifAbsentPut:[
(Depth2Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 2 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@@@ @@@@*H@@D*(@@DUUP@EAUU@AAEU@@@@U@@DDA@@@@@@@@PP@@@@@@@@@@@@@@b');
colorMapFromArray:#[ 0 0 0 255 0 0 255 255 255 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'C @Q@BN@I<@?8C?0[?!!G<@O P\@@ D@@@@@@@@@a');
yourself);
yourself
]
!
fillRectIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self fillRectIcon inspect
ImageEditor openOnClass:self andSelector:#fillRectIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class fillRectIcon'
ifAbsentPut:[
(Depth1Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 1 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@A@@@@@@@@@@@@@@@@@@@@@@@@@@D@@@@a');
colorMapFromArray:#[ 0 0 0 255 0 0 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'@@@@@C?0O?@?<C?0O?@?<C?0O?@?<C?0@@@@@@@a');
yourself);
yourself
]
!
fillVerticalGradientRectIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self fillVerticalGradientRectIcon inspect
ImageEditor openOnClass:self andSelector:#fillVerticalGradientRectIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class fillVerticalGradientRectIcon'
ifAbsentPut:[(Depth4Image width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@DQDQDQD@@ADQDQDQ@@@H"H"H"H@@BH"H"H"@@@3L3L3L0@@L3L3L3L@@ADQDQDQ@@@QDQDQDP@@DQDQDQD@@@@@@@@@
@@@@@@@@@@@b')
colorMapFromArray:#[0 0 0 255 0 0 127 0 0 191 0 0 91 0 0]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@C?0O?@?<C?0O?@?<C?0O?@?<C?0@@@@@@@a'); yourself); yourself]
!
flipHorizontalIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self flipHorizontalIcon inspect
ImageEditor openOnClass:self andSelector:#flipHorizontalIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class flipHorizontalIcon'
ifAbsentPut:[
(Depth1Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 1 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a');
colorMapFromArray:#[ 0 0 0 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'@@@A@C?8HP )JC$8_?1??C$8JR !!BC?8@P@@@@@a');
yourself);
yourself
]
!
flipVerticalIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self flipVerticalIcon inspect
ImageEditor openOnClass:self andSelector:#flipVerticalIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class flipVerticalIcon'
ifAbsentPut:[
(Depth1Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 1 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a');
colorMapFromArray:#[ 0 0 0 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'@@@C@C?0I9@/4BLPH1A?>BLPH1@/4B^PO?@C@@@a');
yourself);
yourself
]
!
leftMouseKeyIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self leftMouseKeyIcon inspect
ImageEditor openOnClass:self andSelector:#leftMouseKeyIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class leftMouseKeyIcon'
ifAbsentPut:[
(Depth2Image new)
width:16;
height:16;
photometric:(#palette);
bitsPerSample:(#( 2 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@@@@@@@EJJ@@AR" @@T((@@@@@@@B** @@**(@@J**@@B** @@**(@@J**@@@**@@@@@@@@@@@@@@a');
colorMapFromArray:#[ 0 0 0 255 0 0 255 255 255 ];
mask:((ImageMask new)
width:16;
height:16;
bits:(ByteArray
fromPackedString:'@@@@@@?0G? _>A?8G? _>A?8G? _>A?8G? O<@_ @@@b');
yourself);
yourself
]
!
maskOutsideCircleIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self maskOutsideCircleIcon inspect
ImageEditor openOnClass:self andSelector:#maskOutsideCircleIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class maskOutsideCircleIcon'
ifAbsentPut:[(Depth1Image width:14 height:14) bits:(ByteArray fromPackedString:'??3??O1=<A3 CN@L0@S@AL@G8@3 CO@\?G3??@@a')
colorMapFromArray:#[0 0 0 255 127 127]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'??3??O?<??3??O?<??3??O?<??3??O?<??3??@@a'); yourself); yourself]
!
maskOutsideRectangleIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self maskOutsideRectangleIcon inspect
ImageEditor openOnClass:self andSelector:#maskOutsideRectangleIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class maskOutsideRectangleIcon'
ifAbsentPut:[(Depth1Image width:14 height:14) bits:(ByteArray fromPackedString:'??3??L@M0@3@CL@L0@3@CL@L0@3@CL@L??7??@@a')
colorMapFromArray:#[0 0 0 255 127 127]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'??3??O?<??3??O?<??3??O?<??3??O?<??3??@@a'); yourself); yourself]
!
pasteIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self pasteIcon inspect
ImageEditor openOnClass:self andSelector:#pasteIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class pasteIcon'
ifAbsentPut:[
(Depth4Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 4 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@@AU@@@@@CHE@E@2@@@ QDQD@0@@L@@@@@H@@BL#H2L#@@@QDQDQL @@D3L@@@@@@AL3A&Y&X@@SL0Y A&@@D3LF@@A @AL3A&@FX@@QDPY&Y&
@@@@@@@@@@@b');
colorMapFromArray:#[ 0 0 0 0 0 128 128 128 0 128 128 128 212 208 200 255 255 0 255 255 255 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'C0A?8O?0??C?<O?0??C?>O?8??#?>O?8_? G>@@a');
yourself);
yourself
]
!
pasteUnderIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self pasteUnderIcon inspect
ImageEditor openOnClass:self andSelector:#pasteUnderIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class pasteUnderIcon'
ifAbsentPut:[
(Depth4Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 4 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@@AU@@@@@CHE@E@2@@@ QDQD@0@@L@@@@@H@@BL#H2L#@@@QDQDQL @@D3L3LP@@@AL3L3E&X@@SL3L0A&@@D3L3@@A @AL3L3@FX@@QDQDQY&
@@@@@@@@@@@b');
colorMapFromArray:#[ 0 0 0 0 0 128 128 128 0 128 128 128 212 208 200 255 255 0 255 255 255 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'C0A?8O?0??C?<O?0??C?>O?8??#?>O?8_? G>@@a');
yourself);
yourself
]
!
pasteWithMaskIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self pasteWithMaskIcon inspect
ImageEditor openOnClass:self andSelector:#pasteWithMaskIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class pasteWithMaskIcon'
ifAbsentPut:[
(Depth4Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 4 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@@AU@@@@@CHE@E@2@@@ QDQD@0@@L@@@@@H@@BL#H2L#@@@QDQDQL @@D3L@@@@@@AL3@3M&X@@SL0L3A&@@D3LCL0A @AL3@3LFX@@QDPY&Y&
@@@@@@@@@@@b');
colorMapFromArray:#[ 0 0 0 0 0 128 128 128 0 128 128 128 212 208 200 255 255 0 255 255 255 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'C0A?8O?0??C?<O?0??C?>O?8??#?>O?8_? G>@@a');
yourself);
yourself
]
!
pointIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self pointIcon inspect
ImageEditor openOnClass:self andSelector:#pointIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class pointIcon'
ifAbsentPut:[
(Depth1Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 1 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@A@@@@@@@@@@@@@@@C@@@@@@@@@@@@@@@a');
colorMapFromArray:#[ 0 0 0 255 255 255 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'@@@@@@@0@G@@8@G@@8@G@@8@G@@X@@@@@@@@@@@a');
yourself);
yourself
]
!
rectIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self rectIcon inspect
ImageEditor openOnClass:self andSelector:#rectIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class rectIcon'
ifAbsentPut:[
(Depth1Image new)
width:14;
height:14;
photometric:(#palette);
bitsPerSample:(#( 1 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@A@@@@@@@@@@@@@@@C@@@@@@@@@@@@@@@a');
colorMapFromArray:#[ 0 0 0 255 0 0 ];
mask:((ImageMask new)
width:14;
height:14;
bits:(ByteArray
fromPackedString:'@@@@@C?0HA@ DB@PHA@ DB@PHA@ DC?0@@@@@@@a');
yourself);
yourself
]
!
rightMouseKeyIcon
<resource: #image>
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self rightMouseKeyIcon inspect
ImageEditor openOnClass:self andSelector:#rightMouseKeyIcon
Icon flushCachedIcons"
^ Icon constantNamed:'ImageEditor class rightMouseKeyIcon'
ifAbsentPut:[
(Depth2Image new)
width:16;
height:16;
photometric:(#palette);
bitsPerSample:(#( 2 ));
samplesPerPixel:(1);
bits:(ByteArray
fromPackedString:'@@@@@@@@@@@@@@@@@JJE@@B"!!P@@((T@@@@@@@B** @@**(@@J**@@B** @@**(@@J**@@@**@@@@@@@@@@@@@@a');
colorMapFromArray:#[ 0 0 0 255 0 0 255 255 255 ];
mask:((ImageMask new)
width:16;
height:16;
bits:(ByteArray
fromPackedString:'@@@@@@?0G? _>A?8G? _>A?8G? _>A?8G? O<@_ @@@b');
yourself);
yourself
]
!
slightlyBrighterIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self slightlyBrighterIcon inspect
ImageEditor openOnClass:self andSelector:#slightlyBrighterIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class slightlyBrighterIcon'
ifAbsentPut:[(Depth8Image width:14 height:14) bits:(ByteArray fromPackedString:'
@PDA@PDA@PDA@PDA@PD@@@@@@@@@;>?/;>?/;0@@@@@@@@C/;>?/;>?/@@@@@@@@A [/;>?/;><@@@@@@@@FA.?/;>?/;0@@@@@@@@XF;>?/;>?/@@@@A XF
A XFA [/;><@@@@FA XFA XFA.?/;0@@@@@@@@XF;>?/;>?/@@@@@@@@A [/;>?/;><@@@@@@@@FA.?/;>?/;0@@@@@@@@C/;>?/;>?/@@@@@@@@@N?/;>?/
;><A@PDA@PDA@PDA@PDA@P@a')
colorMapFromArray:#[88 88 88 0 0 0 255 0 0 0 255 0 0 0 255 0 255 255 255 255 127 255 0 255 127 0 0 0 127 0 0 0 127 0 127 127 127 127 0 127 0 127 127 127 127 170 170 170 0 0 51 0 0 102 0 0 153 0 0 204 0 51 0 0 51 51 0 51 102 0 51 153 0 51 204 0 51 255 0 102 0 0 102 51 0 102 102 0 102 153 0 102 204 0 102 255 0 153 0 0 153 51 0 153 102 0 153 153 0 153 204 0 153 255 0 204 0 0 204 51 0 204 102 0 204 153 0 204 204 0 204 255 0 255 51 0 255 102 0 255 153 0 255 204 51 0 0 51 0 51 51 0 102 51 0 153 51 0 204 51 0 255 51 51 0 51 51 51 51 51 102 51 51 153 51 51 204 51 51 255 51 102 0 51 102 51 51 102 102 51 102 153 51 102 204 51 102 255 51 153 0 51 153 51 51 153 102 51 153 153 51 153 204 51 153 255 51 204 0 51 204 51 51 204 102 51 204 153 51 204 204 51 204 255 51 255 0 51 255 51 51 255 102 51 255 153 51 255 204 51 255 255 102 0 0 102 0 51 102 0 102 102 0 153 102 0 204 102 0 255 102 51 0 102 51 51 102 51 102 102 51 153 102 51 204 102 51 255 102 102 0 102 102 51 102 102 102 102 102 153 102 102 204 102 102 255 102 153 0 102 153 51 102 153 102 102 153 153 102 153 204 102 153 255 102 204 0 102 204 51 102 204 102 102 204 153 102 204 204 102 204 255 102 255 0 102 255 51 102 255 102 102 255 153 102 255 204 102 255 255 153 0 0 153 0 51 153 0 102 153 0 153 153 0 204 153 0 255 153 51 0 153 51 51 153 51 102 153 51 153 153 51 204 153 51 255 153 102 0 153 102 51 153 102 102 153 102 153 153 102 204 153 102 255 153 153 0 153 153 51 153 153 102 153 153 153 153 153 204 153 153 255 153 204 0 153 204 51 153 204 102 153 204 153 153 204 204 153 204 255 153 255 0 153 255 51 153 255 102 153 255 153 153 255 204 153 255 255 204 0 0 204 0 51 204 0 102 204 0 153 204 0 204 204 0 255 204 51 0 204 51 51 204 51 102 204 51 153 204 51 204 204 51 255 204 102 0 204 102 51 204 102 102 204 102 153 204 102 204 204 102 255 204 153 0 204 153 51 204 153 102 204 153 153 204 153 204 204 153 255 204 204 0 204 204 51 204 204 102 204 204 153 204 204 204 204 204 255 204 255 0 204 255 51 204 255 102 204 255 153 204 255 204 204 255 255 255 0 51 255 0 102 255 0 153 255 0 204 255 51 0 255 51 51 255 51 102 255 51 153 255 51 204 255 51 255 255 102 0 255 102 51 255 102 102 255 102 153 255 102 204 255 102 255 255 153 0 255 153 51 255 153 102 255 153 153 255 153 204 255 153 255 255 204 0 255 204 51 255 204 102 255 204 153 255 204 204 255 204 255 255 255 51 255 255 102 255 255 153 255 255 204 255 255 255 9 9 9 19 19 19 29 29 29 39 39 39 49 49 49 58 58 58 68 68 68 78 78 78 98 98 98 107 107 107 117 117 117 137 137 137 147 147 147 156 156 156 166 166 166]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@C??O?<??3??O?<??3??O?<??3??O?<??0@@@@a'); yourself); yourself]
!
slightlyDarkerIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self slightlyDarkerIcon inspect
ImageEditor openOnClass:self andSelector:#slightlyDarkerIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class slightlyDarkerIcon'
ifAbsentPut:[(Depth8Image width:14 height:14) bits:(ByteArray fromPackedString:'
@PDA@PDA@PDA@PDA@PG/;>?/;>?/@@@@@@@@@N?/;>?/;><@@@@@@@@@;>?/;>?/;0@@@@@@@@C/;>?/;>?/@@@@@@@@@N?/;>?/;><@@@@@@@@@;>?/A XF
A XFA X@@@C/;><FA XFA XFA @@@N?/;>?/;><@@@@@@@@@;>?/;>?/;0@@@@@@@@C/;>?/;>?/@@@@@@@@@N?/;>?/;><@@@@@@@@@;>?/;>?/;0@@@@@@
@@@A@PDA@PDA@PDA@PDA@P@a')
colorMapFromArray:#[88 88 88 0 0 0 255 0 0 0 255 0 0 0 255 0 255 255 255 255 127 255 0 255 127 0 0 0 127 0 0 0 127 0 127 127 127 127 0 127 0 127 127 127 127 170 170 170 0 0 51 0 0 102 0 0 153 0 0 204 0 51 0 0 51 51 0 51 102 0 51 153 0 51 204 0 51 255 0 102 0 0 102 51 0 102 102 0 102 153 0 102 204 0 102 255 0 153 0 0 153 51 0 153 102 0 153 153 0 153 204 0 153 255 0 204 0 0 204 51 0 204 102 0 204 153 0 204 204 0 204 255 0 255 51 0 255 102 0 255 153 0 255 204 51 0 0 51 0 51 51 0 102 51 0 153 51 0 204 51 0 255 51 51 0 51 51 51 51 51 102 51 51 153 51 51 204 51 51 255 51 102 0 51 102 51 51 102 102 51 102 153 51 102 204 51 102 255 51 153 0 51 153 51 51 153 102 51 153 153 51 153 204 51 153 255 51 204 0 51 204 51 51 204 102 51 204 153 51 204 204 51 204 255 51 255 0 51 255 51 51 255 102 51 255 153 51 255 204 51 255 255 102 0 0 102 0 51 102 0 102 102 0 153 102 0 204 102 0 255 102 51 0 102 51 51 102 51 102 102 51 153 102 51 204 102 51 255 102 102 0 102 102 51 102 102 102 102 102 153 102 102 204 102 102 255 102 153 0 102 153 51 102 153 102 102 153 153 102 153 204 102 153 255 102 204 0 102 204 51 102 204 102 102 204 153 102 204 204 102 204 255 102 255 0 102 255 51 102 255 102 102 255 153 102 255 204 102 255 255 153 0 0 153 0 51 153 0 102 153 0 153 153 0 204 153 0 255 153 51 0 153 51 51 153 51 102 153 51 153 153 51 204 153 51 255 153 102 0 153 102 51 153 102 102 153 102 153 153 102 204 153 102 255 153 153 0 153 153 51 153 153 102 153 153 153 153 153 204 153 153 255 153 204 0 153 204 51 153 204 102 153 204 153 153 204 204 153 204 255 153 255 0 153 255 51 153 255 102 153 255 153 153 255 204 153 255 255 204 0 0 204 0 51 204 0 102 204 0 153 204 0 204 204 0 255 204 51 0 204 51 51 204 51 102 204 51 153 204 51 204 204 51 255 204 102 0 204 102 51 204 102 102 204 102 153 204 102 204 204 102 255 204 153 0 204 153 51 204 153 102 204 153 153 204 153 204 204 153 255 204 204 0 204 204 51 204 204 102 204 204 153 204 204 204 204 204 255 204 255 0 204 255 51 204 255 102 204 255 153 204 255 204 204 255 255 255 0 51 255 0 102 255 0 153 255 0 204 255 51 0 255 51 51 255 51 102 255 51 153 255 51 204 255 51 255 255 102 0 255 102 51 255 102 102 255 102 153 255 102 204 255 102 255 255 153 0 255 153 51 255 153 102 255 153 153 255 153 204 255 153 255 255 204 0 255 204 51 255 204 102 255 204 153 255 204 204 255 204 255 255 255 51 255 255 102 255 255 153 255 255 204 255 255 255 9 9 9 19 19 19 29 29 29 39 39 39 49 49 49 58 58 58 68 68 68 78 78 78 98 98 98 107 107 107 117 117 117 137 137 137 147 147 147 156 156 156 166 166 166]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@C??O?<??3??O?<??3??O?<??3??O?<??0@@@@a'); yourself); yourself]
!
smoothIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self smoothIcon inspect
ImageEditor openOnClass:self andSelector:#smoothIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor smoothIcon'
ifAbsentPut:[(Depth4Image new) width:14; height:14; bits:(ByteArray fromPackedString:'@@@@@@@@@@@RH@@@H!!@@HRD@@RD @BHQ@@DRH@@ADP@ADP@@@@@QD@@@@@@@DQ@@@@@@@ADP@@@@@QD@@QD@@BHQ@@DRH@@!!HP@AHR@@D"@@@BHP@@@@@@@@
@@@@@@@@@@@b') ; colorMapFromArray:#[127 126 127 255 0 0 255 255 255]; mask:((ImageMask new) width:14; height:14; bits:(ByteArray fromPackedString:'_?1<_G1<_G1??D_DQ<QG1G?<_G1<_G1<_?0@@@@a') ; yourself); yourself]
!
specialCircleIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self specialCircleIcon inspect
ImageEditor openOnClass:self andSelector:#specialCircleIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class specialCircleIcon'
ifAbsentPut:[(Depth2Image width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@@@@@@@PA@@@RBD@@P@@P@P@@A@D@@@PA@@@D@PHHA@A@@A@@D@A@@@PA@@@@@@@@@@@@@b')
colorMapFromArray:#[0 0 0 255 0 0 127 127 127]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@-@E:@''$D^HQ8!!G"D^HH1@PH@-@@0@@@@@a'); yourself); yourself]
!
specialRectangleIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self specialRectangleIcon inspect
ImageEditor openOnClass:self andSelector:#specialRectangleIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor class specialRectangleIcon'
ifAbsentPut:[(Depth2Image width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@@@@@@@UPAU@DBB@PA@@@D@P@@A@D@@@PA@@@D@PHHA@D@@@PA@@@D@UPAU@@@@@@@@@@@@b')
colorMapFromArray:#[0 0 0 255 0 0 127 127 127]
mask:((ImageMask width:14 height:14) bits:(ByteArray fromPackedString:'@@@@@G-8Q8!!G"D^HQ8!!G"D^HP0!!@BG-8@0@@@@@a'); yourself); yourself]
!
sprayIcon
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self sprayIcon inspect
ImageEditor openOnClass:self andSelector:#sprayIcon
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:'ImageEditor sprayIcon'
ifAbsentPut:[(Depth4Image new) width:14; height:14; bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@P@@@@@@DA@P@@@@@PDA@@@@@@@PDA@@@@@@@PD@@@@"H@@PD@@@H"@@@@@@@ADP@@@@@@@QD@@@@@@@DQ@@@@@@@ADP@@
@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 0 0 255 255 255]; mask:((ImageMask new) width:14; height:14; bits:(ByteArray fromPackedString:'@@@@@@@HA%PF*@ITA2 O%@>@C8@O @>@C8@O @@a') ; yourself); yourself]
! !
!ImageEditor class methodsFor:'interface specs'!
changeHLSDialogSpec
"This resource specification was automatically generated
by the UIPainter of ST/X."
"Do not manually edit this!! If it is corrupted,
the UIPainter may not be able to read the specification."
"
UIPainter new openOnClass:ImageEditor andSelector:#changeHLSDialogSpec
ImageEditor new openInterface:#changeHLSDialogSpec
"
<resource: #canvas>
^
#(FullSpec
name: changeHLSDialogSpec
window:
(WindowSpec
label: 'HLS Edit Dialog'
name: 'HLS Edit Dialog'
min: (Point 10 10)
bounds: (Rectangle 0 0 378 312)
)
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Hue-Shift:'
name: 'HueLabel'
layout: (LayoutFrame 20 0 21 0 187 0 43 0)
translateLabel: true
adjust: right
)
(InputFieldSpec
name: 'HueShiftEntryField'
layout: (LayoutFrame 194 0 21 0 237 0 43 0)
tabable: true
model: hueShiftAmount
type: numberInRange
minValue: 0
maxValue: 360
acceptChannel: acceptChannel
acceptOnPointerLeave: false
)
(ThumbWheelSpec
name: 'HueWheel'
layout: (LayoutFrame 246 0 22 0 363 0 42 0)
model: hueShiftAmount
orientation: horizontal
step: 1
endlessRotation: true
)
(LabelSpec
label: 'Light Factor:'
name: 'LightLabel'
layout: (LayoutFrame 20 0 50 0 187 0 72 0)
translateLabel: true
adjust: right
)
(InputFieldSpec
name: 'LightEntryField'
layout: (LayoutFrame 194 0 50 0 237 0 72 0)
tabable: true
model: lightAmount
type: numberInRange
minValue: 0
maxValue: 1000
acceptChannel: acceptChannel
acceptOnPointerLeave: false
)
(ThumbWheelSpec
name: 'LightWheel'
layout: (LayoutFrame 246 0 51 0 363 0 71 0)
model: lightAmount
orientation: horizontal
stop: 1000
step: 1
)
(LabelSpec
label: 'Saturation Factor:'
name: 'SaturationLabel'
layout: (LayoutFrame 20 0 79 0 187 0 101 0)
translateLabel: true
adjust: right
)
(InputFieldSpec
name: 'SaturationEntryField'
layout: (LayoutFrame 194 0 79 0 237 0 101 0)
tabable: true
model: saturationAmount
type: numberInRange
minValue: 0
maxValue: 1000
acceptChannel: acceptChannel
acceptOnPointerLeave: false
)
(ThumbWheelSpec
name: 'SaturationWheel'
layout: (LayoutFrame 246 0 80 0 363 0 100 0)
model: saturationAmount
orientation: horizontal
stop: 1000
step: 1
)
(LabelSpec
label: 'Color Shift'
name: 'Label2'
layout: (LayoutFrame 5 0 127 0 -15 0.5 149 0)
translateLabel: true
)
(LabelSpec
name: 'HueColorLabel'
layout: (LayoutFrame 18 0.0 150 0 -41 0.5 234 0)
level: -1
backgroundChannel: hlsColor
translateLabel: true
)
(LabelSpec
label: 'Preview'
name: 'Label3'
layout: (LayoutFrame 5 0.5 127 0 -5 1 149 0)
translateLabel: true
)
(LabelSpec
name: 'PreviewLabel'
layout: (LayoutFrame 36 0.5 150 0 -23 1.0 234 0)
level: -1
translateLabel: true
labelChannel: previewImageHolder
)
(HorizontalPanelViewSpec
name: 'HorizontalPanel1'
layout: (LayoutFrame 0 0.0 -30 1 0 1.0 0 1)
horizontalLayout: fitSpace
verticalLayout: center
horizontalSpace: 3
verticalSpace: 3
reverseOrderIfOKAtLeft: true
component:
(SpecCollection
collection: (
(ActionButtonSpec
label: 'Cancel'
name: 'Button1'
translateLabel: true
tabable: true
model: cancel
extent: (Point 183 28)
)
(ActionButtonSpec
label: 'OK'
name: 'Button2'
translateLabel: true
tabable: true
model: accept
extent: (Point 183 28)
)
)
)
keepSpaceForOSXResizeHandleH: true
)
)
)
)
!
cropSpec
"This resource specification was automatically generated
by the UIPainter of ST/X."
"Do not manually edit this!! If it is corrupted,
the UIPainter may not be able to read the specification."
"
UIPainter new openOnClass:ImageEditor andSelector:#cropSpec
ImageEditor new openInterface:#cropSpec
"
<resource: #canvas>
^
#(FullSpec
name: cropSpec
window:
(WindowSpec
label: 'Crop Border(s)'
name: 'Crop Border(s)'
min: (Point 10 10)
bounds: (Rectangle 0 0 364 312)
)
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Left:'
name: 'CropLeftLabel'
layout: (LayoutFrame 14 0 24 0 90 0 46 0)
activeHelpKey: cropLeft
translateLabel: true
adjust: left
)
(InputFieldSpec
name: 'CropLeftEntryField'
layout: (LayoutFrame 95 0 24 0 125 0 46 0)
activeHelpKey: cropLeft
tabable: true
model: cropLeftAmount
type: number
acceptChannel: acceptChannel
acceptOnPointerLeave: false
)
(ActionButtonSpec
label: 'Crop Now'
name: 'CropLeftNowButton'
layout: (LayoutFrame 133 0 21 0 229 0 50 0)
activeHelpKey: cropLeft
translateLabel: true
resizeForLabel: true
tabable: true
model: cropLeftNow
autoRepeat: true
usePreferredWidth: true
)
(ActionButtonSpec
label: 'Auto'
name: 'Button6'
layout: (LayoutFrame 236 0 21 0 289 0 50 0)
activeHelpKey: autoCropLeft
translateLabel: true
resizeForLabel: true
tabable: true
model: autoCropLeft
autoRepeat: true
usePreferredWidth: true
)
(LabelSpec
label: 'Right:'
name: 'CropRightLabel'
layout: (LayoutFrame 14 0 55 0 90 0 77 0)
activeHelpKey: cropRight
translateLabel: true
adjust: left
)
(InputFieldSpec
name: 'CropRightEntryField'
layout: (LayoutFrame 95 0 55 0 125 0 77 0)
activeHelpKey: cropRight
tabable: true
model: cropRightAmount
type: number
acceptChannel: acceptChannel
acceptOnPointerLeave: false
)
(ActionButtonSpec
label: 'Crop Now'
name: 'CropRightButton'
layout: (LayoutFrame 133 0 51 0 229 0 80 0)
activeHelpKey: cropRight
translateLabel: true
resizeForLabel: true
tabable: true
model: cropRightNow
autoRepeat: true
usePreferredWidth: true
)
(ActionButtonSpec
label: 'Auto'
name: 'Button7'
layout: (LayoutFrame 236 0 51 0 289 0 80 0)
activeHelpKey: autoCropRight
translateLabel: true
resizeForLabel: true
tabable: true
model: autoCropRight
autoRepeat: true
usePreferredWidth: true
)
(LabelSpec
label: 'Top:'
name: 'CropTopLabel'
layout: (LayoutFrame 14 0 85 0 90 0 107 0)
activeHelpKey: cropTop
translateLabel: true
adjust: left
)
(InputFieldSpec
name: 'CropTopEntryField'
layout: (LayoutFrame 95 0 85 0 125 0 107 0)
activeHelpKey: cropTop
tabable: true
model: cropTopAmount
type: number
acceptChannel: acceptChannel
acceptOnPointerLeave: false
)
(ActionButtonSpec
label: 'Crop Now'
name: 'CropTopButton'
layout: (LayoutFrame 133 0 81 0 229 0 110 0)
activeHelpKey: cropTop
translateLabel: true
resizeForLabel: true
tabable: true
model: cropTopNow
autoRepeat: true
usePreferredWidth: true
)
(ActionButtonSpec
label: 'Auto'
name: 'Button8'
layout: (LayoutFrame 236 0 81 0 289 0 110 0)
activeHelpKey: autoCropTop
translateLabel: true
resizeForLabel: true
tabable: true
model: autoCropTop
autoRepeat: true
usePreferredWidth: true
)
(LabelSpec
label: 'Bottom:'
name: 'CropBottomLabel'
layout: (LayoutFrame 14 0 115 0 90 0 137 0)
activeHelpKey: cropBottom
translateLabel: true
adjust: left
)
(InputFieldSpec
name: 'CropBottomEntryField'
layout: (LayoutFrame 95 0 115 0 125 0 137 0)
activeHelpKey: cropBottom
tabable: true
model: cropBottomAmount
type: number
acceptChannel: acceptChannel
acceptOnPointerLeave: false
)
(ActionButtonSpec
label: 'Crop Now'
name: 'CropBottomButton'
layout: (LayoutFrame 133 0 111 0 229 0 140 0)
activeHelpKey: cropBottom
translateLabel: true
resizeForLabel: true
tabable: true
model: cropBottomNow
autoRepeat: true
usePreferredWidth: true
)
(ActionButtonSpec
label: 'Auto'
name: 'Button9'
layout: (LayoutFrame 236 0 111 0 289 0 140 0)
activeHelpKey: autoCropBottom
translateLabel: true
resizeForLabel: true
tabable: true
model: autoCropBottom
autoRepeat: true
usePreferredWidth: true
)
(ActionButtonSpec
label: 'All'
name: 'Button4'
layout: (LayoutFrame 133 0 148 0 229 0 176 0)
activeHelpKey: cropAll
translateLabel: true
resizeForLabel: true
tabable: true
model: applyCropAction
)
(HorizontalPanelViewSpec
name: 'HorizontalPanel1'
layout: (LayoutFrame 0 0.0 -30 1 0 1.0 0 1)
visibilityChannel: cropBoxIsDialog
horizontalLayout: fitSpace
verticalLayout: center
horizontalSpace: 3
verticalSpace: 3
reverseOrderIfOKAtLeft: true
component:
(SpecCollection
collection: (
(ActionButtonSpec
label: 'Cancel'
name: 'Button1'
translateLabel: true
resizeForLabel: true
tabable: true
model: cancel
extent: (Point 116 28)
)
(ActionButtonSpec
label: 'Apply'
name: 'Button3'
translateLabel: true
resizeForLabel: true
tabable: true
model: applyCropAction
extent: (Point 116 28)
)
(ActionButtonSpec
label: 'OK'
name: 'Button2'
translateLabel: true
resizeForLabel: true
tabable: true
model: accept
extent: (Point 116 28)
)
)
)
)
(ActionButtonSpec
label: 'All'
name: 'Button10'
layout: (LayoutFrame 236 0 148 0 289 0 176 0)
activeHelpKey: autoCropAll
translateLabel: true
resizeForLabel: true
tabable: true
model: autoCropAll
)
)
)
)
!
dialogSpecForNewImage
"This resource specification was automatically generated
by the UIPainter of ST/X."
"Do not manually edit this!! If it is corrupted,
the UIPainter may not be able to read the specification."
"
UIPainter new openOnClass:ImageEditor andSelector:#dialogSpecForNewImage
ImageEditor new openInterface:#dialogSpecForNewImage
"
<resource: #canvas>
^
#(FullSpec
name: dialogSpecForNewImage
window:
(WindowSpec
label: 'New Image'
name: 'New Image'
min: (Point 10 10)
bounds: (Rectangle 0 0 301 119)
)
component:
(SpecCollection
collection: (
(ViewSpec
name: 'View'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 -35 1.0)
level: 1
component:
(SpecCollection
collection: (
(FramedBoxSpec
label: 'Size'
name: 'framedBox1'
layout: (LayoutFrame 1 0.0 7 0.0 0 0.40000000000000002 76 0)
style: (FontDescription helvetica medium roman 12)
labelPosition: topLeft
translateLabel: true
component:
(SpecCollection
collection: (
(ComboBoxSpec
name: 'defaultSizesComboBox'
layout: (LayoutFrame 0 0.0 10 0.0 0 1 35 0.0)
model: selectionOfSize
type: string
acceptOnPointerLeave: false
comboList: listOfDefaultSizes
isFilenameBox: false
)
)
)
)
(FramedBoxSpec
label: 'Color Map'
name: 'framedBox2'
layout: (LayoutFrame 0 0.40000000000000002 7 0.0 -1 1.0 76 0)
style: (FontDescription helvetica medium roman 12)
labelPosition: topLeft
translateLabel: true
component:
(SpecCollection
collection: (
(ComboListSpec
name: 'colorMapComboBox'
layout: (LayoutFrame 0 0.0 10 0.0 0 1 35 0.0)
model: selectionOfColorMap
comboList: listOfColorMaps
useIndex: false
hidePullDownMenuButton: false
)
)
)
)
)
)
)
(UISubSpecification
name: 'windowSpecForCommitWithoutChannels'
layout: (LayoutFrame 2 0.0 -37 1 -2 1.0 -2 1.0)
minorKey: windowSpecForCommitWithoutChannels
keepSpaceForOSXResizeHandleH: true
)
)
)
)
!
floodFillToleranceSpec
"This resource specification was automatically generated
by the UIPainter of ST/X."
"Do not manually edit this!! If it is corrupted,
the UIPainter may not be able to read the specification."
"
UIPainter new openOnClass:ImageEditor andSelector:#floodFillToleranceSpec
ImageEditor new openInterface:#floodFillToleranceSpec
"
<resource: #canvas>
^
#(FullSpec
name: floodFillToleranceSpec
window:
(WindowSpec
label: 'Flood Fill Tolerance'
name: 'Flood Fill Tolerance'
min: (Point 10 10)
bounds: (Rectangle 0 0 364 312)
)
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Flood Fill Tolerance:'
name: 'Label1'
layout: (LayoutFrame 14 0 10 0 242 0 32 0)
activeHelpKey: floodFillMaxError
visibilityChannel: cropBoxIsNotDialog
translateLabel: true
adjust: left
)
(LabelSpec
label: 'Hue:'
name: 'Label2'
layout: (LayoutFrame 29 0 38 0 127 0 60 0)
activeHelpKey: floodFillMaxError
visibilityChannel: cropBoxIsNotDialog
translateLabel: true
adjust: left
)
(InputFieldSpec
name: 'EntryField2'
layout: (LayoutFrame 132 0 38 0 190 0 60 0)
activeHelpKey: floodFillMaxError
visibilityChannel: cropBoxIsNotDialog
tabable: true
model: floodFillMaxHueError
type: number
acceptChannel: acceptChannel
acceptOnPointerLeave: true
)
(LabelSpec
label: 'Light:'
name: 'Label3'
layout: (LayoutFrame 29 0 64 0 127 0 86 0)
activeHelpKey: floodFillMaxError
visibilityChannel: cropBoxIsNotDialog
translateLabel: true
adjust: left
)
(InputFieldSpec
name: 'EntryField3'
layout: (LayoutFrame 132 0 64 0 190 0 86 0)
activeHelpKey: floodFillMaxError
visibilityChannel: cropBoxIsNotDialog
tabable: true
model: floodFillMaxLightError
type: number
acceptChannel: acceptChannel
acceptOnPointerLeave: true
)
(HorizontalPanelViewSpec
name: 'HorizontalPanel1'
layout: (LayoutFrame 0 0.0 -30 1 0 1.0 0 1)
visibilityChannel: cropBoxIsDialog
horizontalLayout: fitSpace
verticalLayout: center
horizontalSpace: 3
verticalSpace: 3
reverseOrderIfOKAtLeft: true
component:
(SpecCollection
collection: (
(ActionButtonSpec
label: 'Cancel'
name: 'Button1'
translateLabel: true
resizeForLabel: true
tabable: true
model: cancel
extent: (Point 116 28)
)
(ActionButtonSpec
label: 'Apply'
name: 'Button3'
translateLabel: true
resizeForLabel: true
tabable: true
model: applyCropAction
extent: (Point 116 28)
)
(ActionButtonSpec
label: 'OK'
name: 'Button2'
translateLabel: true
resizeForLabel: true
tabable: true
model: accept
extent: (Point 116 28)
)
)
)
)
)
)
)
!
shiftDialogSpec
"This resource specification was automatically generated
by the UIPainter of ST/X."
"Do not manually edit this!! If it is corrupted,
the UIPainter may not be able to read the specification."
"
UIPainter new openOnClass:ImageEditor andSelector:#shiftDialogSpec
ImageEditor new openInterface:#shiftDialogSpec
"
<resource: #canvas>
^
#(FullSpec
name: shiftDialogSpec
window:
(WindowSpec
label: 'Shift'
name: 'Shift'
min: (Point 10 10)
bounds: (Rectangle 14 46 259 229)
)
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Amount:'
name: 'AmountLabel'
layout: (LayoutFrame 14 0 21 0 90 0 43 0)
translateLabel: true
adjust: right
)
(InputFieldSpec
name: 'AmountEntryField'
layout: (LayoutFrame 95 0 21 0 139 0 43 0)
tabable: true
model: shiftAmount
type: number
acceptChannel: acceptChannel
acceptOnPointerLeave: false
)
(HorizontalPanelViewSpec
name: 'HorizontalPanel1'
layout: (LayoutFrame 0 0.0 -30 1 0 1.0 0 1)
horizontalLayout: fitSpace
verticalLayout: center
horizontalSpace: 3
verticalSpace: 3
reverseOrderIfOKAtLeft: true
component:
(SpecCollection
collection: (
(ActionButtonSpec
label: 'Cancel'
name: 'Button1'
translateLabel: true
tabable: true
model: cancel
extent: (Point 118 22)
)
(ActionButtonSpec
label: 'OK'
name: 'Button2'
translateLabel: true
tabable: true
model: accept
extent: (Point 118 22)
)
)
)
)
(ArrowButtonSpec
name: 'upArrowButton'
layout: (LayoutFrame 105 0 63 0 127 0 85 0)
model: shiftUpNow
isTriggerOnDown: true
autoRepeat: true
actionValue: ''
direction: up
)
(ArrowButtonSpec
name: 'leftArrowButton'
layout: (LayoutFrame 84 0 86 0 106 0 108 0)
model: shiftLeftNow
isTriggerOnDown: true
autoRepeat: true
actionValue: ''
direction: left
)
(ArrowButtonSpec
name: 'rightArrowButton'
layout: (LayoutFrame 126 0 86 0 148 0 108 0)
model: shiftRightNow
isTriggerOnDown: true
autoRepeat: true
actionValue: ''
direction: right
)
(ArrowButtonSpec
name: 'downArrowButton'
layout: (LayoutFrame 105 0 107 0 127 0 129 0)
model: shiftDownNow
isTriggerOnDown: true
autoRepeat: true
actionValue: ''
direction: down
)
(CheckBoxSpec
label: 'Wrap'
name: 'CheckBox1'
layout: (LayoutFrame 153 0 22 0 289 0 44 0)
model: wrap
translateLabel: true
)
)
)
)
!
uncropSpec
"This resource specification was automatically generated
by the UIPainter of ST/X."
"Do not manually edit this!! If it is corrupted,
the UIPainter may not be able to read the specification."
"
UIPainter new openOnClass:ImageEditor andSelector:#uncropSpec
ImageEditor new openInterface:#uncropSpec
"
<resource: #canvas>
^
#(FullSpec
name: uncropSpec
window:
(WindowSpec
label: 'Add Border(s)'
name: 'Add Border(s)'
min: (Point 10 10)
max: (Point 800 478)
bounds: (Rectangle 0 0 261 228)
)
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Left:'
name: 'Label1'
layout: (LayoutFrame 14 0 21 0 90 0 43 0)
translateLabel: true
adjust: right
)
(InputFieldSpec
name: 'EntryField1'
layout: (LayoutFrame 95 0 21 0 132 0 43 0)
model: cropLeftAmount
type: number
acceptOnPointerLeave: false
)
(LabelSpec
label: 'Right:'
name: 'Label2'
layout: (LayoutFrame 14 0 51 0 90 0 73 0)
translateLabel: true
adjust: right
)
(InputFieldSpec
name: 'EntryField2'
layout: (LayoutFrame 95 0 51 0 132 0 73 0)
model: cropRightAmount
type: number
acceptOnPointerLeave: false
)
(LabelSpec
label: 'Top:'
name: 'Label3'
layout: (LayoutFrame 14 0 81 0 90 0 103 0)
translateLabel: true
adjust: right
)
(InputFieldSpec
name: 'EntryField3'
layout: (LayoutFrame 95 0 81 0 132 0 103 0)
model: cropTopAmount
type: number
acceptOnPointerLeave: false
)
(LabelSpec
label: 'Bottom:'
name: 'Label4'
layout: (LayoutFrame 14 0 111 0 90 0 133 0)
translateLabel: true
adjust: right
)
(InputFieldSpec
name: 'EntryField4'
layout: (LayoutFrame 95 0 111 0 132 0 133 0)
model: cropBottomAmount
type: number
acceptOnPointerLeave: false
)
(HorizontalPanelViewSpec
name: 'HorizontalPanel1'
layout: (LayoutFrame 0 0.0 -30 1 0 1.0 0 1)
horizontalLayout: fitSpace
verticalLayout: center
horizontalSpace: 3
verticalSpace: 3
reverseOrderIfOKAtLeft: true
component:
(SpecCollection
collection: (
(ActionButtonSpec
label: 'Cancel'
name: 'Button1'
translateLabel: true
model: cancel
extent: (Point 124 22)
)
(ActionButtonSpec
label: 'OK'
name: 'Button2'
translateLabel: true
model: accept
extent: (Point 125 22)
)
)
)
)
)
)
)
!
windowSpec
"This resource specification was automatically generated
by the UIPainter of ST/X."
"Do not manually edit this!! If it is corrupted,
the UIPainter may not be able to read the specification."
"
UIPainter new openOnClass:ImageEditor andSelector:#windowSpec
ImageEditor new openInterface:#windowSpec
ImageEditor open
"
<resource: #canvas>
^
#(FullSpec
name: windowSpec
uuid: 'ea3a8340-1e4a-11b2-83b1-485b39758412'
window:
(WindowSpec
label: 'Image Editor'
name: 'Image Editor'
uuid: 'ea3a8bec-1e4a-11b2-83b1-485b39758412'
min: (Point 800 400)
bounds: (Rectangle 0 0 800 446)
menu: menu
icon: defaultIcon
)
component:
(SpecCollection
collection: (
(MenuPanelSpec
name: 'menuToolbarView'
layout: (LayoutFrame 0 0.0 0 0 0 1.0 32 0)
style: (FontDescription helvetica medium roman 10 #'iso10646-1' nil nil)
uuid: 'ea3a98c6-1e4a-11b2-83b1-485b39758412'
menu: menuToolbar
showSeparatingLines: true
)
(VariableHorizontalPanelSpec
name: 'mainPanel'
layout: (LayoutFrame 0 0.0 34 0.0 0 1.0 -26 1.0)
uuid: 'ea3a9eca-1e4a-11b2-83b1-485b39758412'
snapMode: both
barLevel: 0
component:
(SpecCollection
collection: (
(ViewSpec
name: 'leftView'
uuid: 'ea3aa3d4-1e4a-11b2-83b1-485b39758412'
level: 1
component:
(SpecCollection
collection: (
(VariableVerticalPanelSpec
name: 'verticalPanel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
uuid: 'ea3aa672-1e4a-11b2-83b1-485b39758412'
level: 0
snapMode: both
component:
(SpecCollection
collection: (
(ViewSpec
name: 'ColorAnCropBox'
uuid: 'ea3aa992-1e4a-11b2-83b1-485b39758412'
component:
(SpecCollection
collection: (
(TabViewSpec
name: 'TabHeader1'
layout: (LayoutFrame 0 0 0 0 0 1 36 0)
uuid: 'ea3aab9a-1e4a-11b2-83b1-485b39758412'
model: colorCropTabSelectionIndexHolder
menu: colorCropTabLabelList
useIndex: true
translateLabel: true
)
(ViewSpec
name: 'ColorBox'
layout: (LayoutFrame 0 0 36 0 0 1 0 1)
uuid: 'ea3ab0ae-1e4a-11b2-83b1-485b39758412'
visibilityChannel: colorBoxVisibleHolder
component:
(SpecCollection
collection: (
(MenuPanelSpec
name: 'MouseButtonColorToolBar'
layout: (LayoutFrame 0 0.0 0 0 0 1.0 24 0)
uuid: 'ea3ab2d4-1e4a-11b2-83b1-485b39758412'
level: 0
menu: menuMouseButtonColors
)
(LabelSpec
label: 'Label'
name: 'Label1'
layout: (LayoutFrame -160 1 0 0 -104 1 22 0)
activeHelpKey: drawingAlpha
uuid: 'ea3ab590-1e4a-11b2-83b1-485b39758412'
visibilityChannel: alphaVisibleHolder
translateLabel: true
labelChannel: alphaText
)
(InputFieldSpec
name: 'EntryField1'
layout: (LayoutFrame -106 1 2 0 -56 1 22 0)
activeHelpKey: drawingAlpha
uuid: 'ea3aba90-1e4a-11b2-83b1-485b39758412'
visibilityChannel: alphaVisibleHolder
model: alphaHolder
type: numberInRange
acceptOnReturn: true
acceptOnTab: true
numChars: 3
minValue: 0
maxValue: 100
acceptOnPointerLeave: true
)
(ViewSpec
name: 'Box1'
layout: (LayoutFrame -40 1.0 4 0 -26 1.0 18 0)
activeHelpKey: drawingColor1
uuid: 'ea3ac1c0-1e4a-11b2-83b1-485b39758412'
level: -1
backgroundChannel: drawingColor1Holder
)
(ViewSpec
name: 'Box2'
layout: (LayoutFrame -25 1.0 4 0 -11 1.0 18 0)
activeHelpKey: drawingColor2
uuid: 'ea3ac418-1e4a-11b2-83b1-485b39758412'
level: -1
backgroundChannel: drawingColor2Holder
)
(DataSetSpec
name: 'colorDataSetView'
layout: (LayoutFrame 0 0.0 26 0.0 0 1.0 0 1.0)
activeHelpKey: colorMapTable
style: (FontDescription helvetica medium roman 10 #'iso10646-1' nil nil)
uuid: 'ea3ac652-1e4a-11b2-83b1-485b39758412'
model: selectedColors
menu: colorMapMenuHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
miniScrollerVertical: true
dataList: listOfColors
has3Dseparators: true
doubleClickSelector: doubleClickOnColor:
columnHolder: colorTableColumns
multipleSelectOk: true
verticalSpacing: 1
columnAdaptor: colorColumnAdaptor
)
)
)
)
(ViewSpec
name: 'FloodFillBox'
layout: (LayoutFrame 0 0 36 0 0 1 0 1)
uuid: 'ea3acfda-1e4a-11b2-83b1-485b39758412'
visibilityChannel: floodFillBoxVisibleHolder
component:
(SpecCollection
collection: (
(UISubSpecification
name: 'SubSpecification2'
layout: (LayoutFrame 0 0 0 0 0 1 0 1)
uuid: 'ea3ad21e-1e4a-11b2-83b1-485b39758412'
minorKey: floodFillToleranceSpec
)
)
)
)
(ViewSpec
name: 'CropBox'
layout: (LayoutFrame 0 0 36 0 0 1 0 1)
uuid: 'ea3ad552-1e4a-11b2-83b1-485b39758412'
visibilityChannel: cropBoxVisibleHolder
component:
(SpecCollection
collection: (
(UISubSpecification
name: 'SubSpecification1'
layout: (LayoutFrame 0 0 0 0 0 1 0 1)
uuid: 'ea3ad76e-1e4a-11b2-83b1-485b39758412'
minorKey: cropSpec
)
)
)
)
)
)
)
(ArbitraryComponentSpec
name: 'imagePreView'
activeHelpKey: previewView
uuid: 'ea3ad9a8-1e4a-11b2-83b1-485b39758412'
menu: previewMenu
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: false
miniScrollerVertical: false
hasBorder: false
component: ImageView
)
)
)
handles: (Any 0.5 1.0)
)
)
)
)
(ViewSpec
name: 'rightView'
uuid: 'ea3ade8a-1e4a-11b2-83b1-485b39758412'
component:
(SpecCollection
collection: (
(MenuPanelSpec
name: 'ToolBar1'
layout: (LayoutFrame 0 0 0 0.0 28 0 0 1.0)
uuid: 'ea3ae0b0-1e4a-11b2-83b1-485b39758412'
level: 1
menu: toolsMenuToolbar
verticalLayout: true
centerItems: true
textDefault: true
)
(ViewSpec
name: 'editingView'
layout: (LayoutFrame 28 0.0 0 0.0 0 1.0 0 1.0)
uuid: 'ea3ae3bc-1e4a-11b2-83b1-485b39758412'
level: 1
component:
(SpecCollection
collection: (
(ArbitraryComponentSpec
name: 'imageEditView'
layout: (LayoutFrame 2 0.0 2 0.0 -2 1.0 -24 1.0)
uuid: 'ea3ae5ec-1e4a-11b2-83b1-485b39758412'
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
hasBorder: false
component: ImageEditView
)
(LabelSpec
name: 'coordLabel'
layout: (LayoutFrame 2 0.0 -22 1 -83 1.0 0 1.0)
uuid: 'ea3ae8da-1e4a-11b2-83b1-485b39758412'
level: -1
translateLabel: true
labelChannel: imageInfoHolder
resizeForLabel: false
adjust: left
)
(ArrowButtonSpec
name: 'magnifyDownButton'
layout: (LayoutFrame -80 1 -22 1 -58 1 0 1)
activeHelpKey: magnifyImageDown
uuid: 'ea3aebd2-1e4a-11b2-83b1-485b39758412'
translateLabel: true
model: doMagnifyDown
enableChannel: imageIsLoadedHolder
isTriggerOnDown: true
autoRepeat: true
direction: left
)
(ArrowButtonSpec
name: 'magnifyUpButton'
layout: (LayoutFrame -24 1 -22 1 -2 1 0 1)
activeHelpKey: magnifyImageUp
uuid: 'ea3af26c-1e4a-11b2-83b1-485b39758412'
translateLabel: true
model: doMagnifyUp
enableChannel: imageIsLoadedHolder
isTriggerOnDown: true
autoRepeat: true
direction: right
)
(InputFieldSpec
name: 'magnificationInputField'
layout: (LayoutFrame -57 1 -22 1 -26 1 0 1)
activeHelpKey: magnificationNumber
uuid: 'ea3af62c-1e4a-11b2-83b1-485b39758412'
enableChannel: imageIsLoadedHolder
model: magnificationHolder
type: numberInRange
acceptOnReturn: true
acceptOnTab: true
numChars: 2
minValue: 1
maxValue: 99
acceptOnPointerLeave: true
)
)
)
)
)
)
)
)
)
handles: (Any 0.47999999999999998 1.0)
)
(UISubSpecification
name: 'infoBarSubSpec'
layout: (LayoutFrame 0 0.0 -24 1 0 1.0 0 1.0)
uuid: 'ea3afaf0-1e4a-11b2-83b1-485b39758412'
majorKey: ToolApplicationModel
minorKey: windowSpecForInfoBar
)
)
)
)
! !
!ImageEditor class methodsFor:'menu specs'!
colorMapMenu
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#colorMapMenu
(Menu new fromLiteralArrayEncoding:(ImageEditor colorMapMenu)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
enabled: canAddColorToColormapHolder
label: 'Add Color'
itemValue: addColorToColormap
translateLabel: true
)
(MenuItem
enabled: canAddColorToColormapHolder
label: 'Add & Paste Color'
itemValue: addPastedColorToColormap
translateLabel: true
)
(MenuItem
enabled: canAddColorToColormapHolder
label: 'Pick and Add Color...'
itemValue: pickAndAddColorToColormap
translateLabel: true
)
(MenuItem
label: '-'
)
(MenuItem
enabled: hasColormapAndSingleColorSelectedHolder
label: 'Cut Color'
itemValue: cutColorFromColormap
translateLabel: true
isVisible: false
)
(MenuItem
enabled: hasSingleColorSelectedHolder
label: 'Copy Color'
itemValue: copyColorFromColormap
translateLabel: true
shortcutKey: Copy
)
(MenuItem
enabled: hasColormapAndSingleWritableColorSelectedHolder
label: 'Pick and Paste Color...'
itemValue: pickAndPasteColor
translateLabel: true
)
(MenuItem
enabled: canChangeColorInColormapHolder
label: 'Paste Color'
itemValue: pasteColorIntoColormap
translateLabel: true
shortcutKey: Paste
)
(MenuItem
label: '-'
)
(MenuItem
enabled: hasColormapAndSingleWritableColorSelectedHolder
label: 'Edit Color...'
itemValue: editSelectedColor
translateLabel: true
)
(MenuItem
enabled: hasColormapAndColorSelected
label: 'Brighter'
itemValue: makeSelectedColorBrighter
translateLabel: true
)
(MenuItem
enabled: hasColormapAndColorSelected
label: 'Darker'
itemValue: makeSelectedColorDarker
translateLabel: true
)
(MenuItem
enabled: hasColormapAndColorSelected
label: 'Make Gray'
itemValue: makeSelectedColorGray
translateLabel: true
)
(MenuItem
enabled: hasColormapAndSingleWritableColorSelectedHolder
label: 'Color Shift'
itemValue: makeSelectedColorShifted
translateLabel: true
)
(MenuItem
label: '-'
)
(MenuItem
enabled: hasSingleColorSelectedHolder
label: 'Inspect Color'
itemValue: inspectColor
translateLabel: true
)
(MenuItem
enabled: imageHasColormapHolder
label: 'Inspect Colormap'
itemValue: inspectColormap
translateLabel: true
)
)
nil
nil
)
"Modified: / 08-10-2017 / 15:02:33 / cg"
!
menu
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#menu
(Menu new fromLiteralArrayEncoding:(ImageEditor menu)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
label: '&File'
translateLabel: true
submenuChannel: menuFile
"/ keepLinkedMenu: true
)
(MenuItem
label: 'Edit'
translateLabel: true
submenuChannel: menuEdit
"/ keepLinkedMenu: true
)
(MenuItem
label: 'Mode'
translateLabel: true
submenuChannel: modeMenu
isVisible: modeMenuVisible
)
(MenuItem
label: 'Image'
translateLabel: true
submenuChannel: menuColors
)
(MenuItem
label: 'Settings'
translateLabel: true
submenuChannel: menuSettings
)
(MenuItem
label: 'History'
translateLabel: true
isVisible: isStandAlone
submenuChannel: menuHistory
)
(MenuItem
label: 'MENU_Help'
translateLabel: true
startGroup: conditionalRight
submenuChannel: menuHelp
)
)
nil
nil
)
"Modified: / 23-10-2017 / 10:39:43 / cg"
!
menuColors
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#menuColors
(Menu new fromLiteralArrayEncoding:(ImageEditor menuColors)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
enabled: imageIsLoaded
label: 'Depth'
submenu:
(Menu
(
(MenuItem
activeHelpKey: colorMap1
enabled: imageIsLoadedAndNotReadonlyHolder
label: '1-Plane'
itemValue: colorMapMode:
argument: depth1
choice: colorMapMode
choiceValue: depth1
)
(MenuItem
activeHelpKey: colorMap1M
enabled: imageIsLoadedAndNotReadonlyHolder
label: '1-Plane + Mask'
itemValue: colorMapMode:
argument: masked1
choice: colorMapMode
choiceValue: masked1
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: colorMap2
enabled: imageIsLoadedAndNotReadonlyHolder
label: '2-Plane'
itemValue: colorMapMode:
argument: depth2
choice: colorMapMode
choiceValue: depth2
)
(MenuItem
activeHelpKey: colorMap2M
enabled: imageIsLoadedAndNotReadonlyHolder
label: '2-Plane + Mask'
itemValue: colorMapMode:
argument: masked2
choice: colorMapMode
choiceValue: masked2
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: colorMap4
enabled: imageIsLoadedAndNotReadonlyHolder
label: '4-Plane'
itemValue: colorMapMode:
argument: depth4
choice: colorMapMode
choiceValue: depth4
)
(MenuItem
activeHelpKey: colorMap4M
enabled: imageIsLoadedAndNotReadonlyHolder
label: '4-Plane + Mask'
itemValue: colorMapMode:
argument: masked4
choice: colorMapMode
choiceValue: masked4
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: colorMap8
enabled: imageIsLoadedAndNotReadonlyHolder
label: '8-Plane'
itemValue: colorMapMode:
argument: depth8
choice: colorMapMode
choiceValue: depth8
)
(MenuItem
activeHelpKey: colorMap8M
enabled: imageIsLoadedAndNotReadonlyHolder
label: '8-Plane + Mask'
itemValue: colorMapMode:
argument: masked8
choice: colorMapMode
choiceValue: masked8
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: colorMap16
enabled: imageIsLoadedAndNotReadonlyHolder
label: '16-Plane'
itemValue: colorMapMode:
argument: depth16
choice: colorMapMode
choiceValue: depth16
)
(MenuItem
activeHelpKey: colorMap16M
enabled: imageIsLoadedAndNotReadonlyHolder
label: '16-Plane + Mask'
itemValue: colorMapMode:
argument: masked16
choice: colorMapMode
choiceValue: masked16
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: colorMap24
enabled: imageIsLoadedAndNotReadonlyHolder
label: '24-Plane'
itemValue: colorMapMode:
argument: depth24
choice: colorMapMode
choiceValue: depth24
)
(MenuItem
activeHelpKey: colorMap24M
enabled: imageIsLoadedAndNotReadonlyHolder
label: '24-Plane + Mask'
itemValue: colorMapMode:
argument: masked24
choice: colorMapMode
choiceValue: masked24
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: colorMap32
enabled: imageIsLoadedAndNotReadonlyHolder
label: '32-Plane (rgba)'
itemValue: colorMapMode:
argument: depth32
choice: colorMapMode
choiceValue: depth32
)
)
nil
nil
)
)
(MenuItem
enabled: imageIsLoadedAndNotReadonlyHolder
label: 'ColorMap'
submenu:
(Menu
(
(MenuItem
activeHelpKey: compressColormap
enabled: hasColormapHolder
label: 'Compress Colormap'
itemValue: #'menu_compressColorMap'
)
(MenuItem
enabled: hasColormapHolder
label: 'Sort Colormap'
itemValue: #'menu_sortColorMap'
)
(MenuItem
label: 'Reduce Number of Colors by Rounding...'
itemValue: reduceNumberOfColors2
)
(MenuItem
label: 'Reduce Number of Colors by Masking Bits...'
itemValue: reduceNumberOfColors
)
)
nil
nil
)
)
(MenuItem
enabled: imageIsLoadedAndNotReadonlyHolder
label: 'Process'
submenu:
(Menu
(
(MenuItem
label: 'Negative'
itemValue: makeNegative
)
(MenuItem
label: 'Invert Pixel Bits'
itemValue: makeInvertedBits
isVisible: hasColormap
)
(MenuItem
label: '-'
)
(MenuItem
enabled: allowedToChangeImageDimensionAndDepth
label: 'Make dithered 8Bit Palette'
itemValue: makeDitheredPaletteImage
isVisible: false
)
(MenuItem
label: 'Dither to Depth...'
itemValue: ditherToDepth
)
(MenuItem
label: 'Threshold to Depth...'
itemValue: thresholdToDepth
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Make Monochrome...'
itemValue: makeMonochromeImage
)
(MenuItem
label: 'Make GrayScale (same Depth)'
itemValue: makeGrayScaleImage
)
(MenuItem
label: 'Make GrayScale with Depth (Dither)...'
itemValue: ditherGrayToDepth
)
(MenuItem
label: 'Make GrayScale with Depth (Threshold)...'
itemValue: thresholdGrayToDepth
)
(MenuItem
label: 'Make GrayScale with N Gray Colors (Dither)...'
itemValue: ditherToNumberOfGrayColors
)
(MenuItem
label: 'Make GrayScale with N Gray Colors (Threshold)...'
itemValue: thresholdToNumberOfGrayColors
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Make Slightly Brighter'
itemValue: makeSlightlyBrighter
)
(MenuItem
label: 'Make Brighter'
itemValue: makeBrighter
)
(MenuItem
label: 'Make Slightly Darker'
itemValue: makeSlightlyDarker
)
(MenuItem
label: 'Make Darker'
itemValue: makeDarker
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Change HLS...'
itemValue: changeHLS
)
(MenuItem
label: 'Colorize...'
itemValue: colorize
)
(MenuItem
enabled: imageIsLoadedHolder
label: 'Brighten'
itemValue: doBrightenImage
)
(MenuItem
enabled: imageIsLoadedHolder
label: 'Darken'
itemValue: doDarkenImage
)
)
nil
nil
)
)
(MenuItem
enabled: imageIsLoadedAndNotReadonlyHolder
label: 'Mask'
submenu:
(Menu
(
(MenuItem
activeHelpKey: copyMask
enabled: hasMask
label: 'Copy Mask'
itemValue: #'menu_copyMask'
)
(MenuItem
activeHelpKey: pasteMask
enabled: hasMask
label: 'Paste Mask'
itemValue: #'menu_pasteMask'
)
(MenuItem
enabled: hasMask
label: 'Clear Masked Pixels'
itemValue: #'menu_clearMaskedPixels'
)
(MenuItem
enabled: hasMask
label: 'Clear Colormap Entry for Masked Pixels'
itemValue: #'menu_clearColormapEntry0AndMaskedPixels'
)
)
nil
nil
)
)
)
nil
nil
)
"Modified: / 23-10-2017 / 11:18:58 / cg"
!
menuEdit
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#menuEdit
(Menu new fromLiteralArrayEncoding:(ImageEditor menuEdit)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
activeHelpKey: editUndo
enabled: canUndoHolder
label: 'Undo'
itemValue: doUndo
)
(MenuItem
label: '-'
)
(MenuItem
enabled: imageIsLoadedHolder
label: 'Copy to Clipboard'
itemValue: doCopyImageToClipboard
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: editResize
enabled: imageIsLoadedAndAllowedToChangeImageDimensionAndDepth
label: 'Resize...'
itemValue: doResizeImage
)
(MenuItem
activeHelpKey: editMagnifyImage
enabled: imageIsLoadedAndAllowedToChangeImageDimensionAndDepth
label: 'Magnify...'
itemValue: doMagnifyImage
)
(MenuItem
activeHelpKey: editMagnifyImage
enabled: imageIsLoadedAndAllowedToChangeImageDimensionAndDepth
label: 'Magnify By...'
itemValue: doMagnifyImageBy
)
(MenuItem
activeHelpKey: editRotate
enabled: imageIsLoadedAndAllowedToChangeImageDimensionAndDepth
label: 'Rotate...'
itemValue: doRotateImage
)
(MenuItem
activeHelpKey: edit3DProjection
enabled: imageIsLoadedAndAllowedToChangeImageDimensionAndDepth
label: '3D Projection...'
itemValue: do3DProjection
)
(MenuItem
enabled: imageIsLoadedAndAllowedToFlipHolder
label: 'Flip'
submenu:
(Menu
(
(MenuItem
activeHelpKey: editFlipVertical
enabled: imageIsLoadedAndNotReadonlyHolder
label: 'Flip - Vertical'
itemValue: doFlipVertical
labelImage: (ResourceRetriever ImageEditor flipVerticalIcon 'Flip - Vertical')
)
(MenuItem
activeHelpKey: editFlipHorizontal
enabled: imageIsLoadedAndNotReadonlyHolder
label: 'Flip - Horizontal'
itemValue: doFlipHorizontal
labelImage: (ResourceRetriever ImageEditor flipHorizontalIcon 'Flip - Horizontal')
)
)
nil
nil
)
)
(MenuItem
label: '-'
)
(MenuItem
enabled: imageIsLoadedAndAllowedToChangeImageDimension
label: 'Crop'
submenu:
(Menu
(
(MenuItem
activeHelpKey: cropManual
label: 'Manual...'
itemValue: doCropManual
)
(MenuItem
label: '-'
isVisible: false
)
(MenuItem
activeHelpKey: autoCropAll
label: 'All'
itemValue: autoCropAll
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: autoCropLeft
label: 'Left'
itemValue: autoCropLeft
)
(MenuItem
activeHelpKey: autoCropRight
label: 'Right'
itemValue: autoCropRight
)
(MenuItem
activeHelpKey: autoCropTop
label: 'Top'
itemValue: autoCropTop
)
(MenuItem
activeHelpKey: autoCropBottom
label: 'Bottom'
itemValue: autoCropBottom
)
)
nil
nil
)
)
(MenuItem
activeHelpKey: uncropManual
enabled: imageIsLoadedAndAllowedToChangeImageDimensionAndDepth
label: 'Uncrop (Add Border)...'
itemValue: doUnCropManual
)
(MenuItem
activeHelpKey: shiftManual
enabled: imageIsLoadedAndAllowedToChangeImageDimension
label: 'Shift...'
itemValue: doShiftManual
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: fileEditMask
enabled: hasMaskHolder
label: 'Edit Mask'
itemValue: doEditMask
)
(MenuItem
enabled: imageIsLoadedAndNotReadonlyHolder
label: 'Text...'
itemValue: doInsertTextFromUser
)
(MenuItem
label: '-'
)
(MenuItem
enabled: imageIsLoadedHolder
label: 'Animation Sequence'
submenu:
(Menu
(
(MenuItem
enabled: imageHasNextImageHolder
label: 'Next in Sequence'
itemValue: nextImageInSequence
)
(MenuItem
enabled: imageHasPreviousImageHolder
label: 'Previous in Sequence'
itemValue: previousImageInSequence
)
(MenuItem
label: '-'
)
(MenuItem
enabled: imageHasImageSequenceHolder
label: 'Edit each from Sequence'
itemValue: editEachImageFromSequence
)
)
nil
nil
)
)
)
nil
nil
)
!
menuFile
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#menuFile
(Menu new fromLiteralArrayEncoding:(ImageEditor menuFile)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
activeHelpKey: fileNewImageEditor
label: 'New ImageEditor'
itemValue: doNewImageEditor
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: fileNewImage
label: 'New...'
itemValue: doNewImage
)
(MenuItem
activeHelpKey: fileNewImageFromClipboard
label: 'New from ClipBoard'
itemValue: doNewImageFromClipboard
)
(MenuItem
activeHelpKey: fileNewMaskFromClipboard
label: 'Mask from ClipBoard'
itemValue: doNewMaskFromClipboard
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: fileLoadFromClass
label: 'Load...'
itemValue: doLoadFromClass
isVisible: methodSaveAndLoadMenuItemsVisible
)
(MenuItem
activeHelpKey: fileLoadFromFile
label: 'Load from File...'
itemValue: doLoadFromFile
)
(MenuItem
activeHelpKey: fileLoadFromURL
label: 'Load from URL...'
itemValue: doLoadFromURL
)
(MenuItem
label: 'Grab'
submenu:
(Menu
(
(MenuItem
activeHelpKey: fileGrabImageFromScreen
label: 'Grab from Screen Area...'
itemValue: grabScreenImage
)
(MenuItem
activeHelpKey: fileGrabImageFromScreen
enabled: hasLastGrabScreenArea
label: 'Grab again from same Screen Area'
itemValue: grabScreenImageFromLastArea
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: fileGrabImageFromWindow
label: 'Grab from Window...'
itemValue: grabWindowImage
)
(MenuItem
activeHelpKey: fileGrabFullSreenImage
label: 'Grab from whole Screen'
itemValue: grabFullScreenImage
)
)
nil
nil
)
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: fileSaveMethod
enabled: imageIsLoadedAndClassDefined
label: 'Save'
itemValue: doSaveMethod
isVisible: methodSaveAndLoadMenuItemsVisible
)
(MenuItem
activeHelpKey: fileSaveMethodAs
enabled: imageIsLoadedHolder
label: 'Save As...'
itemValue: doSaveMethodAs
isVisible: methodSaveAndLoadMenuItemsVisible
)
(MenuItem
activeHelpKey: fileSaveAs
enabled: imageIsLoadedHolder
label: 'Save to File...'
itemValue: doSaveImageFileAs
)
(MenuItem
activeHelpKey: fileSaveMaskAs
enabled: hasMaskHolder
label: 'Save Mask to File...'
itemValue: doSaveImageMaskFileAs
)
(MenuItem
activeHelpKey: fileSaveButtonImageAs
enabled: imageIsLoadedHolder
label: 'Save as Button to File...'
itemValue: doSaveButtonImageToFileAs
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: filePrint
enabled: imageIsLoadedHolder
label: 'Print'
itemValue: doPrint
)
(MenuItem
label: '-'
isVisible: isStandAlone
)
(MenuItem
activeHelpKey: fileBrowseClass
enabled: hasClassDefinedHolder
label: 'Browse Class'
itemValue: doBrowseClass
isVisible: isStandAlone
)
(MenuItem
enabled: imageIsLoadedHolder
label: 'Inspect Image'
itemValue: doInspectImage
isVisible: isStandAlone
)
(MenuItem
activeHelpKey: fileShowStoreString
enabled: imageIsLoadedHolder
label: 'Show storeString'
itemValue: doShowStoreString
)
(MenuItem
activeHelpKey: fileShowStoreString
enabled: imageIsLoadedHolder
label: 'Show Pixel Array Literal String'
itemValue: doShowPixelArrayLiteralString
)
(MenuItem
label: '-'
isVisible: isStandAlone
)
(MenuItem
activeHelpKey: fileExit
label: 'Exit'
itemValue: closeRequest
isVisible: isStandAlone
)
)
nil
nil
)
"Modified: / 25-02-2017 / 12:40:30 / cg"
!
menuMouseButtonColors
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#menuMouseButtonColors
(Menu new fromLiteralArrayEncoding:(ImageEditor menuMouseButtonColors)) startUp
"
<resource: #menu>
^
#(#Menu
#(
#(#MenuItem
#label: 'Left Mouse Button'
#nameKey: #leftMouseKeyButton
#activeHelpKey: #mouseKeyColorMode
#enabled: #imageIsLoadedHolder
#labelImage: #(#ResourceRetriever nil #leftMouseKeyIcon)
#choice: #mouseKeyColorMode
#choiceValue: 1
)
#(#MenuItem
#label: 'Right Mouse Button'
#nameKey: #rightMouseKeyButton
#activeHelpKey: #mouseKeyColorMode
#enabled: #imageIsLoadedHolder
#labelImage: #(#ResourceRetriever nil #rightMouseKeyIcon)
#choice: #mouseKeyColorMode
#choiceValue: 2
)
) nil
nil
)
"Modified: / 04-07-2010 / 10:17:37 / cg"
!
menuSettings
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#menuSettings
(Menu new fromLiteralArrayEncoding:(ImageEditor menuSettings)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
activeHelpKey: settingsGridMagnification
label: 'Grid Magnification Limit...'
itemValue: doChangeGridMagnification
translateLabel: true
)
(MenuItem
label: 'Pen'
translateLabel: true
submenu:
(Menu
(
(MenuItem
label: '1'
translateLabel: true
choice: penWidthHolder
choiceValue: 1
)
(MenuItem
label: '5'
translateLabel: true
choice: penWidthHolder
choiceValue: 5
)
(MenuItem
label: '10'
translateLabel: true
choice: penWidthHolder
choiceValue: 10
)
)
nil
nil
)
)
(MenuItem
label: 'Spray'
translateLabel: true
submenu:
(Menu
(
(MenuItem
label: '4'
translateLabel: true
choice: spraySpotHolder
choiceValue: 4
)
(MenuItem
label: '8'
translateLabel: true
choice: spraySpotHolder
choiceValue: 8
)
(MenuItem
label: '16'
translateLabel: true
choice: spraySpotHolder
choiceValue: 16
)
(MenuItem
label: '32'
translateLabel: true
choice: spraySpotHolder
choiceValue: 32
)
)
nil
nil
)
)
)
nil
nil
)
!
menuToolbar
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#menuToolbar
(Menu new fromLiteralArrayEncoding:(ImageEditor menuToolbar)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
activeHelpKey: fileNewImage
label: 'newImage'
itemValue: doNewImage
isButton: true
labelImage: (ResourceRetriever ToolbarIconLibrary newImageIcon)
)
(MenuItem
activeHelpKey: fileGrabImageFromScreen
label: 'grabScreenImage'
itemValue: grabScreenImage
isButton: true
labelImage: (ResourceRetriever ToolbarIconLibrary snapshot24x24Icon)
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: fileLoadFromClass
label: 'loadFromClass'
itemValue: doLoadFromClass
isButton: true
isVisible: isStandAloneAndMethodSaveAndLoadMenuItemsVisible
submenuChannel: menuHistory
labelImage: (ResourceRetriever XPToolbarIconLibrary loadImageFromMethodIcon)
keepLinkedMenu: true
)
(MenuItem
activeHelpKey: fileSaveMethodAs
enabled: imageIsLoadedHolder
label: 'fileSaveMethodAs'
itemValue: doSaveMethodAs
isButton: true
isVisible: isStandAloneAndMethodSaveAndLoadMenuItemsVisible
labelImage: (ResourceRetriever XPToolbarIconLibrary saveImageAsMethodAsIcon)
)
(MenuItem
activeHelpKey: fileSaveMethod
enabled: imageIsLoadedHolder
label: 'saveAsMethod'
itemValue: doSaveMethod
isButton: true
isVisible: isNotStandAloneAndMethodSaveAndLoadMenuItemsVisible
labelImage: (ResourceRetriever ToolbarIconLibrary saveImageAsMethodIcon)
)
(MenuItem
label: '-'
isVisible: methodSaveAndLoadMenuItemsVisible
)
(MenuItem
activeHelpKey: fileLoadFromFile
label: 'loadFromFile'
itemValue: doLoadFromFile
isButton: true
labelImage: (ResourceRetriever ToolbarIconLibrary loadImageFromFileIcon)
)
(MenuItem
activeHelpKey: fileSave
enabled: imageIsLoadedHolder
label: 'save'
itemValue: doSaveImageFile
isButton: true
isVisible: saveButtonInToolbarVisibleHolder
labelImage: (ResourceRetriever ToolbarIconLibrary saveImageIcon)
)
(MenuItem
activeHelpKey: fileSaveAs
enabled: imageIsLoadedHolder
label: 'saveAsFile'
itemValue: doSaveImageFileAs
isButton: true
labelImage: (ResourceRetriever ToolbarIconLibrary saveImageToFileAsIcon)
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: editUndo
enabled: canUndoHolder
label: 'Undo'
itemValue: doUndo
isButton: true
labelImage: (ResourceRetriever ToolbarIconLibrary undoIcon)
)
(MenuItem
label: '-'
isVisible: imageHasImageSequenceHolder
)
(MenuItem
activeHelpKey: previousImageInSequence
enabled: imageHasPreviousImageHolder
label: 'Previous Image'
itemValue: previousImageInSequence
isVisible: imageHasImageSequenceHolder
labelImage: (ResourceRetriever ToolbarIconLibrary leftArrow24x24Icon)
)
(MenuItem
activeHelpKey: nextImageInSequence
enabled: imageHasNextImageHolder
label: 'Next Image'
itemValue: nextImageInSequence
isVisible: imageHasImageSequenceHolder
labelImage: (ResourceRetriever ToolbarIconLibrary rightArrow24x24Icon)
)
)
nil
nil
)
"Modified: / 26-02-2017 / 23:03:40 / cg"
!
modeMenu
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#modeMenu
(Menu new fromLiteralArrayEncoding:(ImageEditor modeMenu)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
activeHelpKey: drawModePoint
enabled: imageIsLoadedHolder
label: 'Point'
labelImage: (ResourceRetriever ImageEditor pointIcon 'Point')
choice: editMode
choiceValue: point
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: drawModePoint
enabled: imageIsLoadedHolder
label: 'Spray'
labelImage: (ResourceRetriever ImageEditor sprayIcon 'Spray')
choice: editMode
choiceValue: spray
)
(MenuItem
activeHelpKey: drawModeSmooth
enabled: imageIsLoadedHolder
label: 'Smooth'
labelImage: (ResourceRetriever ImageEditor smoothIcon 'Smooth')
choice: editMode
choiceValue: smooth
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: drawModeBox
enabled: imageIsLoadedHolder
label: 'Rect'
labelImage: (ResourceRetriever ImageEditor rectIcon 'Rect')
choice: editMode
choiceValue: box
)
(MenuItem
activeHelpKey: drawModeFilledBox
enabled: imageIsLoadedHolder
label: 'Filled Rectangle'
labelImage: (ResourceRetriever ImageEditor fillRectIcon 'Filled Rectangle')
choice: editMode
choiceValue: filledBox
)
(MenuItem
activeHelpKey: drawModeCircle
enabled: imageIsLoadedHolder
label: 'Circle'
labelImage: (ResourceRetriever ImageEditor circleIcon 'Circle')
choice: editMode
choiceValue: circle
)
(MenuItem
activeHelpKey: drawModeFilledCircle
enabled: imageIsLoadedHolder
label: 'Filled Circle'
labelImage: (ResourceRetriever ImageEditor fillCircleIcon 'Filled Circle')
choice: editMode
choiceValue: filledCircle
)
(MenuItem
activeHelpKey: drawModeFill
enabled: imageIsLoadedHolder
label: 'Fill'
labelImage: (ResourceRetriever ImageEditor fillIcon 'Fill')
choice: editMode
choiceValue: fill
)
(MenuItem
enabled: imageIsLoadedHolder
label: 'Gradient Fill'
isVisible: false
submenu:
(Menu
(
(MenuItem
activeHelpKey: drawModeFill
enabled: imageIsLoadedHolder
label: 'Horizontal'
labelImage: (ResourceRetriever ImageEditor fillHorizontalGradientRectIcon 'Horizontal')
choice: editMode
choiceValue: fillHorizontalGradient
)
(MenuItem
activeHelpKey: drawModeFill
enabled: imageIsLoadedHolder
label: 'Vertical'
labelImage: (ResourceRetriever ImageEditor fillVerticalGradientRectIcon 'Vertical')
choice: editMode
choiceValue: fillVerticalGradient
)
(MenuItem
activeHelpKey: drawModeFill
enabled: imageIsLoadedHolder
isVisible: false
label: 'Diagonal'
labelImage: (ResourceRetriever ImageEditor fillDiagonalGradientRectIcon 'Diagonal')
choice: editMode
choiceValue: fillDiagonalGradient
)
)
nil
nil
)
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: drawModeMaskOutsideRectangle
enabled: imageHasMaskAndIsNotReadOnlyHolder
label: 'Mask Outside Rectangle'
labelImage: (ResourceRetriever ImageEditor maskOutsideRectangleIcon 'Mask Outside Rectangle')
choice: editMode
choiceValue: maskOutsideRect
)
(MenuItem
activeHelpKey: drawModeMaskOutsideCircle
enabled: imageHasMaskAndIsNotReadOnlyHolder
label: 'Mask Outside Circle'
labelImage: (ResourceRetriever ImageEditor maskOutsideCircleIcon 'Mask Outside Circle')
choice: editMode
choiceValue: maskOutsideCircle
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: drawModeCopy
enabled: imageIsLoadedHolder
label: 'Copy'
labelImage: (ResourceRetriever ImageEditor copyIcon 'Copy')
choice: editMode
choiceValue: copy
)
(MenuItem
activeHelpKey: drawModePasteWithMask
enabled: imageIsLoadedHolder
label: 'Paste with Mask'
labelImage: (ResourceRetriever ImageEditor pasteWithMaskIcon 'Paste with Mask')
choice: editMode
choiceValue: pasteWithMask
)
(MenuItem
activeHelpKey: drawModePaste
enabled: imageIsLoadedHolder
label: 'Paste Over'
labelImage: (ResourceRetriever ImageEditor pasteIcon 'Paste')
choice: editMode
choiceValue: paste
)
(MenuItem
activeHelpKey: drawModePasteUnder
enabled: imageIsLoadedHolder
label: 'Paste Under'
labelImage: (ResourceRetriever ImageEditor pasteUnderIcon 'Paste Under')
choice: editMode
choiceValue: pasteUnder
)
(MenuItem
label: '-'
)
(MenuItem
activeHelpKey: drawModeSpecial
enabled: imageIsLoadedHolder
label: 'Special'
labelImage: (ResourceRetriever ImageEditor specialRectangleIcon 'Special')
choice: editMode
choiceValue: specialOperation
)
)
nil
nil
)
"Modified: / 07-12-2017 / 15:30:46 / cg"
!
previewMenu
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#previewMenu
(Menu new fromLiteralArrayEncoding:(ImageEditor previewMenu)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
label: 'TileMode'
indication: tileModeHolder
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Background Color'
submenu:
(Menu
(
(MenuItem
label: 'Gray'
choice: previewBackgroundColorHolder
)
(MenuItem
label: 'Black'
choice: previewBackgroundColorHolder
choiceValue: black
)
(MenuItem
label: 'White'
choice: previewBackgroundColorHolder
choiceValue: white
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Red'
choice: previewBackgroundColorHolder
choiceValue: red
)
(MenuItem
label: 'Green'
choice: previewBackgroundColorHolder
choiceValue: green
)
(MenuItem
label: 'Blue'
choice: previewBackgroundColorHolder
choiceValue: blue
)
)
nil
nil
)
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Magnification'
submenu:
(Menu
(
(MenuItem
label: '0.1'
choice: previewMagnificationHolder
choiceValue: 0.1
)
(MenuItem
label: '0.25'
choice: previewMagnificationHolder
choiceValue: 0.25
)
(MenuItem
label: '0.5'
choice: previewMagnificationHolder
choiceValue: 0.5
)
(MenuItem
label: '1'
choice: previewMagnificationHolder
choiceValue: 1
)
(MenuItem
label: '2'
choice: previewMagnificationHolder
choiceValue: 2
)
(MenuItem
label: '4'
choice: previewMagnificationHolder
choiceValue: 4
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Choose...'
itemValue: changePreviewImageMagnification
)
)
nil
nil
)
)
)
nil
nil
)
"Modified: / 10-09-2017 / 14:54:41 / cg"
!
toolsMenuToolbar
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:ImageEditor andSelector:#toolsMenuToolbar
(Menu new fromLiteralArrayEncoding:(ImageEditor toolsMenuToolbar)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
activeHelpKey: drawModePoint
enabled: canDrawPointsHolder
label: 'Point'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor pointIcon)
choice: editMode
choiceValue: point
)
(MenuItem
activeHelpKey: drawModeSpray
enabled: canSprayHolder
label: 'Spray'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor sprayIcon)
choice: editMode
choiceValue: spray
)
(MenuItem
activeHelpKey: drawModeBox
enabled: canDrawRectsHolder
label: 'Rect'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor rectIcon)
choice: editMode
choiceValue: box
)
(MenuItem
activeHelpKey: drawModeFilledBox
enabled: canFillRectsHolder
label: 'FillRect'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor fillRectIcon)
choice: editMode
choiceValue: filledBox
)
(MenuItem
activeHelpKey: drawModeCircle
enabled: canDrawCirclesHolder
label: 'Circle'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor circleIcon)
choice: editMode
choiceValue: circle
)
(MenuItem
activeHelpKey: drawModeFill
enabled: canFloodFillHolder
label: 'Fill'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor fillIcon)
choice: editMode
choiceValue: fill
)
(MenuItem
activeHelpKey: drawModeCopy
enabled: imageIsLoadedHolder
label: 'Copy'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor copyIcon)
choice: editMode
choiceValue: copy
)
(MenuItem
activeHelpKey: drawModePasteWithMask
enabled: imageIsLoadedAndNotReadonlyHolder
label: 'Paste With Mask'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor pasteWithMaskIcon)
choice: editMode
choiceValue: pasteWithMask
)
(MenuItem
activeHelpKey: drawModePaste
enabled: imageIsLoadedAndNotReadonlyHolder
label: 'Paste'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor pasteIcon)
choice: editMode
choiceValue: paste
)
(MenuItem
activeHelpKey: drawModePasteUnder
enabled: imageIsLoadedAndNotReadonlyHolder
label: 'Paste Under'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor pasteUnderIcon)
choice: editMode
choiceValue: pasteUnder
)
(MenuItem
activeHelpKey: drawModeCropSubImage
enabled: imageIsLoadedHolder
label: 'Crop SubImage'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor cropSubImageIcon)
choice: editMode
choiceValue: cropSubImage
)
(MenuItem
activeHelpKey: drawModeSpecial
enabled: imageIsLoadedHolder
label: 'Special'
translateLabel: true
isButton: true
labelImage: (ResourceRetriever ImageEditor specialRectangleIcon)
choice: editMode
choiceValue: specialOperation
)
)
nil
nil
)
"Modified: / 24-08-2017 / 20:53:02 / cg"
! !
!ImageEditor class methodsFor:'tableColumns specs'!
colorTableColumns
"This resource specification was automatically generated
by the DataSetBuilder of ST/X."
"Do not manually edit this!! If it is corrupted,
the DataSetBuilder may not be able to read the specification."
"
DataSetBuilder new openOnClass:ImageEditor andSelector:#colorTableColumns
"
<resource: #tableColumns>
^#(
(DataSetColumnSpec
activeHelpKey: ''
labelButtonType: Button
rendererType: rowSelector
backgroundSelector: theColorItself:
selectedBackgroundSelector: theColorItself:
isResizeable: false
)
(DataSetColumnSpec
label: 'R'
labelAlignment: left
labelButtonType: Button
columnAlignment: right
editorType: InputField
type: number
model: redFromColor:
writeSelector: redAtColor:put:
selectSelector: canSelectRedInColor:
)
(DataSetColumnSpec
label: 'G'
labelAlignment: left
labelButtonType: Button
columnAlignment: right
editorType: InputField
type: number
model: greenFromColor:
writeSelector: greenAtColor:put:
selectSelector: canSelectGreenInColor:
)
(DataSetColumnSpec
label: 'B'
labelAlignment: left
labelButtonType: Button
columnAlignment: right
editorType: InputField
type: number
model: blueFromColor:
writeSelector: blueAtColor:put:
selectSelector: canSelectBlueInColor:
)
)
"Modified: / 22-07-2007 / 13:21:57 / cg"
! !
!ImageEditor methodsFor:'accessing'!
image
"returns the current editing image"
^ imageEditView image
!
postOpenAction: anAction
"sets an action which is evaluated after opening"
postOpenAction := anAction
!
resourceClass:aClass
imageEditView resourceClass:aClass
!
savedFile
"if user did a save to file, return the filename.
Otherwise, this returns nil"
^ savedFile
!
savedImage
"if user did a save, return what was saved last.
Otherwise, this returns nil"
^ savedImage
! !
!ImageEditor methodsFor:'accessing-behavior'!
allowedToChangeImageDimension
"used to edit an existing image's contents only (Expecco)"
^ self allowedToChangeImageDimensionAndDepth
"Created: / 16-02-2017 / 01:59:21 / cg"
!
allowedToChangeImageDimensionAndDepth
"used to edit an existing image's contents only (Expecco)"
self readOnly ifTrue:[^ false].
^ allowedToChangeImageDimensionAndDepth ? true
!
allowedToChangeImageDimensionAndDepth:aBoolean
"used to edit an existing image's contents only (Expecco)"
allowedToChangeImageDimensionAndDepth := aBoolean
! !
!ImageEditor methodsFor:'accessing-views'!
colorDataSetView
"returns the view of the colormap"
^(self componentAt: #colorDataSetView)
"Created: / 26.7.1998 / 12:02:14 / cg"
!
coordLabel
"returns the view the coord label"
^self componentAt: #coordLabel
!
imageEditView
"returns the editor view of the image"
imageEditView isNil ifTrue:[
imageEditView := (self componentAt: #imageEditView) scrolledView.
imageEditView addDependent:self.
].
^ imageEditView
"Modified: / 10.2.2000 / 23:19:20 / cg"
!
imagePreView
"returns the preview of the image"
|imagePreViewSubViews|
imagePreViewSubViews := (self componentAt: #imagePreView) subViews.
"subViews is an empty array at closing image Editor"
imagePreViewSubViews isEmptyOrNil ifTrue:[
^ nil
].
^ imagePreViewSubViews first
! !
!ImageEditor methodsFor:'actions'!
applyCropAction
self cropLeft:(self cropLeftAmount value) right:(self cropRightAmount value)
top:(self cropTopAmount value) bottom:(self cropBottomAmount value)
"Created: / 17-02-2017 / 14:34:35 / cg"
"Modified: / 19-02-2017 / 15:11:41 / cg"
!
cropBottomNow
self cropLeft:0 right:0 top:0 bottom:(self cropBottomAmount value)
"Created: / 19-02-2017 / 15:07:36 / cg"
!
cropLeft:left right:right top:top bottom:bottom
|img|
img := imageEditView image.
img isNil ifTrue:[^ self].
true "firstChange" ifTrue:[
imageEditView makeUndo.
"/ firstChange := false.
].
imageEditView
makeSubImageX:left y:top
width:(img width - left - right)
height:(img height - top - bottom).
self updateImagePreView.
self updateInfoLabel
"Created: / 19-02-2017 / 15:07:58 / cg"
!
cropLeftNow
self cropLeft:(self cropLeftAmount value) right:0 top:0 bottom:0
"Created: / 19-02-2017 / 15:08:06 / cg"
!
cropRightNow
self cropLeft:0 right:(self cropRightAmount value) top:0 bottom:0
"Created: / 19-02-2017 / 15:08:12 / cg"
!
cropTopNow
self cropLeft:0 right:0 top:(self cropTopAmount value) bottom:0
"Created: / 19-02-2017 / 15:08:29 / cg"
! !
!ImageEditor methodsFor:'aspects'!
activityInfoHolder
^ self infoLabelHolder
"Modified: / 29.7.1998 / 18:49:03 / cg"
!
alphaHolder
|holder|
(holder := builder bindingAt:#alphaHolder) isNil ifTrue:[
builder aspectAt:#alphaHolder put:(holder := 100 asValue).
holder onChangeEvaluate:[ imageEditView drawingAlpha:holder value ].
].
^ holder
"Created: / 05-09-2017 / 00:38:14 / cg"
"Modified: / 05-09-2017 / 10:47:01 / cg"
!
alphaText
^ 'alpha:'
"Created: / 05-09-2017 / 00:32:55 / cg"
!
alphaVisibleHolder
|holder|
(holder := builder bindingAt:#alphaVisibleHolder) isNil ifTrue:[
builder aspectAt:#alphaVisibleHolder put:(holder := false asValue).
].
^ holder
"Created: / 05-09-2017 / 00:35:36 / cg"
!
canAddColorToColormap
|img|
img := self image.
img isNil ifTrue:[^ false].
img photometric == #blackIs0 ifTrue:[^ false].
img photometric == #whiteIs0 ifTrue:[^ false].
^ true
"Created: / 31-08-2017 / 18:32:27 / cg"
!
canAddColorToColormapHolder
^ [self canAddColorToColormap]
"Created: / 31-08-2017 / 18:32:40 / cg"
!
canChangeColorInColormap
|img|
img := self image.
img isNil ifTrue:[^ false].
img photometric == #palette ifFalse:[^ false].
^ true
"Created: / 31-08-2017 / 18:34:12 / cg"
!
canChangeColorInColormapHolder
^ [self canChangeColorInColormap]
"Created: / 31-08-2017 / 18:34:18 / cg"
!
canResizeImage
^ self imageIsLoadedAndNotReadonlyHolder
!
colorBoxVisibleHolder
|holder|
(holder := builder bindingAt:#colorBoxVisibleHolder) isNil ifTrue:[
builder aspectAt:#colorBoxVisibleHolder put:(holder := true asValue).
].
^ holder
"Created: / 03-02-2017 / 11:20:21 / cg"
!
colorColumnAdaptor
^ self
"Created: / 26.7.1998 / 12:17:03 / cg"
!
colorCropTabLabelList
^ resources array:(self colorCropTabSpecList collect:#first)
"Created: / 19-02-2017 / 14:58:25 / cg"
!
colorCropTabSelectionIndexHolder
|holder|
(holder := builder bindingAt:#colorCropTabSelectionIndexHolder) isNil ifTrue:[
builder aspectAt:#colorCropTabSelectionIndexHolder put:(holder := self defaultEditTabIndex asValue).
holder onChangeSend:#colorCropTabSelectionIndexChanged to:self.
].
^ holder
"Created: / 19-02-2017 / 14:59:11 / cg"
"Modified: / 19-02-2017 / 23:33:39 / cg"
!
colorCropTabSpecList
^ #(
('Colors' colors)
('Crop' crop)
('Fill' fill)
)
"Created: / 19-02-2017 / 15:34:33 / cg"
!
colorCropTabSymbolList
^ self colorCropTabSpecList collect:#second
"Created: / 19-02-2017 / 15:34:54 / cg"
!
cropBottomAmount
^ builder valueAspectFor:'cropBottomAmount' initialValue:1
"Created: / 19-02-2017 / 15:09:09 / cg"
!
cropBoxIsDialog
^ false
"Created: / 03-02-2017 / 11:23:50 / cg"
"Modified: / 19-02-2017 / 15:24:07 / cg"
!
cropBoxIsNotDialog
^ self cropBoxIsDialog not
"Created: / 17-02-2017 / 14:38:04 / cg"
!
cropBoxVisibleHolder
|holder|
(holder := builder bindingAt:#cropBoxVisibleHolder) isNil ifTrue:[
builder aspectAt:#cropBoxVisibleHolder put:(holder := false asValue).
].
^ holder
"Created: / 03-02-2017 / 11:20:13 / cg"
!
cropLeftAmount
^ builder valueAspectFor:'cropLeftAmount' initialValue:1
"Created: / 19-02-2017 / 15:09:23 / cg"
!
cropRightAmount
^ builder valueAspectFor:'cropRightAmount' initialValue:1
"Created: / 19-02-2017 / 15:09:29 / cg"
!
cropTopAmount
^ builder valueAspectFor:'cropTopAmount' initialValue:1
"Created: / 19-02-2017 / 15:09:35 / cg"
!
defaultEditTabIndex
"the default tab to show in the color/crop/fill tablist"
^ 1
"Created: / 19-02-2017 / 23:34:12 / cg"
!
drawingColor1Holder
"returns a valueHolder for the current selected mouse-button-1 color"
|holder|
(holder := builder bindingAt:#drawingColor1Holder) isNil ifTrue:[
builder aspectAt:#drawingColor1Holder put:(holder := IndirectValue new)
].
^ holder
"Created: / 23-02-2017 / 10:18:25 / cg"
!
drawingColor2Holder
"returns a valueHolder for the current selected mouse-button-2 color"
|holder|
(holder := builder bindingAt:#drawingColor2Holder) isNil ifTrue:[
builder aspectAt:#drawingColor2Holder put:(holder := IndirectValue new)
].
^ holder
"Created: / 23-02-2017 / 10:18:33 / cg"
!
floodFillBoxVisibleHolder
|holder|
(holder := builder bindingAt:#floodFillBoxVisibleHolder) isNil ifTrue:[
builder aspectAt:#floodFillBoxVisibleHolder put:(holder := false asValue).
].
^ holder
"Created: / 19-02-2017 / 15:28:40 / cg"
!
floodFillMaxHueError
|holder|
(holder := builder bindingAt:#floodFillMaxHueError) isNil ifTrue:[
builder aspectAt:#floodFillMaxHueError put:(holder := 0 asValue).
holder onChangeEvaluate:[ imageEditView floodFillMaxHueError:holder value ].
].
^ holder
"Created: / 17-02-2017 / 15:19:17 / cg"
!
floodFillMaxLightError
|holder|
(holder := builder bindingAt:#floodFillMaxLightError) isNil ifTrue:[
builder aspectAt:#floodFillMaxLightError put:(holder := 0 asValue).
holder onChangeEvaluate:[ imageEditView floodFillMaxLightError:holder value ].
].
^ holder
"Created: / 17-02-2017 / 15:19:11 / cg"
!
hasClassAndSelectorDefinedHolder
^ [
|cls|
(cls := imageEditView resourceClass) notNil
and:[imageEditView resourceSelector notNil]
]
"Created: / 04-07-2010 / 10:11:10 / cg"
!
hasClassDefinedHolder
^ [
imageEditView resourceClass notNil
]
"Created: / 04-07-2010 / 10:11:47 / cg"
!
hasColorSelectedHolder
^ [ self selectedColors value notEmptyOrNil "self selectedColorIndexOrNil notNil" ]
"Created: / 04-07-2010 / 10:12:22 / cg"
!
hasColormap
"true if a colormap is shown (might be a drwing map, not the real map)"
|img|
^ (img := self image) notNil
and:[img colorMap notNil or:[ drawingColormap notNil or:[ self listOfColors notEmptyOrNil ]]]
"Created: / 30-09-1998 / 23:53:55 / cg"
"Modified: / 23-02-2017 / 09:57:45 / cg"
"Modified (comment): / 31-08-2017 / 18:36:08 / cg"
!
hasColormapAndColorSelected
^ [ self hasColormap and:[self hasColorSelectedHolder value]]
"Modified: / 31-08-2017 / 14:08:20 / cg"
!
hasColormapAndSingleColorSelected
^ self hasColormapHolder value and:[self hasSingleColorSelectedHolder value]
"Modified: / 31-08-2017 / 18:44:49 / cg"
!
hasColormapAndSingleColorSelectedHolder
^ [ self hasColormapAndSingleColorSelected value ]
"Created: / 31-08-2017 / 18:44:36 / cg"
!
hasColormapAndSingleWritableColorSelectedHolder
^ [ self hasColormapAndSingleColorSelected
and:[self canChangeColorInColormap ]]
"Created: / 31-08-2017 / 18:42:46 / cg"
!
hasColormapHolder
"true if a colormap is shown (might be a drwing map, not the real map)"
^ [self hasColormap]
"Created: / 04-07-2010 / 10:13:05 / cg"
"Modified (comment): / 31-08-2017 / 18:36:47 / cg"
!
hasSingleColorSelectedHolder
^ [ self selectedColors value size == 1 "self selectedColorIndexOrNil notNil" ]
"Created: / 04-07-2010 / 10:12:22 / cg"
!
hasWritableColorSelectedHolder
^ [ self hasSingleColorSelectedHolder value and:[self canChangeColorInColormap ]]
"Created: / 08-10-2017 / 14:45:11 / cg"
!
imageHasColormap
"true if a colormap is shown (might be a drwing map, not the real map)"
|img|
^ (img := self image) notNil
and:[img colorMap notNil ]
"Created: / 31-08-2017 / 18:36:25 / cg"
!
imageHasColormapHolder
^ [self imageHasColormap]
"Created: / 31-08-2017 / 18:36:42 / cg"
!
imageHasImageSequence
|img|
^ (img := self image) notNil and:[img imageSequence notNil]
"Created: / 21-10-2010 / 14:35:45 / cg"
!
imageHasImageSequenceHolder
|holder|
(holder := builder bindingAt:#imageHasImageSequenceHolder) isNil ifTrue:[
builder aspectAt:#imageHasImageSequenceHolder put:(holder := false asValue).
holder value:(self imageHasImageSequence).
].
^ holder
"Modified: / 21-10-2010 / 14:36:57 / cg"
!
imageHasMaskAndIsNotReadOnlyHolder
"returns whether an image is loaded and editable as value holder"
^ BlockValue
with:[:loaded | loaded and:[ self image mask notNil and:[self readOnly not] ]]
argument:(self imageIsLoadedHolder)
"Created: / 16-02-2017 / 12:17:25 / cg"
!
imageHasNextImage
^ self imageHasImageSequence and:[ (imageSeqNr ? 1) < self image imageSequence size ]
"Created: / 21-10-2010 / 14:37:10 / cg"
!
imageHasNextImageHolder
|holder|
(holder := builder bindingAt:#imageHasNextImageHolder) isNil ifTrue:[
builder aspectAt:#imageHasNextImageHolder put:(holder := false asValue).
holder value:(self imageHasNextImage).
].
^ holder
"Modified: / 21-10-2010 / 14:37:40 / cg"
!
imageHasPreviousImage
^ self imageHasImageSequence and:[ (imageSeqNr ? 1) > 1 ]
"Created: / 21-10-2010 / 14:37:21 / cg"
!
imageHasPreviousImageHolder
|holder|
(holder := builder bindingAt:#imageHasPreviousImageHolder) isNil ifTrue:[
builder aspectAt:#imageHasPreviousImageHolder put:(holder := false asValue).
holder value:(self imageHasPreviousImage).
].
^ holder
"Modified: / 21-10-2010 / 14:37:48 / cg"
!
imageInfoHolder
|holder|
(holder := builder bindingAt:#imageInfoHolder) isNil ifTrue:[
builder aspectAt:#imageInfoHolder put:(holder := '' asValue).
].
^ holder
"Modified: / 04-07-2010 / 10:15:14 / cg"
!
listOfColors
"returns the list of colors"
|list|
(list := builder bindingAt:#listOfColors) isNil ifTrue:[
builder aspectAt:#listOfColors put:(list := List new).
list addDependent:self.
].
^ list
!
magnificationHolder
"returns current magnification of the image as an AspectAdaptor"
|holder|
(holder := builder bindingAt:#valueOfMagnification) isNil ifTrue:[
builder aspectAt:#valueOfMagnification put:(
holder := AspectAdaptor new subject:self; forAspect:#magnification)
].
^ holder
!
penWidthHolder
|holder|
(holder := builder bindingAt:#penWidthHolder) isNil ifTrue:[
builder aspectAt:#penWidthHolder put:(holder := imageEditView penWidth asValue).
holder onChangeSend:#penWidthHolderChanged to:self.
].
^ holder
"Created: / 15-02-2012 / 22:30:58 / cg"
!
previewBackgroundColorHolder
|holder|
(holder := builder bindingAt:#previewBackgroundColor) isNil ifTrue:[
builder aspectAt:#previewBackgroundColor put:(holder := nil asValue).
holder addDependent:self.
].
^ holder
"Created: / 04-07-2010 / 10:19:34 / cg"
!
previewMagnificationHolder
|holder|
(holder := builder bindingAt:#previewMagnificationHolder) isNil ifTrue:[
builder aspectAt:#previewMagnificationHolder put:(holder := 1 asValue).
holder addDependent:self.
].
^ holder
"Created: / 10-09-2017 / 14:10:07 / cg"
!
readOnly
^ false
!
saveButtonInToolbarVisibleHolder
^ false
"Created: / 26-02-2017 / 22:58:41 / cg"
!
selectedColors
"returns a valueHolder for the current set of selected colors."
|holder|
(holder := builder bindingAt:#selectedColors) isNil ifTrue:[
builder aspectAt:#selectedColors put:(holder := nil asValue).
holder onChangeSend:#selectedColorsChanged to:self.
].
^ holder
!
selectionOfColor
"returns a valueHolder for the current selection of the edit color.
Here, an AspectAdaptor which accesses selectedColorIndex is returned."
|holder|
(holder := builder bindingAt:#selectionOfColor) isNil ifTrue:[
builder aspectAt:#selectionOfColor put:(
holder := AspectAdaptor new subject:self; forAspect:#selectedColorIndex ).
].
^ holder
!
spraySpotHolder
|holder|
(holder := builder bindingAt:#spraySpotHolder) isNil ifTrue:[
builder aspectAt:#spraySpotHolder put:(holder := imageEditView spraySpot asValue).
holder onChangeSend:#spraySpotHolderChanged to:self.
].
^ holder
"Created: / 15-02-2012 / 22:36:38 / cg"
!
tileModeHolder
|holder|
(holder := builder bindingAt:#tileModeHolder) isNil ifTrue:[
builder aspectAt:#tileModeHolder put:(holder := false asValue).
holder addDependent:self.
].
^ holder
"Modified: / 21-10-2010 / 14:35:24 / cg"
!
valueOfMagnification
<resource: #obsolete>
"returns current magnification of the image as an AspectAdaptor"
self obsoleteMethodWarning:'stupid method name - use #magnificationHolder'.
^ self magnificationHolder
! !
!ImageEditor methodsFor:'change & update'!
changePreviewImageMagnification
|mag|
mag := Dialog request:'Magnification?' initialAnswer:self imagePreView magnificationFactor.
mag isEmptyOrNil ifTrue:[^ self].
mag := Number readFrom:mag onError:nil.
mag isNil ifTrue:[^ self].
self previewMagnificationHolder value:mag
"Created: / 10-09-2017 / 14:52:52 / cg"
!
colorCropTabSelectionIndexChanged
|selIndex sym|
selIndex := self colorCropTabSelectionIndexHolder value.
sym := self colorCropTabSymbolList at:selIndex.
self colorBoxVisibleHolder value:(sym == #colors).
self cropBoxVisibleHolder value:(sym == #crop).
self floodFillBoxVisibleHolder value:(sym == #fill).
"Created: / 19-02-2017 / 15:01:05 / cg"
"Modified: / 21-04-2017 / 16:05:51 / cg"
!
colorMapModeFromImage:anImage
"retrieves the colorMapMode for an image"
|image colorMapModeKey|
image := self image.
image isNil ifTrue:[^ nil ].
image mask notNil ifTrue: [
colorMapModeKey := 'masked'.
] ifFalse:[
colorMapModeKey := 'depth'.
].
colorMapModeKey := (colorMapModeKey , image depth printString) asSymbol.
^ colorMapModeKey
"Created: / 06-04-2017 / 13:19:19 / cg"
!
findColorMapMode
"finds the colorMapMode for a new image"
|image newListOfColors colorMapModeKey drawColor1 drawColor2 someOrAllUsedColors|
image := self image.
(colorMapModeKey := self colorMapModeFromImage:image) isNil ifTrue:[^ self].
self colorMapMode setValue:colorMapModeKey.
image photometric == #palette ifTrue:[
image colorMap isNil ifTrue:[
image depth > 16 ifTrue:[
image photometric:#rgb
].
].
].
image depth > 12 ifTrue:[
newListOfColors := OrderedCollection new.
(image depth > 16 or:[image colorMap isEmptyOrNil]) ifTrue:[
someOrAllUsedColors := image usedColorsMax:10000.
someOrAllUsedColors notNil ifTrue:[
someOrAllUsedColors := someOrAllUsedColors asArray.
someOrAllUsedColors sort:self sortBlockForColors.
newListOfColors addAll:someOrAllUsedColors.
"/ listOfColors add:Color black; add:Color white.
].
image mask notNil ifTrue:[
newListOfColors := (Array with:(Color noColor)),newListOfColors.
].
] ifFalse:[
newListOfColors addAll:(image colorMap).
].
] ifFalse:[
newListOfColors := OrderedCollection withAll:(self listOfColors).
newListOfColors isEmpty ifTrue:[
self colorMapMode: colorMapMode value.
image := self image.
].
"/ image mask notNil ifTrue:[
"/ newListOfColors := (Array with:(Color noColor)),newListOfColors.
"/ ].
].
newListOfColors notEmptyOrNil ifTrue:[
drawColor1 := newListOfColors at:1.
drawColor2 := newListOfColors at:2 ifAbsent:drawColor1.
self hasTransparentColorInColorList ifTrue: [
(newListOfColors includes:(Color colorId:0)) ifFalse:[
newListOfColors addFirst:(Color colorId:0).
drawColor1 := newListOfColors at:2.
drawColor2 := newListOfColors at:3 ifAbsent:drawColor1.
]
].
"/ imageEditView drawingColors:(Array with: drawColor1 with: drawColor2).
"/ self selectionOfColor
"/ setValue: 0;
"/ value: (listOfColors indexOf: imageEditView selectedColor).
].
self listOfColors asOrderedCollection ~= newListOfColors ifTrue:[
self listOfColors contents:newListOfColors.
].
"Modified: / 05-09-2017 / 09:03:31 / cg"
!
selectedColorsChanged
|colorIndices selectedIndex|
(colorIndices := self selectedColors value) size == 1 ifTrue:[
"/ a single color selected
selectedIndex := colorIndices first
].
self selectionOfColor value:selectedIndex
"Modified: / 17-02-2017 / 14:40:33 / cg"
!
update:something with:aParameter from:changedObject
|clrIndex image imagePreView clr changedColor cMap|
image := self image.
imagePreView := self imagePreView.
changedObject == self tileModeHolder ifTrue:[
image isNil ifTrue:[
^ self
].
imagePreView
tileMode:(changedObject value) tileOffset:(image extent);
clear;
invalidate.
^ self
].
changedObject == self previewBackgroundColorHolder ifTrue:[
clr := changedObject value isNil
ifTrue:[imageEditView viewBackground]
ifFalse:[Color perform:changedObject value].
imagePreView
viewBackground:clr;
clear;
invalidate.
^ self
].
changedObject == self previewMagnificationHolder ifTrue:[
imagePreView
magnificationFactor:(self previewMagnificationHolder value);
clear;
invalidate.
^ self
].
changedObject == self listOfColors ifTrue:[
something == #at: ifTrue:[
"/ colormap entry changed at aParameter
clrIndex := aParameter.
(self hasTransparentColorInColorList) ifTrue:[
clrIndex := clrIndex - 1.
].
changedColor := changedObject at:aParameter.
cMap := image colorMap.
(cMap notNil and:[cMap isFixedPalette not]) ifTrue:[
image colorMap at:clrIndex put:changedColor.
self colorMapChanged.
] ifFalse:[
drawingColormap notNil ifTrue:[
drawingColormap size < clrIndex ifTrue:[
|newDrawingColormap|
newDrawingColormap := drawingColormap species new:clrIndex.
newDrawingColormap replaceFrom:1 with:drawingColormap.
drawingColormap := newDrawingColormap.
].
drawingColormap at:clrIndex put:changedColor.
].
].
^ self
].
^ self
].
changedObject == imageEditView undoImages ifTrue:[
self canUndoHolder value:(changedObject notEmpty).
^ self
].
changedObject == imageEditView ifTrue:[
something == #imageColors ifTrue:[
self updateListOfColorsAndColormapMode.
^ self
].
something == #image ifTrue:[
self updateAfterImageChange.
imagePreView image:image scroll:false.
self updateListOfColorsAndColormapMode.
self tileModeHolder value ifTrue:[
imagePreView tileMode:true tileOffset:(image extent).
].
self updateInfoLabel.
^ self
].
something == #subImageIn ifTrue:[
imagePreView image ~~ image ifTrue:[
self error:'internal error' mayProceed:true.
].
self tileModeHolder value ifTrue:[
imagePreView invalidate.
] ifFalse:[
imagePreView invalidate:aParameter.
].
^ self
].
something == #selectedColor ifTrue:[
(aParameter isNil or:[aParameter = (Color colorId:0)]) ifTrue:[
"/ no color/mask */
"/ self halt.
clrIndex := self hasTransparentColorInColorList ifTrue:[1] ifFalse:[0].
] ifFalse:[
clrIndex := self listOfColors indexOf:aParameter.
].
self selectedColors value:{clrIndex}. "/ selectionOfColor value:clrIndex.
^ self
].
^ self
].
changedObject == imageEditView modifiedHolder ifTrue:[
"/ self halt:'to be implemented'.
^ self
].
changedObject == imageEditView image ifTrue:[
"/ self halt:'to be implemented'.
self updateAfterImageChange.
^ self
].
super update:something with:aParameter from:changedObject
"Modified: / 13-09-2017 / 18:01:26 / cg"
!
updateAfterImageChange
|img|
(img := self image) notNil ifTrue:[
img := img onDevice:device.
self updateColorsFromImage:img.
self findColorMapMode.
self updateLabelsAndHistory.
imageSeqNr isNil ifTrue:[
imageSeqNr := 1
].
self imageHasImageSequenceHolder value:(self imageHasImageSequence).
self imageHasNextImageHolder value:(self imageHasNextImage).
self imageHasPreviousImageHolder value:(self imageHasPreviousImage).
self alphaVisibleHolder value:(img hasAlphaChannel)
] ifFalse:[
self updateForNoImage
]
"Modified: / 05-09-2017 / 00:44:10 / cg"
!
updateColorsFromImage:image
|colors depth|
depth := image depth.
depth > 16 ifTrue:[
colors := #() "/ too many - will only show the one's which are explicitly added.
] ifFalse:[
((image photometric == #blackIs0)
or:[ image photometric == #whiteIs0 ]) ifTrue:[
depth <= 8 ifTrue:[
colors := 1 to:(1 << depth) collect:[:i | image colorFromValue:i-1]
].
].
colors isNil ifTrue:[
colors := image colorMap.
colors isNil ifTrue:[
Error handle:[:ex |
colors := OrderedCollection new.
] do:[
colors := image usedColors asSet.
].
].
].
].
self listOfColors contents:(colors asOrderedCollection).
"Modified: / 31-08-2017 / 18:54:53 / cg"
!
updateForNoImage
"updates channels and view, if image is loaded"
self imageIsLoadedHolder value: false.
self listOfColors removeAll.
self imagePreView image: nil.
self imageHasImageSequenceHolder value:false.
self alphaVisibleHolder value:false.
"Modified: / 05-09-2017 / 00:44:20 / cg"
!
updateLabelsAndHistory
"updates labels and history, if something has changed"
|image rsrcClass rsrcSelector imgFile|
image := self image.
self imageIsLoadedHolder value: image notNil.
image isNil ifTrue: [^nil].
self updateInfoLabel.
((rsrcClass := imageEditView resourceClass) notNil
and:[ (rsrcSelector := imageEditView resourceSelector) notNil ]) ifTrue:[
self addHistoryEntryForClass:rsrcClass selector:rsrcSelector.
] ifFalse:[
(imgFile := image fileName) notNil ifTrue: [
self addHistoryEntryForFile:imgFile.
].
].
"Modified: / 01-09-2017 / 10:10:12 / cg"
!
updateListOfColorsAndColormapMode
|listOfColors selectedColor colorMap image|
selectedColor := self selectedColorOrNil.
listOfColors := self listOfColors.
image := self image.
image isNil ifTrue:[
listOfColors removeAll.
] ifFalse:[
colorMap := image colorMap.
colorMap notNil ifTrue:[
(colorMap size <= 4096) ifTrue:[
(image mask notNil or:[image hasAlphaChannel]) ifTrue:[
colorMap := (Array with:(Color noColor)),colorMap.
].
listOfColors contents:colorMap.
] ifFalse:[
listOfColors removeAll.
colorMap isFixedPalette ifTrue:[
image colorMap:nil.
image photometric:#rgb.
image samplesPerPixel:3.
image bitsPerSample:(Array
with:(colorMap bitsRed)
with:(colorMap bitsGreen)
with:(colorMap bitsBlue)).
].
]
].
].
self findColorMapMode.
selectedColor notNil ifTrue:[
self selectColor:selectedColor.
].
"Modified: / 05-09-2017 / 08:25:14 / cg"
! !
!ImageEditor methodsFor:'data access'!
atColor:anOldColor put:newColor
"a color changed to a new color"
|index list oldColor image newImage oldSel|
list := self listOfColors.
index := list identityIndexOf:anOldColor.
oldSel := self selectionOfColor value.
index ~~ 0 ifTrue:[
oldColor := list at:index.
list at:index put:newColor
] ifFalse:[
self error:'internal error' mayProceed:true.
list add:newColor
].
image := self image.
(image colorMap isNil
and:[drawingColormap isNil]) ifTrue:[
oldColor notNil ifTrue:[
imageEditView makeUndo.
newImage := image copy.
newImage
colorsFromX:0 y:0 toX:(image width-1) y:(image height-1)
do:[:x :y :clr |
|newClr|
newClr := (clr = oldColor) ifTrue:[newColor] ifFalse:[clr].
newImage colorAtX:x y:y put:newClr
].
imageEditView image:newImage.
imageEditView setModified.
self updateImage.
self updateImagePreView.
self selectedColors value:{oldSel}.
imageEditView selectedColorIndex:oldSel.
imageEditView selectedColor:(self listOfColors at:oldSel).
]
].
!
blueAtColor:aColor put:newBlue
"helper used to return a new row element, when blue is changed"
|byte|
aColor isNil ifTrue:[^ self]. "/ mask cannot be changed
byte := newBlue clampBetween:0 and:255.
byte = aColor blueByte ifTrue:[^ self ].
self atColor:aColor
put:(Color redByte:(aColor redByte) greenByte:(aColor greenByte) blueByte:byte).
!
blueFromColor:aColor
"helper used to access a color as a row in the dataSet view"
aColor isNil ifTrue:[^ 'none'].
^ aColor blueByte ? 'mask'
"Created: / 26.7.1998 / 12:30:35 / cg"
"Modified: / 31.7.1998 / 01:11:18 / cg"
!
canSelectBlueInColor:aColor
^ aColor blueByte notNil
"Created: / 7.8.1998 / 22:50:34 / cg"
"Modified: / 7.8.1998 / 22:52:57 / cg"
!
canSelectGreenInColor:aColor
^ aColor greenByte notNil
"Created: / 7.8.1998 / 22:50:22 / cg"
"Modified: / 7.8.1998 / 22:52:46 / cg"
!
canSelectRedInColor:aColor
^ aColor redByte notNil
"Created: / 7.8.1998 / 22:50:00 / cg"
"Modified: / 7.8.1998 / 22:51:03 / cg"
!
greenAtColor:aColor put:newGreen
"helper used to return a new row element, when green is changed"
|byte|
aColor isNil ifTrue:[^ self]. "/ mask cannot be changed
byte := newGreen clampBetween:0 and:255.
byte = aColor greenByte ifTrue:[^ self].
self atColor:aColor
put:(Color redByte:(aColor redByte) greenByte:byte blueByte:(aColor blueByte)).
!
greenFromColor:aColor
"helper used to access a color as a row in the dataSet view"
aColor isNil ifTrue:[^ 'none'].
^ aColor greenByte ? 'mask'
"Created: / 26.7.1998 / 12:30:29 / cg"
"Modified: / 31.7.1998 / 01:11:31 / cg"
!
redAtColor:aColor put:newRed
"helper used to return a new row element, when red is changed"
|byte|
aColor isNil ifTrue:[^ self]. "/ mask cannot be changed
byte := newRed clampBetween:0 and:255.
byte = aColor redByte ifTrue:[^ self].
self atColor:aColor
put:(Color redByte:byte greenByte:(aColor greenByte) blueByte:(aColor blueByte)).
!
redFromColor:aColor
"helper used to access a color as a row in the dataSet view"
aColor isNil ifTrue:[^ 'none'].
^ aColor redByte ? 'mask'
"Modified: / 31.7.1998 / 01:11:35 / cg"
!
theColorItself:aColor
"an accessor for the table-column"
^ aColor
! !
!ImageEditor methodsFor:'defaults'!
aboutIcon
^ self class defaultIcon
! !
!ImageEditor methodsFor:'drag & drop'!
canDropObjects:aCollectionOfDropObjects in:aWidget
^ (aCollectionOfDropObjects size == 1)
and:[ aCollectionOfDropObjects
contains:[:dropObject | dropObject isFileObject]]
!
dropObjects:aCollectionOfDropObjects in:aWidget at:position
|dropObject|
dropObject := aCollectionOfDropObjects first.
dropObject isFileObject ifTrue:[
self loadFromFile:dropObject asFilename.
]
! !
!ImageEditor methodsFor:'event handling'!
processEvent:anEvent
"Return true, if I have eaten the event"
<resource: #keyboard (#Paste #Copy )>
|view focusView p transformation|
view := anEvent view.
view notNil ifTrue:[
view == self imagePreView ifTrue:[
((anEvent isButtonPressEvent and:[ anEvent button == 1 ])
or:[ anEvent isButtonMotionEvent and:[ anEvent hasButton1 ]]) ifTrue:[
p := anEvent x @ anEvent y.
(transformation := view transformation) notNil ifTrue:[
p := transformation applyInverseTo:p.
].
p := p / self previewMagnificationHolder value.
self imageEditView scrollToMakeVisible:p.
^ true.
].
].
anEvent isKeyPressEvent ifTrue:[
focusView := view windowGroup focusView ? view.
(focusView isComponentOf:(builder componentAt:#colorDataSetView)) ifTrue:[
anEvent key == #Paste ifTrue:[
self pasteColorIntoColormap.
^ true.
].
anEvent key == #Copy ifTrue:[
self copyColorFromColormap.
^ true.
].
].
].
].
^ false.
"Modified: / 10-09-2017 / 16:40:13 / cg"
! !
!ImageEditor methodsFor:'help'!
defaultInfoLabel
"returns the text shown in the info label, when the mouse is NOT over
some widget with a help text."
|resourceClass resourceSelector img|
resourceClass := imageEditView resourceClass.
resourceClass notNil ifTrue:[
resourceSelector := imageEditView resourceSelector.
resourceSelector notNil ifTrue:[
^ resources
string:(self modified
ifTrue:['Image (modified) from: %1 » %2']
ifFalse:['Image from: %1 » %2'])
with:resourceClass name
with:resourceSelector
].
].
(img := imageEditView image) notNil ifTrue:[
img fileName notNil ifTrue:[
^ resources
string:(self modified
ifTrue:['Image (modified) from: %1']
ifFalse:['Image from: %1'])
with:(img fileName asFilename baseName).
].
].
^ resources string:'No class and selector defined.'
"Modified: / 29-08-2017 / 19:47:25 / cg"
!
openDocumentation
"opens the documentation file of the Image Editor"
self openHTMLDocument: 'tools/uipainter/ImageEditor.html'
! !
!ImageEditor methodsFor:'loading'!
loadFromClass:aClass andSelector:aSelector
"loads an image from the method specified by class and selector"
self assert:(aClass isNil or:[aClass isClass]).
(aClass isNil or:[aSelector isNil]) ifTrue:[
imageEditView resourceClass:aClass.
imageEditView resourceSelector:aSelector.
imageEditView image:nil.
self clearModified.
^ self.
].
(imageEditView loadFromClass:aClass andSelector:aSelector) notNil ifTrue:[
self updateAfterImageChange.
self clearModified.
]
"Modified: / 16-03-1999 / 21:44:41 / cg"
"Modified (comment): / 16-02-2017 / 10:22:51 / cg"
!
loadFromFile:aFileName
"loads an image from aFileName and sets up color map list and other info labels"
self withCursor:Cursor wait do:[
(imageEditView loadFromFile: aFileName) notNil ifTrue:[
self updateAfterImageChange
]
]
"Modified: / 16.3.1999 / 21:44:26 / cg"
!
loadFromImage:anImage
"loads an image from anImage and sets up color map list and other info labels"
|img|
anImage notNil ifTrue:[
img := anImage onDevice:device.
].
imageEditView image:img.
imageEditView clearModified.
self updateAfterImageChange.
"Modified: / 16-03-1999 / 21:43:56 / cg"
"Modified (comment): / 16-02-2017 / 10:21:47 / cg"
!
loadFromOrPrepareForClass: aClass andSelector: aSelector
"loads an image by evaluating aMessage;
if no image could extract from aMessage; do set the class and the selector from
the aMessage for a saving at the end of editing"
(imageEditView loadFromClass:aClass andSelector:aSelector) notNil ifTrue: [
self updateColorsFromImage:self image.
self findColorMapMode.
] ifFalse: [
imageEditView resourceClass: aClass.
imageEditView resourceSelector:aSelector.
].
self updateLabelsAndHistory.
"Modified: / 16.3.1999 / 21:45:07 / cg"
! !
!ImageEditor methodsFor:'menu aspects'!
canDrawCirclesHolder
^ self imageIsLoadedAndNotReadonlyHolder
"Created: / 16-02-2017 / 01:41:31 / cg"
!
canDrawPointsHolder
^ self imageIsLoadedAndNotReadonlyHolder
"Created: / 16-02-2017 / 01:39:37 / cg"
!
canDrawRectsHolder
^ self imageIsLoadedAndNotReadonlyHolder
"Created: / 16-02-2017 / 01:40:17 / cg"
!
canFillCircleHolder
^ self imageIsLoadedAndNotReadonlyHolder
"Created: / 10-04-2017 / 08:46:00 / cg"
!
canFillRectsHolder
^ self imageIsLoadedAndNotReadonlyHolder
"Created: / 16-02-2017 / 01:40:21 / cg"
!
canFloodFillHolder
^ self imageIsLoadedAndNotReadonlyHolder
"Created: / 16-02-2017 / 01:41:33 / cg"
!
canSprayHolder
^ self imageIsLoadedAndNotReadonlyHolder
"Created: / 16-02-2017 / 01:44:47 / cg"
!
colorMapMenuHolder
^ [ self class colorMapMenu ]
"Created: / 31-08-2017 / 18:47:17 / cg"
!
imageIsLoadedAndAllowedToChangeImageDimension
"returns whether an image is loaded as value holder"
^ [
self imageIsLoadedHolder value
and:[ self allowedToChangeImageDimension ]
]
"Created: / 16-02-2017 / 01:58:41 / cg"
!
imageIsLoadedAndAllowedToChangeImageDimensionAndDepth
"returns whether an image is loaded as value holder"
^ [
self imageIsLoadedHolder value
and:[ self allowedToChangeImageDimensionAndDepth ]
]
"Modified: / 04-07-2010 / 10:15:43 / cg"
!
imageIsLoadedAndAllowedToFlipHolder
^ self imageIsLoadedAndNotReadonlyHolder
"Created: / 16-02-2017 / 01:57:02 / cg"
!
imageIsLoadedAndClassDefined
"returns whether an image is loaded as value holder"
^ [self hasClassAndSelectorDefinedHolder value
and:[self imageIsLoadedHolder value]]
"Created: / 31-07-1998 / 02:04:18 / cg"
"Modified: / 04-07-2010 / 10:15:48 / cg"
!
imageIsLoadedAndNotReadonlyHolder
"returns whether an image is loaded and editable as value holder"
^ BlockValue
with:[:loaded | loaded and:[ self readOnly not ]]
argument:(self imageIsLoadedHolder)
"Modified: / 16-02-2017 / 12:11:31 / cg"
!
imageIsLoadedHolder
"returns whether an image is loaded as value holder"
|holder|
(holder := builder bindingAt:#imageIsLoaded) isNil ifTrue:[
builder aspectAt:#imageIsLoaded put:(holder := false asValue).
].
^ holder
"Created: / 04-07-2010 / 10:15:38 / cg"
! !
!ImageEditor methodsFor:'menu item visibility'!
isNotStandAloneAndMethodSaveAndLoadMenuItemsVisible
^ self isNotStandAlone and:[ self methodSaveAndLoadMenuItemsVisible ]
!
isStandAloneAndMethodSaveAndLoadMenuItemsVisible
^ self isStandAlone and:[ self methodSaveAndLoadMenuItemsVisible ]
!
methodSaveAndLoadMenuItemsVisible
^ true
!
modeMenuVisible
^ true
! !
!ImageEditor methodsFor:'menu modes'!
colorMapMode
"returns the colorMapMode"
colorMapMode isNil ifTrue: [colorMapMode := '' asValue].
^colorMapMode
!
editMode
"returns editMode"
editMode isNil ifTrue: [
editMode := #point asValue.
editMode onChangeEvaluate:[imageEditView editMode:(editMode value)]
].
^editMode
!
mouseKeyColorMode
"returns mouseKeyColorMode"
mouseKeyColorMode isNil ifTrue:[
mouseKeyColorMode := 1 asValue.
mouseKeyColorMode onChangeEvaluate: [
imageEditView mouseKeyColorMode:mouseKeyColorMode value.
self selectedColors value:{ self listOfColors indexOf:imageEditView selectedColor }.
]
].
^mouseKeyColorMode
"Modified: / 10.2.2000 / 23:16:42 / cg"
! !
!ImageEditor methodsFor:'private'!
askForDepthThenDo:aBlock
|oldDepth suggestion depth|
oldDepth := self image depth.
suggestion := LastDepth notNil ifTrue:[
LastDepth
] ifFalse:[
oldDepth > 8
ifTrue:[8]
ifFalse:[(oldDepth // 2 - 1) nextPowerOf2]
].
depth := Dialog request:'New depth ?' initialAnswer:suggestion asString.
depth isEmptyOrNil ifTrue:[^ self].
depth := Number readFrom:depth onError:nil.
depth isNil ifTrue:[^ self].
LastDepth := depth.
aBlock value:depth
"Created: / 24-08-2017 / 17:05:39 / cg"
"Modified: / 30-08-2017 / 01:22:36 / cg"
!
checkModified
imageEditView modified value ifTrue:[
(Dialog
confirm:(resources string:'Image was not saved. Proceed anyway ?')
yesLabel:(resources string:'Proceed')
noLabel:(resources string:'Cancel')
initialAnswer:false
) ifFalse: [^false].
imageEditView clearModified.
].
^ true
"Modified: / 29.7.1998 / 18:55:24 / cg"
!
clearModifiedAndRememberImageSaved
"called after a save-to-xxx operation"
self clearModified.
savedImage := self image.
!
clearModifiedAndRememberImageSavedAsFile:file
"called after a save-to-file operation"
self clearModifiedAndRememberImageSaved.
savedFile := file.
!
pointFromString:aString
|p s x y|
p := Object readFromString:aString onError:nil.
p isPoint ifTrue:[^ p].
s := aString readStream.
x := Number readFrom:s onError:nil.
x notNil ifTrue:[
s skipSeparators.
[s atEnd not and:[s peek isDigit not]] whileTrue:[s next].
y := Number readFrom:s onError:nil.
^ x @ (y ? x)
].
^ nil
!
sortBlockForColors
^ self sortBlockForColorsByHLS.
"/ ^ self sortBlockForColorsByRGB
!
sortBlockForColorsByHLS
^ [:a :b |
|h1 h2 s1 s2 l1 l2|
h1 := a hue ? 0.
h2 := b hue ? 0.
(h1 between: h2-30 and:h2+30) ifTrue:[
l1 := a light.
l2 := b light.
l1 = l2 ifTrue:[
a saturation < b saturation
] ifFalse:[
l1 < l2
].
"/ s1 := a saturation.
"/ s2 := b saturation.
"/ s1 = s2 ifTrue:[
"/ a light < b light
"/ ] ifFalse:[
"/ s1 < s2
"/ ]
] ifFalse:[
h1 < h2
]
]
!
sortBlockForColorsByRGB
^ [:a :b |
a redByte == b redByte ifTrue:[
a greenByte == b greenByte ifTrue:[
a blueByte < b blueByte
] ifFalse:[
a greenByte < b greenByte
]
] ifFalse:[
a redByte < b redByte
]
]
!
updateImage
|img|
img := imageEditView image.
imageEditView image:img.
self fetchImageData.
self imageIsLoadedHolder changed.
"Modified: / 16-02-2017 / 12:18:08 / cg"
!
updateImagePreView
self tileModeHolder value ifTrue:[
self imagePreView tileMode:true tileOffset:(self image extent).
].
self imagePreView
setImage:(self image) scroll:false invalidate:false; "/ true.
invalidate.
! !
!ImageEditor methodsFor:'queries'!
hasAlphaChannel
|img|
img := self image.
img isNil ifTrue:[^ false].
^ img hasAlphaChannel
"Created: / 05-09-2017 / 08:29:23 / cg"
!
hasLastGrabScreenArea
^ [ lastGrabbedScreenArea notNil ]
!
hasMask
|img|
img := self image.
img isNil ifTrue:[^ false].
img mask isNil ifTrue:[^ false].
^ colorMapMode value notNil and:[colorMapMode value startsWith:'mask']
"Created: / 18-08-1998 / 17:17:38 / cg"
"Modified: / 05-09-2017 / 08:28:44 / cg"
!
hasMaskHolder
^ [ self hasMask ]
"Created: / 18-02-2017 / 00:41:19 / cg"
!
hasTransparentColorInColorList
^ self hasMask or:[self hasAlphaChannel]
"Created: / 05-09-2017 / 09:03:24 / cg"
!
modified
"true if the image was modified"
^ imageEditView modified
"Modified (comment): / 20-02-2017 / 16:23:32 / cg"
!
modified:aBoolean
super modified:aBoolean.
imageEditView modified:aBoolean
!
preferredExtent
"returns the preferred extent"
^ super preferredExtent max: ((Screen current width//3)@(Screen current height//3.5))
"Modified (format): / 13-04-2017 / 09:52:25 / cg"
! !
!ImageEditor methodsFor:'selection'!
magnification
"returns the magnification of the image"
self imageEditView isNil ifTrue: [^1].
^imageEditView magnification x
!
magnification: aValue
"sets the magnification of the image"
|magnification|
magnification := (aValue ? 1) asPoint.
(magnification = imageEditView magnification or: [magnification = (0@0)]) ifTrue: [^nil].
imageEditView magnification: magnification
!
selectedColorIndex
"returns the index of the selected color"
^selectedColorIndex
!
selectedColorIndex: anIndex
"sets the index of the selected color"
|clr pixel|
selectedColorIndex := anIndex.
anIndex isNil ifTrue:[^ self].
clr := self listOfColors at:anIndex ifAbsent:nil.
clr isNil ifTrue:[^ self].
pixel := anIndex - 1.
(self listOfColors at:1) = Color noColor ifTrue:[
anIndex == 1 ifTrue:[
pixel := nil. "/ mask
] ifFalse:[
pixel := pixel - 1
]
].
imageEditView selectedColor:clr.
imageEditView selectedColorIndex:pixel.
"Modified: / 17-02-2017 / 16:29:09 / cg"
! !
!ImageEditor methodsFor:'startup & release'!
closeDownViews
builder notNil ifTrue:[
DefaultRelativeSizes :=
Array
with:(builder componentAt:#mainPanel) relativeCorners
with:(builder componentAt:#verticalPanel) relativeCorners.
].
super closeDownViews
!
closeRequest
"asks for permission before closing"
imageEditView checkModified ifTrue:[
super closeRequest
]
!
commonPostBuild
imageEditView undoImages addDependent:self.
imageEditView imageInfoHolder:(self imageInfoHolder).
imageEditView activityInfoHolder:(self activityInfoHolder).
imageEditView clickInfoCallBack:[:button :point |
|mouseButtonColorToolBar|
button <= 2 ifTrue:[
mouseButtonColorToolBar := self componentAt:#MouseButtonColorToolBar.
(mouseButtonColorToolBar itemAt:button) toggleIndication.
mouseButtonColorToolBar do: [:i| i updateIndicators].
].
].
imageEditView addDependent:self.
imageEditView modifiedHolder addDependent:self.
DefaultRelativeSizes notNil ifTrue:[
(builder componentAt:#mainPanel) relativeCorners:DefaultRelativeSizes first.
(builder componentAt:#verticalPanel) relativeCorners:DefaultRelativeSizes second.
].
"/ using masters infoHolder ?
self useAlienInfoLabel ifTrue:[
(builder componentAt:#mainPanel) layout bottomOffset:0.
(builder componentAt:#infoBarSubSpec) beInvisible
]
"Modified: / 20-02-2018 / 13:05:30 / stefan"
!
open
"after opening, gets the imageEditView"
super open.
imageEditView := (self componentAt: #imageEditView) subViews first.
"Modified (comment): / 05-09-2017 / 10:39:45 / cg"
!
postOpenWith:aBuilder
"after opening, sets the masterApplication of the imageEditView to self;
evaluate the postOpenAction"
postOpenAction value.
super postOpenWith:aBuilder.
aBuilder keyboardProcessor menuBar:nil.
self windowGroup addPreEventHook:self.
self colorCropTabSelectionIndexChanged.
self drawingColor1Holder valueHolder:(imageEditView drawingColorHolders at:1).
self drawingColor2Holder valueHolder:(imageEditView drawingColorHolders at:2).
imageEditView drawingAlpha:(self alphaHolder value).
"Modified (format): / 05-09-2017 / 10:40:10 / cg"
! !
!ImageEditor methodsFor:'user actions-colormap'!
addColorToColormap
"undoable: add black (a new color) to the map"
self addColorToColormap:(Color black) undoable:true
"Modified: / 31-08-2017 / 14:30:32 / cg"
!
addColorToColormap:newColor
"undoable
when editing a palette image, the new color is added to the image's colorMap
(unless it is full).
When editing a true-color image, it is added to my own list-of-colors,
which only holds drawing colors, but is not the colormap's image"
|depth img cMap newColorMap newImage oldCListSize newMode listOfColors|
img := self image.
img isNil ifTrue:[
self warn:'No Image.'.
^ self
].
depth := img depth.
cMap := img colorMap.
(cMap isNil or:[cMap isMappedPalette or:[cMap isFixedPalette]]) ifTrue:[
drawingColormap isNil ifTrue:[
self information:(resources stringWithCRs:'Image has no colormap.\The shown colorMap is for drawing only.').
drawingColormap := OrderedCollection new.
].
drawingColormap add:newColor.
self listOfColors contents:drawingColormap.
self selectedColors value:{drawingColormap size}.
"/ self warn:'Image has no colormap.\Change colorMap mode first.' withCRs.
^ self
].
(cMap size == (1 bitShift:depth)) ifTrue:[
depth >= 8 ifTrue:[
self warn:'No space for more colors in colormap.'.
^ self
].
(self confirm:(resources stringWithCRs:'No space for more colors in colormap.\Change depth ?'))
ifFalse:[
^ self
].
imageEditView makeUndo.
img mask notNil ifTrue:[
newMode := 'masked' , (depth*2) printString.
] ifFalse:[
newMode := 'depth' , (depth*2) printString.
].
self colorMapMode:newMode.
] ifFalse:[
imageEditView makeUndo.
].
cMap := cMap asArray.
listOfColors := self listOfColors.
oldCListSize := listOfColors size.
newColorMap := cMap copyWith:newColor.
newImage := img species new
width:(img width) height:(img height) depth:depth
fromArray:img bits.
newImage colorMap:newColorMap.
newImage fileName:img fileName.
newImage mask:(img mask copy).
(imageEditView image:newImage) notNil ifTrue:[
listOfColors contents: newImage colorMap.
self findColorMapMode.
"/ mhmh - somehow, we get two colors added ... (sigh findColorMapMode adds another one ...)
listOfColors size > (oldCListSize + 1) ifTrue:[
listOfColors removeLast
].
self selectedColors value:{listOfColors size}.
self updateLabelsAndHistory.
]
"Created: / 12-03-1999 / 00:20:28 / cg"
"Modified: / 16-02-2017 / 10:17:25 / cg"
"Modified (comment): / 31-08-2017 / 14:28:11 / cg"
!
addColorToColormap:newColor undoable:undoable
"when editing a palette image, the new color is added to the image's colorMap
(unless it is full).
When editing a true-color image, it is added to my own list-of-colors,
which only holds drawing colors, but is not the colormap's image"
|depth img cMap newColorMap newImage oldCListSize newMode listOfColors|
img := self image.
img isNil ifTrue:[
self warn:'No Image.'.
^ self
].
depth := img depth.
cMap := img colorMap.
(cMap notNil and:[cMap isMappedPalette or:[cMap isArray]]) ifTrue:[
] ifFalse:[
(cMap isNil or:[cMap isFixedPalette]) ifTrue:[
drawingColormap isNil ifTrue:[
self information:(resources stringWithCRs:'Image has no colormap.\The shown colorMap is for drawing only.').
drawingColormap := OrderedCollection new.
].
drawingColormap add:newColor.
self listOfColors contents:drawingColormap.
self selectedColors value:{drawingColormap size}.
"/ self warn:'Image has no colormap.\Change colorMap mode first.' withCRs.
^ self
].
].
(cMap size == (1 bitShift:depth)) ifTrue:[
depth >= 8 ifTrue:[
self warn:'No space for more colors in colormap.'.
^ self
].
(self confirm:(resources stringWithCRs:'No space for more colors in colormap.\Change depth ?'))
ifFalse:[
^ self
].
undoable ifTrue:[ imageEditView makeUndo ].
img mask notNil ifTrue:[
newMode := 'masked' , (depth*2) printString.
] ifFalse:[
newMode := 'depth' , (depth*2) printString.
].
self colorMapMode:newMode.
] ifFalse:[
undoable ifTrue:[ imageEditView makeUndo ].
].
cMap := cMap asArray.
listOfColors := self listOfColors.
oldCListSize := listOfColors size.
newColorMap := cMap copyWith:newColor.
newImage := img species new
width:(img width) height:(img height) depth:depth
fromArray:img bits.
newImage colorMap:newColorMap.
newImage fileName:img fileName.
newImage mask:(img mask copy).
(imageEditView image:newImage) notNil ifTrue:[
listOfColors contents: newImage colorMap.
self findColorMapMode.
"/ mhmh - somehow, we get two colors added ... (sigh findColorMapMode adds another one ...)
listOfColors size > (oldCListSize + 1) ifTrue:[
listOfColors removeLast
].
self selectedColors value:{listOfColors size}.
self updateLabelsAndHistory.
]
"Created: / 31-08-2017 / 14:30:01 / cg"
"Modified: / 08-10-2017 / 09:15:10 / cg"
!
addPastedColorToColormap
"undoable: add the color in the clipboard to the map"
|clipBoardColor|
(clipBoardColor := self clipBoardColor) isNil ifTrue:[
^ self
].
self addColorToColormap:clipBoardColor undoable:true
"Created: / 08-10-2017 / 09:04:23 / cg"
!
changeHLS
"interactive Hue/Light/Saturation editing with thumbWheels"
|bindings hueShift lightValue saturationValue originalColormap firstChange acceptChannel
shiftAction originalAvgColor avgColorHolder avgColor shiftedColor shiftProcess readySema
originalPixels p previewImage previewImageHolder originalPreviewColormap originalPreviewPixels
anyChange |
avgColorHolder := nil asValue.
previewImageHolder := nil asValue.
"/
"/ compute the averageColor in the background (while building dialog and asking user)
"/
readySema := Semaphore new.
[
|image|
image := imageEditView image.
originalColormap := image colorMap copy.
originalPixels := image bits.
previewImage := self image magnifiedPreservingRatioTo:100@100.
avgColor := originalAvgColor := previewImage "image" averageColor.
avgColorHolder value:avgColor.
previewImageHolder value: previewImage.
originalPreviewColormap := previewImage colorMap copy.
originalPreviewPixels := previewImage bits.
readySema signal.
] forkAt:7.
acceptChannel := TriggerValue new.
firstChange := true.
anyChange := false.
shiftedColor := [:clr :hShift :lFactor :sFactor |
Color
hue:((clr hue) ? 0 + hShift)
light:((clr light * (lFactor/100)) min:100)
saturation:((clr saturation * (sFactor/100)) min:100)].
shiftAction :=
[
|hShift lFactor sFactor|
acceptChannel value:true.
firstChange ifTrue:[
imageEditView makeUndo.
firstChange := false.
anyChange := true.
].
readySema notNil ifTrue:[readySema wait. readySema := nil].
hShift := hueShift value.
lFactor := lightValue value.
sFactor := saturationValue value.
avgColorHolder value:(shiftedColor value:originalAvgColor value:hShift value:lFactor value:sFactor).
previewImage
colorMap:originalPreviewColormap copy;
bits:originalPreviewPixels copy;
release;
colorMapProcessing:[:clr | shiftedColor value:clr value:hShift value:lFactor value:sFactor].
previewImageHolder value:nil; value:previewImage.
shiftProcess notNil ifTrue:[
shiftProcess terminate.
shiftProcess waitUntilTerminated.
shiftProcess := nil.
].
shiftProcess :=
[
[
imageEditView image
colorMap:originalColormap copy;
bits:originalPixels copy;
release;
colorMapProcessing:[:clr | shiftedColor value:clr value:hShift value:lFactor value:sFactor].
self updateImage.
self updateInfoLabel.
self updateImagePreView.
] ensure:[ shiftProcess := nil ].
] forkAt:7.
].
bindings := IdentityDictionary new.
bindings at:#hueShiftAmount put:(hueShift := 0 asValue).
hueShift onChangeEvaluate:shiftAction.
bindings at:#lightAmount put:(lightValue := 100 asValue).
lightValue onChangeEvaluate:shiftAction.
bindings at:#saturationAmount put:(saturationValue := 100 asValue).
saturationValue onChangeEvaluate:shiftAction.
bindings at:#acceptChannel put:acceptChannel.
bindings at:#hlsColor put:avgColorHolder.
bindings at:#previewImageHolder put:previewImageHolder.
(self openDialogInterface:#changeHLSDialogSpec withBindings:bindings)
ifFalse:[
anyChange ifTrue:[
imageEditView undo
]
].
(p := shiftProcess) notNil ifTrue:[
p waitUntilTerminated.
].
anyChange ifTrue:[
self updateImage.
self updateImagePreView.
].
"Modified: / 28-08-2017 / 13:05:35 / cg"
!
changeHLSOfColors:colorsToShift
"interactive Hue/Light/Saturation editing"
|bindings hueShift lightValue saturationValue originalColormap firstChange acceptChannel
shiftAction avgColorHolder avgColor shiftedColor shiftProcess readySema
originalPixels p previewImage previewImageHolder originalPreviewColormap originalPreviewPixels
anyChange |
avgColorHolder := nil asValue.
previewImageHolder := nil asValue.
"/
"/ compute the averageColor in the background (while building dialog and asking user)
"/
readySema := Semaphore new.
[
|image red green blue|
image := imageEditView image.
originalColormap := image colorMap copy.
originalPixels := image bits.
red := (colorsToShift collect:[:clr | clr red]) average.
green := (colorsToShift collect:[:clr | clr green]) average.
blue := (colorsToShift collect:[:clr | clr blue]) average.
avgColor := Color red:red green:green blue:blue.
avgColorHolder value:avgColor.
previewImage := self image magnifiedPreservingRatioTo:100@100.
previewImageHolder value: previewImage.
originalPreviewColormap := previewImage colorMap copy.
originalPreviewPixels := previewImage bits.
readySema signal.
] forkAt:7.
acceptChannel := TriggerValue new.
firstChange := true.
anyChange := false.
shiftedColor := [:clr :hShift :lFactor :sFactor |
Color
hue:((clr hue) ? 0 + hShift)
light:((clr light * lFactor) min:100)
saturation:((clr saturation * sFactor) min:100)].
shiftAction :=
[
|hShift lFactor sFactor|
acceptChannel value:true.
firstChange ifTrue:[
imageEditView makeUndo.
firstChange := false.
anyChange := true.
].
readySema notNil ifTrue:[readySema wait. readySema := nil].
hShift := hueShift value.
lFactor := lightValue value.
sFactor := saturationValue value.
avgColorHolder value:(shiftedColor value:avgColor value:hShift value:lFactor value:sFactor).
previewImage
colorMap:originalPreviewColormap copy;
bits:originalPreviewPixels copy;
release;
colorMapProcessing:[:clr |
(colorsToShift includes:clr) ifTrue:[
shiftedColor value:clr value:hShift value:lFactor value:sFactor.
] ifFalse:[
clr
]
].
previewImageHolder value:nil; value:previewImage.
shiftProcess notNil ifTrue:[
shiftProcess terminate.
shiftProcess waitUntilTerminated.
shiftProcess := nil.
].
shiftProcess :=
[
[
imageEditView image
colorMap:originalColormap copy;
bits:originalPixels copy;
release;
colorMapProcessing:[:clr |
(colorsToShift includes:clr) ifTrue:[
shiftedColor value:clr value:hShift value:lFactor value:sFactor.
] ifFalse:[
clr
]
].
self updateImage.
self updateInfoLabel.
self updateImagePreView.
] ensure:[ shiftProcess := nil ].
] forkAt:7.
].
bindings := IdentityDictionary new.
bindings at:#hueShiftAmount put:(hueShift := 0 asValue).
hueShift onChangeEvaluate:shiftAction.
bindings at:#lightAmount put:(lightValue := 100 asValue).
lightValue onChangeEvaluate:shiftAction.
bindings at:#saturationAmount put:(saturationValue := 100 asValue).
saturationValue onChangeEvaluate:shiftAction.
bindings at:#acceptChannel put:acceptChannel.
bindings at:#hlsColor put:avgColorHolder.
bindings at:#previewImageHolder put:previewImageHolder.
(self openDialogInterface:#changeHLSDialogSpec withBindings:bindings)
ifFalse:[
anyChange ifTrue:[
imageEditView undo
]
].
(p := shiftProcess) notNil ifTrue:[
p waitUntilTerminated.
].
anyChange ifTrue:[
self updateImage.
self updateImagePreView.
].
"Modified (comment): / 28-08-2017 / 13:04:44 / cg"
!
clearColormapEntry0AndMaskedPixels
"ensure that there is a colorMap entry with 0/0/0 at position
0 and then clear all masked pixels (to pixelValue 0).
This is required for windows icons to be really transparent"
|index colorMap|
self nonUndoableCompressColorMap.
colorMap := self image colorMap.
(colorMap includes:(Color black)) ifFalse:[
self addColorToColormap:(Color black) undoable:false.
colorMap := self image colorMap.
].
index := colorMap indexOf:(Color black).
index == 1 ifFalse:[
self nonUndoableSortColorMapWith:self sortBlockForColorsByRGB.
colorMap := self image colorMap.
].
self nonUndoableClearMaskedPixels
"Modified: / 31-08-2017 / 14:30:28 / cg"
!
clearMaskedPixels
"clear all masked pixels (to pixelValue 0)"
|newImage|
newImage := self image clearMaskedPixels.
0 to:newImage height - 1 do:[:y |
0 to:newImage width - 1 do:[:x |
(newImage maskAtX:x y:y) == 0 ifTrue:[
newImage pixelAtX:x y:y put:0
]
]
].
(imageEditView image:newImage) notNil ifTrue:[
self fetchImageData.
]
!
clipBoardColor
"return the color in the clipboard, or nil, if there is none.
If there is none, beep (if user's settings allow it)"
|clr|
clr := imageEditView getClipboardObject.
clr isColor ifFalse:[
self beepInEditor.
^ nil
].
^ clr
"Created: / 08-10-2017 / 09:02:14 / cg"
!
colorMapChanged
|img|
img := self image.
img release.
self imageEditView invalidate.
self imagePreView invalidate.
"/ (imageEditView image:img) notNil ifTrue:[
"/ self updateLabelsAndHistory.
"/ self imagePreView image:img
"/ ]
"Created: / 7.8.1998 / 22:26:10 / cg"
"Modified: / 18.8.1998 / 17:08:55 / cg"
!
colorMapMode:aMode
"calculates a new color map for the image from aMode.
This might involve the computation of a colormap
(if depth is smaller)"
|depth numColors newColorMap newImage
oldImage image newColors realColorMap oldFileName
usedColors useNearest usageCounts tmpBits tmpMap quest
prevMode maskThreshold maskImage|
oldImage := self image.
"/ rubbish; the mode is already changed
"/ prevMode := colorMapMode value.
prevMode := self colorMapModeFromImage:oldImage.
prevMode == aMode ifTrue:[^ self].
self withExecuteCursorDo:[
newColorMap := self class listOfColorMaps at:aMode.
(aMode == #depth32 or:[aMode == #masked32]) ifTrue:[
depth := 32.
] ifFalse:[
(aMode == #depth24 or:[aMode == #masked24]) ifTrue:[
depth := 24.
] ifFalse:[
(aMode == #depth16 or:[aMode == #masked16]) ifTrue:[
depth := 16.
] ifFalse:[
depth := (newColorMap size log:2) asInteger.
].
].
].
useNearest := false.
depth == 1 ifTrue:[
quest := 'Keep colormap (or use standard B&W)'
] ifFalse:[
prevMode isNil ifTrue:[
quest := 'Compute colormap (or use standard)'
] ifFalse:[
quest := 'Keep colormap (or use standard)'
]
].
"/ currently always true!!
((prevMode = aMode)
or:[depth > oldImage depth
or:[true "self confirm:(resources string:quest)"]]
) ifTrue:[
(newColorMap isOrderedCollection or:[newColorMap isFixedPalette not]) ifTrue:[
"/ keep the colormap
"/ newColorMap atAllPut:Color black.
depth > oldImage depth ifTrue:[
"/ easy - simply copy the part
numColors := 1 bitShift:oldImage depth.
0 to:numColors-1 do:[:pixel |
newColorMap at:(pixel+1) put:(oldImage colorFromValue:pixel)
].
] ifFalse:[
"/ see if all used color fit the new colormap
usedColors := oldImage usedColorsMax:(1 bitShift:depth).
(usedColors notNil and:[usedColors size > (1 bitShift:depth)]) ifTrue:[
usedColors := oldImage realUsedColors
].
(usedColors notNil and:[usedColors size <= (1 bitShift:depth)]) ifTrue:[
"/ yea - just install them
usedColors asArray keysAndValuesDo:[:idx :clr |
newColorMap at:idx put:clr
].
] ifFalse:[
"/ copy over those that are most often used.
oldImage depth < 8 ifTrue:[
tmpBits := ByteArray uninitializedNew:(oldImage width*oldImage height).
oldImage bits
expandPixels:(oldImage depth)
width:oldImage width
height:oldImage height
into:tmpBits
mapping:nil.
] ifFalse:[
oldImage depth == 8 ifTrue:[
tmpBits := oldImage bits
] ifFalse:[
colorMapMode value:prevMode.
self findColorMapMode.
self warn:(resources
stringWithCRs:'Too many used colors (%1) in image.\\You should choose one of:\\- convert the image to gray\- reduce the number of colors\- dither to depth\- choose another depth'
with: oldImage realUsedColors size ).
^ self
"/ (self confirm:('Too many used colors in image (', oldImage usedColors size printString , ').\\Dither ?' withCRs))
"/ ifFalse:[.
"/ ^ self
"/ ].
"/ self image: (Image newForDepth:depth) fromImage:oldImage.
"/ ^ self.
]
].
usageCounts := tmpBits usageCounts.
tmpMap := Array new:usageCounts size.
oldImage colorMap asArray keysAndValuesDo:[:i :clr |
tmpMap at:i put:clr
].
usageCounts sort:[:a :b | a > b] with:tmpMap.
1 to:(1 bitShift:depth) do:[:idx |
newColorMap at:idx put:(tmpMap at:idx)
].
useNearest := Dialog
confirmWithCancel:(resources
stringWithCRs:'Image requires %1 colors.\ColorMap has only space for %2\\Use nearest (or map to first color) ?'
with:usedColors size
with:(1 bitShift:depth))
labels:(resources array:#('Cancel' 'First' 'Nearest')).
useNearest isNil ifTrue:[
colorMapMode value:prevMode.
^ self "/ cancel
].
]
]
]
] ifFalse:[
"/ standard colormap
usedColors := oldImage usedColors.
(usedColors conform:[:clr | newColorMap includes:clr]) ifFalse:[
useNearest := Dialog
confirmWithCancel:(resources
stringWithCRs:'Not all colors are present in the new colormap.\\Map missing ones to nearest (or map to first color) ?'
)
labels:(resources array:#('Cancel' 'First' 'Nearest')).
useNearest isNil ifTrue:[
colorMapMode value:prevMode.
^ self "/ cancel
].
].
newColorMap := oldImage colorMap.
].
imageEditView makeUndo.
newImage := Image newForDepth:depth.
newImage depth:depth.
depth >= 16 ifTrue:[
newImage colorMap:nil.
depth == 32 ifTrue:[
newImage samplesPerPixel:4; photometric:#rgba.
] ifFalse:[
newImage samplesPerPixel:3; photometric:#rgb.
].
].
"/ newImage photometric:oldImage photometric.
oldFileName := oldImage fileName.
Image imageErrorSignal handle:[:ex|
"/ arrive here only if not all colors can be represented;
"/ then do a more expensive nearest color search
Color colorErrorSignal handle:[:ex|
colorMapMode value:prevMode.
imageEditView undo.
^ self warn:(resources string:'Conversion failed !!')
] do:[
newImage := Image newForDepth:depth.
newImage
width:oldImage width height:oldImage height depth:depth;
colorMap:newColorMap;
photometric:#palette;
bits:(ByteArray new:(newImage bytesPerRow * newImage height));
mask:oldImage mask.
oldImage
colorsFromX:0 y:0
toX:(oldImage width-1) y:(oldImage height-1)
do:[:x :y :clr |
|newColor|
(newColorMap includes:clr)
ifTrue: [newColor := clr]
ifFalse: [
newColor := clr nearestIn:newColorMap.
useNearest ifFalse:[
(newColor deltaFrom:clr) > 0.5 ifTrue:[
newColor := oldImage colorFromValue:0
]
]
].
newImage colorAtX:x y:y put:newColor.
].
image := newImage
].
] do:[
|newPhotometric|
depth == 32 ifTrue:[
newPhotometric := #rgba.
] ifFalse:[
(newColorMap notNil and:[newColorMap isOrderedCollection or:[newColorMap isFixedPalette not]]) ifTrue:[
newPhotometric := #palette
]
].
image := newImage fromImage:oldImage photometric:newPhotometric.
"/ -- nope; keep the newly determined photometric. image photometric:oldImage photometric.
].
(aMode asString startsWith:'mask') ifTrue:[
image mask isNil ifTrue:[
(oldImage depth == 32 and:[ oldImage photometric == #rgba ]) ifTrue:[
maskImage := ImageMask fromAlphaInImage:oldImage
] ifFalse:[
false "(Dialog confirm:'Generate mask from black ?' default:false)" ifTrue:[
maskThreshold := 0.1.
maskImage := Depth1Image fromImage:(image asThresholdMonochromeImage:maskThreshold).
] ifFalse:[
maskImage := ImageMask extent:image extent.
maskImage bits:(ByteArray
new:(maskImage bytesPerRow * maskImage height)
withAll:16rFF).
].
].
image mask:maskImage.
].
] ifFalse:[
image mask: nil.
oldImage mask notNil ifTrue:[
newImage depth == 32 ifTrue:[
newImage computeAlphaValuesFromMask:oldImage mask
].
].
].
(newColorMap isOrderedCollection or:[newColorMap isFixedPalette not]) ifTrue:[
realColorMap := OrderedCollection new.
image realColorMap do:[:clr|
(realColorMap includes: clr) ifFalse: [realColorMap add: clr]
].
newColors := realColorMap copyFrom: 1 to: (newColorMap size min: realColorMap size).
newColorMap do:[:clr|
((newColors size < newColorMap size) and: [(newColors includes: clr) not])
ifTrue:[
newColors add: clr
]
].
image colorMap: newColors.
].
image fileName: oldFileName.
(imageEditView image: image) notNil ifTrue:[
self fetchImageData.
]
]
"Modified: / 28-11-2017 / 16:39:03 / cg"
!
colorize
"interactive Hue editing"
|bindings hueShift lightValue saturationValue originalColormap firstChange acceptChannel
shiftAction avgColorHolder avgColor shiftedColor shiftProcess readySema
originalPixels p|
"/ compute the averageColor in the background (while asking user)
readySema := Semaphore new.
[
|image|
image := imageEditView image.
originalColormap := image colorMap copy.
avgColor := image averageColor.
originalPixels := image bits.
readySema signal.
] forkAt:7.
acceptChannel := TriggerValue new.
avgColorHolder := avgColor asValue.
firstChange := true.
shiftedColor := [:clr :hShift :lFactor :sFactor |
Color
hue:((clr hue) ? 0 + hShift)
light:((clr light * lFactor / 100) min:100)
saturation:(((clr saturation max:20) * sFactor / 100) min:100)].
shiftAction :=
[
|hShift lFactor sFactor|
acceptChannel value:true.
firstChange ifTrue:[
imageEditView makeUndo.
firstChange := false.
].
readySema notNil ifTrue:[readySema wait. readySema := nil].
hShift := hueShift value.
lFactor := lightValue value.
sFactor := saturationValue value.
avgColorHolder value:(shiftedColor value:avgColor value:hShift value:lFactor value:sFactor).
shiftProcess notNil ifTrue:[
shiftProcess terminate.
shiftProcess waitUntilTerminated.
shiftProcess := nil.
].
shiftProcess :=
[
[
imageEditView image
colorMap:originalColormap copy;
bits:originalPixels copy;
release;
colorMapProcessing:[:clr | shiftedColor value:clr value:hShift value:lFactor value:sFactor].
self updateImage.
self updateInfoLabel.
self updateImagePreView.
] ensure:[ shiftProcess := nil ].
] forkAt:7.
].
bindings := IdentityDictionary new.
bindings at:#hueShiftAmount put:(hueShift := 0 asValue).
hueShift onChangeEvaluate:shiftAction.
bindings at:#lightAmount put:(lightValue := 100 asValue).
lightValue onChangeEvaluate:shiftAction.
bindings at:#saturationAmount put:(saturationValue := 100 asValue).
saturationValue onChangeEvaluate:shiftAction.
bindings at:#acceptChannel put:acceptChannel.
bindings at:#hlsColor put:avgColorHolder.
(self openDialogInterface:#changeHLSDialogSpec withBindings:bindings)
ifFalse:[
firstChange ~~ true ifTrue:[
imageEditView undo
]
].
(p := shiftProcess) notNil ifTrue:[
p waitUntilTerminated.
].
self updateImage.
self updateImagePreView.
"Created: / 01-11-2007 / 23:27:37 / cg"
!
compressColorMap
"calculates a new color map for the image, using only used colors"
|newImage|
newImage := self image.
newImage compressColorMap.
(imageEditView image:newImage) notNil ifTrue:[
self fetchImageData.
]
!
copyColorFromColormap
imageEditView setClipboardObject:(self selectedColorOrNil)
!
doubleClickOnColor:aColorIndex
self editSelectedColor.
"Created: / 22-07-2007 / 13:14:37 / cg"
!
editSelectedColor
self processSelectedColorWith:[:clr |
|editor|
editor := ColorEditDialog new.
editor color:clr.
editor open.
editor accepted ifFalse:[
AbortOperationRequest raise.
].
editor color
]
!
fetchImageData
|image|
(image := imageEditView image) notNil ifTrue:[
self findColorMapMode.
self updateLabelsAndHistory.
self updateInfoLabel.
]
"Modified: / 24-08-2017 / 18:20:37 / cg"
!
inspectColor
|clrIndex clr|
self hasColormap ifFalse:[
clr := self selectedColorOrNil
] ifTrue:[
clrIndex := self selectedColorIndexOrNil.
clrIndex isNil ifTrue:[
^ self
].
clr := self image colorFromValue:clrIndex-1
].
clr inspect
!
inspectColormap
self hasColormap ifTrue:[
self image colorMap inspect
].
!
makeBrighter
self updateImageAfterDoing:#makeBrighter.
"Modified: / 31-08-2017 / 12:16:30 / cg"
!
makeDarker
self updateImageAfterDoing:#makeDarker.
"Modified: / 31-08-2017 / 12:16:24 / cg"
!
makeGrayScaleImage
self updateImageAfterDoing:#makeGrayScaleImage.
"Modified: / 31-08-2017 / 12:16:15 / cg"
!
makeSelectedColorBrighter
self processSelectedColorsWith:[:clr | clr lightened]
!
makeSelectedColorDarker
self processSelectedColorsWith:[:clr | clr darkened]
!
makeSelectedColorGray
self processSelectedColorsWith:[:clr | Color brightness:(clr brightness)]
!
makeSelectedColorShifted
"shift the selected color (in the colormap)
using the hls/rgb shifting slider dialog"
|cMap colors cmapOffset|
cMap := self image colorMap.
"/ if there is a mask, it is at position 1 in the table
cmapOffset := self hasTransparentColorInColorList ifTrue:[1] ifFalse:[0].
colors := self selectedColors value collect:[:idx | cMap at:idx-cmapOffset].
self changeHLSOfColors:colors.
"Modified: / 05-09-2017 / 09:03:47 / cg"
!
makeSlightlyBrighter
self updateImageAfterDoing:#makeSlightlyBrighter.
"Created: / 24-11-2010 / 11:06:11 / cg"
"Modified: / 31-08-2017 / 12:16:01 / cg"
!
makeSlightlyDarker
self updateImageAfterDoing:#makeSlightlyDarker.
"Created: / 24-11-2010 / 11:06:23 / cg"
"Modified: / 31-08-2017 / 12:15:55 / cg"
!
menu_clearColormapEntry0AndMaskedPixels
"ensure that there is a colorMap entry with 0/0/0 at position
0 and then clear all masked pixels (to pixelValue 0)"
imageEditView makeUndo.
self withExecuteCursorDo:[
self nonUndoableClearColormapEntry0AndMaskedPixels
]
"Modified: / 31-08-2017 / 14:31:21 / cg"
!
menu_clearMaskedPixels
"clear all masked pixels (to pixelValue 0)"
imageEditView makeUndo.
self withExecuteCursorDo:[
self nonUndoableClearMaskedPixels
]
"Modified: / 31-08-2017 / 14:23:20 / cg"
!
menu_compressColorMap
"calculates a new color map for the image, using only used colors"
|depth oldImage usedColors colorMap|
oldImage := self image.
oldImage photometric ~~ #palette ifTrue:[
self information:'Compress colorMap: Only palette images have colormaps.'.
^ self
].
depth := oldImage depth.
colorMap := oldImage colorMap asArray.
usedColors := oldImage realUsedColors.
usedColors size == colorMap size ifTrue:[
self information:'Compress colorMap: Colormap already compressed - no compression.'.
^ self
].
imageEditView makeUndo.
self withExecuteCursorDo:[
self nonUndoableCompressColorMap
]
"Modified: / 31-08-2017 / 14:22:19 / cg"
!
menu_copyMask
|mask|
mask := self image mask.
MaskClipboard := mask subImageIn: (0@0 extent:mask extent).
!
menu_pasteMask
|img mask|
imageEditView makeUndo.
img := self image.
mask := img mask.
mask
copyFrom:MaskClipboard
x:0 y:0
toX:0 y:0
width:(mask width min:MaskClipboard width)
height:(mask height min:MaskClipboard height).
img mask:mask.
(imageEditView image:img copy) notNil ifTrue:[
self fetchImageData.
]
!
menu_sortColorMap
"calculates a new color map for the image, sorting colors"
self menu_sortColorMapWith:self sortBlockForColors
!
menu_sortColorMapWith:sortBlock
"calculates a new color map for the image, sorting colors"
self image photometric ~~ #palette ifTrue:[
self information:'Compress colorMap: Only palette images have colormaps.'.
^ self
].
imageEditView makeUndo.
self withExecuteCursorDo:[
self nonUndoableSortColorMapWith:sortBlock
]
"Created: / 30-09-1998 / 23:51:23 / cg"
"Modified: / 31-08-2017 / 14:20:14 / cg"
!
pasteColorIntoColormap
|clipBoardColor cmap|
(clipBoardColor := self clipBoardColor) isNil ifTrue:[
^ self
].
cmap := self image colorMap.
(cmap isNil or:[cmap isMappedPalette or:[cmap isFixedPalette]]) ifTrue:[
drawingColormap isNil ifTrue:[
drawingColormap := #()
].
drawingColormap := drawingColormap copyWith:clipBoardColor.
self selectedColors value:drawingColormap size.
^ self.
].
self processSelectedColorWith:[:clr | clipBoardColor]
"Modified (format): / 08-10-2017 / 09:03:59 / cg"
!
pickAndAddColorToColormap
self addColorToColormap:(Color fromUser) undoable:true
"Modified: / 31-08-2017 / 14:30:22 / cg"
!
pickAndPasteColor
self pickColor.
self pasteColorIntoColormap.
!
pickColor
imageEditView setClipboardObject:(Color fromUser)
!
processSelectedColorWith:aBlock
"undoable color processing:
the selected color will be replaced by the value of aBlock"
self processSelectedColorsWith:aBlock.
!
processSelectedColorsWith:aBlock
"undoable color processing:
the selected colors will be replaced by the value of aBlock
(which gets a color vector and must return a color vector)"
|img cMap modifiedColormap oldColors newImage selectedColorIndices newColors maskOffset processingSubset|
selectedColorIndices := self selectedColors value.
selectedColorIndices isEmptyOrNil ifTrue:[^ self].
img := self image.
self hasTransparentColorInColorList ifTrue:[
maskOffset := 1.
] ifFalse:[
maskOffset := 0.
].
cMap := img colorMap.
(cMap isNil) ifTrue:[
oldColors := drawingColormap.
processingSubset := false.
] ifFalse:[
(cMap isMappedPalette or:[cMap isFixedPalette]) ifTrue:[
oldColors := cMap asArray.
processingSubset := false.
] ifFalse:[
oldColors := selectedColorIndices collect:[:idx | cMap at:idx-maskOffset].
processingSubset := true.
].
].
imageEditView makeUndo.
modifiedColormap := cMap asNewArray.
(selectedColorIndices max - maskOffset) > modifiedColormap size ifTrue:[
|t|
t := Array new:(selectedColorIndices max - maskOffset).
t replaceFrom:1 with:modifiedColormap.
modifiedColormap := t.
].
newColors := oldColors collect:aBlock.
processingSubset ifTrue:[
selectedColorIndices with:newColors do:[:idx :newColor |
modifiedColormap at:idx-maskOffset put:newColor.
].
] ifFalse:[
selectedColorIndices do:[:idx |
modifiedColormap at:idx-maskOffset put:(newColors at:idx-maskOffset ifAbsent:[self halt.Color black])
].
].
newImage := img species new
width:img width
height:img height
depth:img depth
fromArray:img bits.
(cMap isNil) ifTrue:[
"/ only a dummy...
] ifFalse:[
newImage colorMap:modifiedColormap.
newImage photometric:#palette.
].
newImage fileName:img fileName.
newImage mask:(img mask copy).
(imageEditView image:newImage) notNil ifTrue:[
self fetchImageData.
].
self selectedColors value:selectedColorIndices.
"Modified: / 08-10-2017 / 09:20:13 / cg"
!
reduceNumberOfColors
"reduce by masking off r/g/b bits"
|s n anyChange img usedColors|
s := Dialog request:'Number of color bits to strip (1-7) ?' initialAnswer:3.
s size == 0 ifTrue:[^ self].
n := Integer readFrom:s onError:0.
(n between:1 and:7) ifFalse:[
Dialog warn:'Image unchanged'.
^ self
].
self withExecuteCursorDo:[
anyChange := imageEditView reduceColorResolutionBy:n.
anyChange ifFalse:[
Dialog warn:'Image unchanged'.
] ifTrue:[
img := imageEditView image.
imageEditView image:img.
self fetchImageData.
usedColors := img usedColorsMax:10000.
usedColors size == 10000 ifTrue:[
Dialog information:('>= ' , usedColors size printString , ' colors used.')
] ifFalse:[
Dialog information:(usedColors size printString , ' colors used.')
]
]
].
"Modified: / 29-10-2010 / 18:08:01 / cg"
"Modified (comment): / 24-08-2017 / 20:50:28 / cg"
!
reduceNumberOfColors2
"reduce by rounding r/g/b channel values"
|s rndR rndG rndB usedColors image newImage|
s := Dialog request:'Rounding Interval red (2..) ?' initialAnswer:4.
s size == 0 ifTrue:[^ self].
rndR := Integer readFrom:s onError:0.
s := Dialog request:'Rounding Interval green (2..) ?' initialAnswer:2.
s size == 0 ifTrue:[^ self].
rndG := Integer readFrom:s onError:0.
s := Dialog request:'Rounding Interval blue (2..) ?' initialAnswer:10.
s size == 0 ifTrue:[^ self].
rndB := Integer readFrom:s onError:0.
((rndR > 1) or:[(rndG > 1) or:[(rndB > 1)]]) ifFalse:[
Dialog warn:'Image unchanged'.
^ self
].
self withExecuteCursorDo:[
|reduceColor nUsed|
reduceColor :=
[:clr |
|r g b nr ng nb|
r := clr redByte.
g := clr greenByte.
b := clr blueByte.
nr := (r roundTo:rndR) min:255.
ng := (g roundTo:rndG) min:255.
nb := (b roundTo:rndB) min:255.
Color redByte:nr greenByte:ng blueByte:nb.
].
image := self image.
"/ usedColors := image usedColorsMax:4096.
imageEditView makeUndo.
newImage := image copy.
newImage photometric == #palette ifTrue:[
newImage colorMap:(image colorMap collect:reduceColor).
] ifFalse:[
image
colorsFromX:0 y:0 toX:(image width-1) y:(image height-1)
do:[:x :y :clr |
newImage colorAtX:x y:y put:(reduceColor value:clr)
].
].
imageEditView image:newImage.
imageEditView setModified.
self updateImage.
self updateImagePreView.
self fetchImageData.
usedColors := newImage usedColorsMax:10000.
nUsed := usedColors size.
nUsed == 10000 ifTrue:[
Dialog information:('>= ' , nUsed printString , ' colors used.')
] ifFalse:[
Dialog information:(nUsed printString , ' colors used.')
]
].
"Modified: / 24-08-2017 / 18:25:04 / cg"
"Modified (comment): / 24-08-2017 / 20:50:14 / cg"
!
selectColor:aColor
|idx img cMap|
aColor isNil ifTrue:[
idx := nil.
] ifFalse:[
img := self image.
img notNil ifTrue: [
aColor == Color noColor ifTrue:[
(img mask notNil) ifTrue:[
idx := 1.
]
] ifFalse:[
(cMap := self listOfColors) notNil ifTrue:[
idx := cMap indexOf:aColor ifAbsent:nil.
].
idx isNil ifTrue:[
"/ should not happen...
(cMap := img colorMap) notNil ifTrue:[
idx := cMap indexOf:aColor ifAbsent:nil.
idx notNil ifTrue:[
img mask notNil ifTrue:[
idx := idx + 1.
].
]
].
].
].
].
].
self selectedColors value:{idx}.
"Modified: / 02-07-2010 / 12:06:07 / cg"
!
selectedColorIndexOrNil
|img clrIndex|
img := self image.
img isNil ifTrue:[
"/ self warn:'No Image.'.
^ nil
].
clrIndex := self selectionOfColor value.
self hasTransparentColorInColorList ifTrue: [
(clrIndex isInteger and:[clrIndex > 1]) ifTrue:[
^ clrIndex - 1
].
^ nil
].
^ clrIndex
"Modified: / 05-09-2017 / 09:04:05 / cg"
!
selectedColorOrNil
|cmapIndex img cMap colorList|
cmapIndex := self selectedColorIndexOrNil.
cmapIndex isNil ifTrue:[^ nil].
cmapIndex == 0 ifTrue:[^ nil].
img := self image.
cMap := img colorMap.
cMap isNil ifTrue:[
"/ self warn:(resources stringWithCRs:'Image has no colormap.\Please change the colorMap mode first.').
colorList := self listOfColors.
colorList notNil ifTrue:[
^ colorList at:cmapIndex ifAbsent:nil
].
^ nil
].
^ cMap at:cmapIndex.
!
sortColorMap
"calculates a new color map for the image, sorting colors"
self nonUndoableSortColorMapWith:self sortBlockForColorsByRGB
"Modified: / 31-08-2017 / 14:20:07 / cg"
!
sortColorMapWith:sortBlock
"warning: not undoable
calculates a new color map for the image, sorting colors"
|depth newColorMap newImage oldImage usedColors oldToNew oldBits newBits tmpBits
expectedSize w h|
oldImage := self image.
depth := oldImage depth.
w := oldImage width.
h := oldImage height.
usedColors := oldImage realColorMap.
"/ translation table
oldToNew := ByteArray new:(1 bitShift:depth).
newColorMap := usedColors asArray.
newColorMap sort:sortBlock.
oldImage colorMap asArray keysAndValuesDo:[:oldIdx :clr |
|newPixel|
(usedColors includes:clr) ifTrue:[
newPixel := newColorMap indexOf:clr.
oldToNew at:oldIdx put:newPixel-1.
]
].
oldBits := oldImage bits.
"/ sanity check...
expectedSize := ((w * h * depth + 7) // 8).
(oldBits size < expectedSize) ifTrue:[
self halt:'incorrect pixeldata size'.
oldBits := (ByteArray new:expectedSize) replaceFrom:1 with:oldBits; yourself.
].
newBits := ByteArray new:(oldBits size).
depth ~~ 8 ifTrue:[
"/ expand/compress can only handle 8bits
tmpBits := ByteArray uninitializedNew:(w*h).
oldBits
expandPixels:depth
width:w height:h
into:tmpBits
mapping:oldToNew.
tmpBits
compressPixels:depth
width:w height:h
into:newBits
mapping:nil
] ifFalse:[
oldBits
expandPixels:depth
width:w height:h
into:newBits
mapping:oldToNew.
].
newImage := oldImage species new
width:w height:h depth:depth
fromArray:newBits.
newImage colorMap:newColorMap.
newImage fileName:oldImage fileName.
newImage mask:(oldImage mask copy).
(imageEditView image:newImage) notNil ifTrue:[
self fetchImageData.
]
"Modified: / 15-09-1998 / 17:53:32 / cg"
"Created: / 30-09-1998 / 23:51:23 / cg"
"Modified (comment): / 31-08-2017 / 14:19:21 / cg"
!
updateImageAfterDoing:aBlockOrSelector
self withExecuteCursorDo:[
aBlockOrSelector value:imageEditView.
self updateImage.
].
"Created: / 31-08-2017 / 12:14:39 / cg"
! !
!ImageEditor methodsFor:'user actions-colormap-basic'!
nonUndoableClearColormapEntry0AndMaskedPixels
"ensure that there is a colorMap entry with 0/0/0 at position
0 and then clear all masked pixels (to pixelValue 0).
This is required for windows icons to be really transparent"
|index colorMap|
self nonUndoableCompressColorMap.
colorMap := self image colorMap.
(colorMap includes:(Color black)) ifFalse:[
self addColorToColormap:(Color black) undoable:false.
colorMap := self image colorMap.
].
index := colorMap indexOf:(Color black).
index == 1 ifFalse:[
self nonUndoableSortColorMapWith:self sortBlockForColorsByRGB.
colorMap := self image colorMap.
].
self nonUndoableClearMaskedPixels
"Created: / 31-08-2017 / 14:31:09 / cg"
!
nonUndoableClearMaskedPixels
"clear all masked pixels (to pixelValue 0)"
|newImage|
newImage := self image clearMaskedPixels.
0 to:newImage height - 1 do:[:y |
0 to:newImage width - 1 do:[:x |
(newImage maskAtX:x y:y) == 0 ifTrue:[
newImage pixelAtX:x y:y put:0
]
]
].
(imageEditView image:newImage) notNil ifTrue:[
self fetchImageData.
]
"Created: / 31-08-2017 / 14:22:58 / cg"
!
nonUndoableCompressColorMap
"not undoable
calculates a new color map for the image, using only used colors"
|newImage|
newImage := self image.
newImage compressColorMap.
(imageEditView image:newImage) notNil ifTrue:[
self fetchImageData.
]
"Created: / 31-08-2017 / 14:21:51 / cg"
!
nonUndoableSortColorMapWith:sortBlock
"not undoable
calculates a new color map for the image, sorting colors"
|depth newColorMap newImage oldImage usedColors oldToNew oldBits newBits tmpBits
expectedSize w h|
oldImage := self image.
depth := oldImage depth.
w := oldImage width.
h := oldImage height.
usedColors := oldImage realColorMap.
"/ translation table
oldToNew := ByteArray new:(1 bitShift:depth).
newColorMap := usedColors asArray.
newColorMap sort:sortBlock.
oldImage colorMap asArray keysAndValuesDo:[:oldIdx :clr |
|newPixel|
(usedColors includes:clr) ifTrue:[
newPixel := newColorMap indexOf:clr.
oldToNew at:oldIdx put:newPixel-1.
]
].
oldBits := oldImage bits.
"/ sanity check...
expectedSize := ((w * h * depth + 7) // 8).
(oldBits size < expectedSize) ifTrue:[
self halt:'incorrect pixeldata size'.
oldBits := (ByteArray new:expectedSize) replaceFrom:1 with:oldBits; yourself.
].
newBits := ByteArray new:(oldBits size).
depth ~~ 8 ifTrue:[
"/ expand/compress can only handle 8bits
tmpBits := ByteArray uninitializedNew:(w*h).
oldBits
expandPixels:depth
width:w height:h
into:tmpBits
mapping:oldToNew.
tmpBits
compressPixels:depth
width:w height:h
into:newBits
mapping:nil
] ifFalse:[
oldBits
expandPixels:depth
width:w height:h
into:newBits
mapping:oldToNew.
].
newImage := oldImage species new
width:w height:h depth:depth
fromArray:newBits.
newImage colorMap:newColorMap.
newImage fileName:oldImage fileName.
newImage mask:(oldImage mask copy).
(imageEditView image:newImage) notNil ifTrue:[
self fetchImageData.
]
"Created: / 31-08-2017 / 14:19:42 / cg"
! !
!ImageEditor methodsFor:'user actions-editing'!
autoCropAll
"find all borders and cut them off"
imageEditView autoCropLeft:true right:true top:true bottom:true.
self updateInfoLabel
"Created: / 20-02-2017 / 18:05:38 / cg"
!
autoCropBottom
"find a bottom border and cut it off"
imageEditView autoCropLeft:false right:false top:false bottom:true.
self updateInfoLabel
"Created: / 20-02-2017 / 18:05:45 / cg"
!
autoCropLeft
"find a left border and cut it off"
imageEditView autoCropLeft:true right:false top:false bottom:false.
self updateInfoLabel
"Created: / 20-02-2017 / 18:05:52 / cg"
!
autoCropRight
"find a right border and cut it off"
imageEditView autoCropLeft:false right:true top:false bottom:false.
self updateInfoLabel
"Created: / 20-02-2017 / 18:04:20 / cg"
!
autoCropTop
"find a top border and cut it off"
imageEditView autoCropLeft:false right:false top:true bottom:false.
self updateInfoLabel
"Created: / 20-02-2017 / 18:06:03 / cg"
!
ditherGrayToDepth
self askForDepthThenDo:[:depth |
self ditherGrayToDepth:depth
].
"Created: / 24-08-2017 / 17:49:42 / cg"
!
ditherGrayToDepth:depth
self withExecuteCursorDo:[
|image newImage|
image := self image.
depth == 1 ifTrue:[
newImage := image asErrorDitheredMonochromeImage
] ifFalse:[
newImage := image asGrayImageDepth:depth dither:#floydSteinberg.
].
imageEditView newImageWithUndo:newImage.
].
"Created: / 24-08-2017 / 17:51:07 / cg"
"Modified: / 23-10-2017 / 10:58:18 / cg"
!
ditherToDepth
self askForDepthThenDo:[:depth |
self convertToDepth:depth dither:true
].
"Created: / 07-07-2006 / 13:22:10 / cg"
"Modified: / 30-08-2017 / 00:34:42 / cg"
!
ditherToNumberOfGrayColors
|oldDepth numGrayColors suggestion grayImage userInput grayColors|
oldDepth := self image depth.
grayImage := self image asGrayImageDepth:8.
suggestion := LastNumThresholdGrayColors notNil ifTrue:[
LastNumThresholdGrayColors
] ifFalse:[
oldDepth > 8
ifTrue:[256]
ifFalse:[2 raisedTo:((oldDepth // 2 - 1) nextPowerOf2)]
].
Dialog modifyingBoxWith:[:box |
|preview slider update thresholdValue|
thresholdValue := suggestion asValue.
box enterField
converter:(PrintConverter new initForNumber);
model:thresholdValue.
box verticalPanel extent:1.0 @ 300.
box verticalPanel add:(slider := HorizontalSlider new start:2 stop:256 step:1).
slider model:thresholdValue.
slider width:1.0; leftInset:4; rightInset:4.
box verticalPanel add:(preview := ImageView new).
preview extent:300 @300.
preview level:-1.
box verticalPanel horizontalLayout:#fitSpace.
update :=
[
|numGrayColors depth s t tImage|
numGrayColors := thresholdValue value clampBetween:2 and:256.
grayColors := Color grayColorVector:numGrayColors.
tImage := grayImage asDitheredImageUsing:grayColors depth:(grayImage depth).
preview image:(tImage magnifiedPreservingRatioTo:preview extent).
].
update value.
box enterField acceptOnLostFocus:true.
box enterField acceptOnLeave:true.
thresholdValue onChangeEvaluate:update.
] do:[
userInput := Dialog request:'Number of Gray Colors ?' initialAnswer:suggestion asString.
].
userInput isEmptyOrNil ifTrue:[^ self].
numGrayColors := Number readFrom:userInput onError:nil.
numGrayColors isNil ifTrue:[^ self].
grayColors := Color grayColorVector:numGrayColors.
imageEditView newImageWithUndo:(grayImage asDitheredImageUsing:grayColors depth:(grayImage depth)).
"Created: / 23-10-2017 / 11:17:44 / cg"
!
do3DProjection
"make a naive 3D projection;
can be used to create those typical marketing images as seen in web pages"
|box dx1 dx2 image|
image := imageEditView image.
box := EnterBox new.
box title:(resources string:'dX1 (0 < dx < 0.5):').
box okText:(resources string:'OK').
box abortText:(resources string:'Cancel').
box initialText:'0.1'.
box showAtPointer.
(box accepted
and: [(dx1 := Number readFrom:(box contents) onError:nil) notNil])
ifTrue:[
box title:(resources string:'dX2 (0 < dx < 0.5):').
box initialText:(dx1 printString).
box showAtPointer.
(box accepted
and: [(dx2 := Number readFrom:(box contents) onError:nil) notNil])
ifTrue:[
imageEditView threeDProjection:dx1 and:dx2.
]
].
self updateInfoLabel
"Modified (comment): / 31-08-2017 / 13:58:03 / cg"
!
doBrightenImage
imageEditView brightenImage.
self listOfColors removeAll.
self findColorMapMode.
"/ imageEditView removelastUndo
!
doBrowseClass
"opens a System Browser on the resourceClass and the resourceSelector"
|cls|
cls := imageEditView resourceClass.
cls isNil ifTrue:[^ self warn:'No Class specified'].
cls browserClass
openInClass:cls class
selector:(imageEditView resourceSelector)
"Modified: / 31.7.1998 / 02:01:15 / cg"
!
doCopyImageToClipboard
imageEditView copyImageToClipboard.
!
doCropManual
"let user specify borders and cut them off"
|bindings left top right bottom img firstChange cropAction acceptChannel|
acceptChannel := TriggerValue new.
firstChange := true.
cropAction :=
[:lV :rV :tV :bV | |l r t b|
acceptChannel value:true.
l := lV value.
r := rV value.
t := tV value.
b := bV value.
(l + r + t + b) == 0 ifTrue:[
self window beepInEditor
] ifFalse:[
img := imageEditView image.
firstChange ifTrue:[
imageEditView makeUndo.
firstChange := false.
].
imageEditView
makeSubImageX:l y:t
width:(img width - l - r)
height:(img height - t - b).
self updateImagePreView.
self updateInfoLabel
].
].
bindings := IdentityDictionary new.
bindings at:#cropLeftAmount put:(left := 1 asValue).
bindings at:#cropRightAmount put:(right := 1 asValue).
bindings at:#cropTopAmount put:(top := 1 asValue).
bindings at:#cropBottomAmount put:(bottom := 1 asValue).
bindings at:#acceptChannel put:acceptChannel.
bindings at:#cropLeftNow put:[ cropAction value:left value:0 value:0 value:0 ].
bindings at:#cropRightNow put:[ cropAction value:0 value:right value:0 value:0 ].
bindings at:#cropTopNow put:[ cropAction value:0 value:0 value:top value:0 ].
bindings at:#cropBottomNow put:[ cropAction value:0 value:0 value:0 value:bottom ].
bindings at:#applyCropAction put:[ cropAction value:left value:right value:top value:bottom ].
bindings at:#cropBoxIsDialog put:true.
(self openDialogInterface:#cropSpec withBindings:bindings)
ifFalse:[
firstChange ~~ true ifTrue:[
imageEditView undo.
self updateImagePreView.
]
].
"Created: / 07-09-1998 / 18:16:07 / cg"
"Modified: / 19-02-2017 / 15:43:50 / cg"
!
doDarkenImage
imageEditView darkenImage.
self listOfColors removeAll.
self findColorMapMode.
"/ imageEditView removelastUndo
!
doEditMask
|mask|
(mask := self image mask) notNil ifTrue:[
mask edit
].
"Modified: / 18-02-2017 / 00:38:51 / cg"
!
doFlipHorizontal
"flips horizontally current image"
imageEditView flipHorizontal
!
doFlipVertical
"flips vertically current image"
imageEditView flipVertical
!
doInsertTextFromUser
|text tempForm tempImage maskImage font w h paintColor|
text := Dialog request:'Text to be inserted (placed as bitmap into clipboard for paste):'.
text isEmptyOrNil ifTrue:[^ self ].
font := Font family:'arial' size:20.
font := font onDevice:Screen current.
w := font widthOf:text.
h := font heightOf:text.
tempForm := Form extent:(w@h) depth:1 onDevice:(Screen current).
tempForm clear.
tempForm font:font.
tempForm paint:(Color colorId:1).
tempForm displayString:text at:(0@font ascent).
tempImage := tempForm asImage.
maskImage := tempForm asImage.
paintColor := imageEditView selectedColor.
paintColor colorId == 0 ifTrue:[
paintColor := Color black
].
tempImage
photometric:#palette;
colorMap:(Array
with:Color white
with:paintColor);
mask:maskImage.
ImageEditView copyImageToClipboard:tempImage.
self editMode value:#paste.
"Modified: / 11-11-2007 / 12:32:55 / cg"
!
doInspectImage
"opens a System Browser on the resourceClass and the resourceSelector"
self image inspect
!
doInvertedBitsImage
"inverts the pixels"
self withExecuteCursorDo:[
imageEditView makeInvertedBits.
self updateImage.
].
"/
"/ imageEditView negativeImage.
"/ self listOfColors removeAll.
"/ self findColorMapMode.
"/ "/ imageEditView removelastUndo
"/
"/
"Created: / 31-08-2017 / 12:49:13 / cg"
!
doMagnifyDown
"magnifies the current image one step down"
|magHolder mag|
magHolder := self magnificationHolder.
(mag := magHolder value) > 1 ifTrue: [
magHolder value: mag - 1
]
"Modified: / 26.7.1998 / 20:24:08 / cg"
!
doMagnifyImage
"magnifies the current image to a new size"
|box newSize image antiAliased|
antiAliased := (LastMagnifySmoothing ? false) asValue.
image := imageEditView image.
box := EnterBox new.
box title:(resources string:'Images new size:').
box okText:(resources string:'OK').
box abortText:(resources string:'Cancel').
box initialText:(LastMagnifyTo ? image extent) printString.
box verticalPanel add:(CheckBox label:(resources string:'Antialias/Smooth') model:antiAliased).
box showAtPointer.
(box accepted
and: [(newSize := self pointFromString:(box contents)) notNil])
ifTrue:[
newSize isPoint ifFalse:[
self warn:'Please enter the new size as ''x @ y''.'.
^ self.
].
LastMagnifyTo := newSize.
LastMagnifySmoothing := antiAliased value.
antiAliased value ifTrue:[
((newSize x < image width) or:[(newSize y < image height)]) ifTrue:[
imageEditView magnifySmoothingTo:newSize.
] ifFalse:[
imageEditView magnifyAntiAliasedImageTo:newSize.
].
] ifFalse:[
imageEditView magnifyImageTo:newSize.
].
].
self updateInfoLabel
"Modified: / 30-08-2017 / 15:46:02 / cg"
!
doMagnifyImageBy
"magnifies the current image (by a scale)"
|oldSize newSize scaleString scale image smoothing|
image := imageEditView image.
oldSize := image extent.
smoothing := (LastMagnifySmoothing ? false) asValue.
Dialog modifyingBoxWith:[:box |
box verticalPanel add:(CheckBox label:(resources string:'Antialias/Smooth') model:smoothing).
"/ box verticalPanel add:(CheckBox label:(resources string:'Smoothing') model:smoothing).
] do:[
scaleString := Dialog
request:(resources string:'Scale factor (<1 to shrink; >1 to magnify):')
initialAnswer:(LastMagnifyBy ? 1) printString
list:#('0.1' '0.25' '0.3' '0.5' '1.5' '2' '3' '4').
].
scaleString isNil ifTrue:[^ self].
scale := Object readFromString:scaleString onError:nil.
scale notNil ifTrue:[
scale isNumber ifFalse:[
self warn:'please enter a scale factor (<1 to shrink; >1 to magnify).'.
^ self.
].
LastMagnifyBy := scale.
LastMagnifySmoothing := smoothing value.
newSize := oldSize * scale.
smoothing value ifTrue:[
scale < 1 ifTrue:[
imageEditView magnifySmoothingBy:scale.
] ifFalse:[
imageEditView magnifyAntiAliasedImageTo:newSize.
].
] ifFalse:[
imageEditView magnifyImageTo:newSize.
].
].
self updateInfoLabel
"Modified: / 30-08-2017 / 15:34:56 / cg"
!
doMagnifyUp
"magnifies the current image one step up"
|magHolder mag|
magHolder := self magnificationHolder.
(mag := magHolder value) < 63 ifTrue: [
magHolder value: mag + 1
]
"Modified: / 26.7.1998 / 20:23:52 / cg"
!
doResizeImage
"resizes the current image"
|box newSize image|
image := imageEditView image.
box := EnterBox new.
box title:(resources string:'Images new size:').
box okText:(resources string:'OK').
box abortText:(resources string:'Cancel').
box initialText:image extent printString.
box showAtPointer.
(box accepted
and: [(newSize := self pointFromString:(box contents)) notNil])
ifTrue:[
imageEditView resizeImageTo:newSize.
].
!
doRotateImage
"rotates current image"
|rotationString box rotation|
rotationString := Dialog
request:(resources string:'Rotate by (degrees, clockwise):')
list:#( '-90' '90' '180' '45' '-45' '135' '-135' )
initialAnswer:90.
rotationString isEmptyOrNil ifTrue:[^ self]. "/ canceled
rotation := Number readFrom:rotationString onError:[nil].
rotation isNil ifTrue:[^ self].
"/ box := EnterBox new.
"/ box title:(resources string:'Rotate by (degrees, clockwise):').
"/ box okText:(resources string:'OK').
"/ box abortText:(resources string:'Cancel').
"/ box initialText: '0'.
"/ box showAtPointer.
"/ (box accepted and: [(rotation := Number readFromString: box contents onError:nil) notNil])
"/ ifFalse:[ ^ self ].
imageEditView rotateImageBy:rotation.
self updateInfoLabel.
"Modified: / 18-03-2012 / 14:41:14 / cg"
"Modified (comment): / 24-08-2017 / 15:02:57 / cg"
!
doShiftManual
"let user specify amount and shift"
|bindings amount img firstChange shiftAction acceptChannel wrapHolder|
acceptChannel := TriggerValue new.
wrapHolder := (lastShiftUsedWrap ? true) asValue.
firstChange := true.
shiftAction :=
[:shiftH :shiftV |
acceptChannel value:true.
img := imageEditView image.
firstChange ifTrue:[
imageEditView makeUndo.
firstChange := false.
].
imageEditView shiftImageHorizontal:(shiftH value) vertical:(shiftV value) wrap:(wrapHolder value).
self updateInfoLabel
].
bindings := IdentityDictionary new.
bindings at:#shiftAmount put:(amount := 1 asValue).
bindings at:#wrap put:wrapHolder.
bindings at:#acceptChannel put:acceptChannel.
bindings at:#shiftLeftNow put:[ shiftAction value:(-1*amount value) value:0 ].
bindings at:#shiftRightNow put:[ shiftAction value:amount value value:0 ].
bindings at:#shiftUpNow put:[ shiftAction value:0 value:(-1*amount value) ].
bindings at:#shiftDownNow put:[ shiftAction value:0 value:amount value ].
(self openDialogInterface:#shiftDialogSpec withBindings:bindings)
ifFalse:[
firstChange ~~ true ifTrue:[
imageEditView undo
]
].
lastShiftUsedWrap := wrapHolder value.
"Created: / 7.9.1998 / 18:16:07 / cg"
"Modified: / 7.9.1998 / 18:20:42 / cg"
!
doUnCropManual
"let user specify borders and add them"
|bindings leftAmount topAmount rightAmount bottomAmount img|
bindings := IdentityDictionary new.
bindings at:#cropLeftAmount put:(leftAmount := 1 asValue).
bindings at:#cropRightAmount put:(rightAmount := 1 asValue).
bindings at:#cropTopAmount put:(topAmount := 1 asValue).
bindings at:#cropBottomAmount put:(bottomAmount := 1 asValue).
bindings at:#cropBoxIsDialog put:true.
(self openDialogInterface:#uncropSpec withBindings:bindings)
ifTrue:[
leftAmount := leftAmount value.
rightAmount := rightAmount value.
topAmount := topAmount value.
bottomAmount := bottomAmount value.
img := imageEditView image.
imageEditView
makeBorderedImageX:leftAmount y:topAmount
width:(img width + leftAmount + rightAmount)
height:(img height + topAmount + bottomAmount).
self updateInfoLabel
].
"Created: / 07-09-1998 / 18:16:07 / cg"
"Modified: / 19-02-2017 / 15:31:00 / cg"
!
doUndo
"reverses last edit action"
imageEditView undo.
self updateImagePreView
!
makeInverse
"inverts the pixels - for palettes, this leads to funny results"
self updateImageAfterDoing:#makeInverse.
"Modified: / 31-08-2017 / 12:16:07 / cg"
"Modified (comment): / 31-08-2017 / 13:51:28 / cg"
!
makeMonochromeImage
"let user choose a threshold, then convert to monochrome"
|image userInput thresholdBrighness|
image := imageEditView image.
Dialog modifyingBoxWith:[:box |
|preview slider update thresholdValue|
thresholdValue := 0.5 asValue.
box enterField
converter:(PrintConverter new initForNumber);
model:thresholdValue.
box verticalPanel extent:1.0 @ 300.
box verticalPanel add:(slider := HorizontalSlider new start:0 stop:1 step:0.05).
slider model:thresholdValue.
slider width:1.0; leftInset:4; rightInset:4.
box verticalPanel add:(preview := ImageView new).
preview extent:300 @300.
preview level:-1.
box verticalPanel horizontalLayout:#fitSpace.
update :=
[
|s t|
t := thresholdValue value clampBetween:0 and:1.
preview image:((image asThresholdMonochromeImage:t)
magnifiedPreservingRatioTo:preview extent).
].
update value.
box enterField acceptOnLostFocus:true.
box enterField acceptOnLeave:true.
thresholdValue onChangeEvaluate:update.
] do:[
userInput := Dialog request:'Threshold (0=black; 1=white) ?' initialAnswer:0.5.
].
userInput isEmptyOrNil ifTrue:[^ self].
thresholdBrighness := Number readFrom:userInput onError:nil.
thresholdBrighness isNil ifTrue:[^ self].
thresholdBrighness := thresholdBrighness clampBetween:0 and:1.
imageEditView newImageWithUndo:(image asThresholdMonochromeImage:thresholdBrighness)
"Created: / 24-08-2017 / 15:26:44 / cg"
"Modified: / 24-08-2017 / 17:54:21 / cg"
"Modified (format): / 23-10-2017 / 10:42:52 / cg"
!
makeNegative
"negates current image by negating the color map"
self withExecuteCursorDo:[
imageEditView makeNegative.
self updateImage.
].
"Created: / 31-08-2017 / 13:49:47 / cg"
"Modified (comment): / 01-09-2017 / 10:27:37 / cg"
!
thresholdGrayToDepth
self askForDepthThenDo:[:depth |
self thresholdGrayToDepth:depth
].
"Created: / 24-08-2017 / 17:49:23 / cg"
!
thresholdGrayToDepth:depth
self withExecuteCursorDo:[
|newImage|
newImage := self image asThresholdGrayImageDepth:depth.
imageEditView newImageWithUndo:newImage.
].
"Created: / 24-08-2017 / 17:49:30 / cg"
!
thresholdToDepth
self askForDepthThenDo:[:depth |
self convertToDepth:depth dither:false
].
"Created: / 30-08-2017 / 00:31:33 / cg"
!
thresholdToNumberOfGrayColors
|oldDepth numGrayColors suggestion grayImage userInput grayColors|
oldDepth := self image depth.
grayImage := self image asGrayImageDepth:8.
suggestion := LastNumThresholdGrayColors notNil ifTrue:[
LastNumThresholdGrayColors
] ifFalse:[
oldDepth > 8
ifTrue:[256]
ifFalse:[2 raisedTo:((oldDepth // 2 - 1) nextPowerOf2)]
].
Dialog modifyingBoxWith:[:box |
|preview slider update thresholdValue|
thresholdValue := suggestion asValue.
box enterField
converter:(PrintConverter new initForNumber);
model:thresholdValue.
box verticalPanel extent:1.0 @ 300.
box verticalPanel add:(slider := HorizontalSlider new start:2 stop:256 step:1).
slider model:thresholdValue.
slider width:1.0; leftInset:4; rightInset:4.
box verticalPanel add:(preview := ImageView new).
preview extent:300 @300.
preview level:-1.
box verticalPanel horizontalLayout:#fitSpace.
update :=
[
|numGrayColors depth s t tImage|
numGrayColors := thresholdValue value clampBetween:2 and:256.
grayColors := Color grayColorVector:numGrayColors.
tImage := grayImage asNearestPaintImageDepth:(grayImage depth) colors:grayColors.
preview image:(tImage magnifiedPreservingRatioTo:preview extent).
].
update value.
box enterField acceptOnLostFocus:true.
box enterField acceptOnLeave:true.
thresholdValue onChangeEvaluate:update.
] do:[
userInput := Dialog request:'Number of Gray Colors ?' initialAnswer:suggestion asString.
].
userInput isEmptyOrNil ifTrue:[^ self].
numGrayColors := Number readFrom:userInput onError:nil.
numGrayColors isNil ifTrue:[^ self].
grayColors := Color grayColorVector:numGrayColors.
imageEditView newImageWithUndo:(grayImage asNearestPaintImageDepth:(grayImage depth) colors:grayColors).
"Created: / 23-10-2017 / 10:55:15 / cg"
! !
!ImageEditor methodsFor:'user actions-editing-colors'!
convertToDepth:depth dither:doDither
|answer labels values
ditherColors fixColors
nGrey greyColorsAlready moreColors d|
"/ no colormap above 12 bits!!
depth > 12 ifTrue:[
answer := #TrueColor.
] ifFalse:[
doDither ifTrue:[
(depth >= 8) ifTrue:[
labels := #('Cancel' 'Use Browser Palette' 'Use Standard' 'Compute' 'TrueColor').
values := #(nil UseBrowserPalette UseStandard Compute TrueColor).
] ifFalse:[
depth == 1 ifTrue:[
answer := #UseStandard
] ifFalse:[
labels := #('Cancel' 'Use Standard' 'Compute' 'TrueColor').
values := #(nil UseStandard Compute TrueColor).
].
].
] ifFalse:[
(depth >= 8) ifTrue:[
labels := #('Cancel' 'Use Browser Palette' 'Use Standard' 'TrueColor').
values := #(nil UseBrowserPalette UseStandard TrueColor).
] ifFalse:[
answer := #UseStandard
].
].
].
answer isNil ifTrue:[
answer := OptionBox
request:'Compute a new (optimized) colormap\(Warning: this may take some time)\\or else use a standard colormap?' withCRs
label:(resources string:'Dither how')
image:(YesNoBox iconBitmap)
buttonLabels:(resources array:labels)
values:values
default:#UseStandard
onCancel:nil.
answer isNil ifTrue:[^ self].
].
(answer == #Compute) ifTrue:[
ditherColors :=
Color
best:(1 bitShift:depth)
ditherColorsForImage:self image
] ifFalse:[
(answer == #UseBrowserPalette) ifTrue:[
ditherColors := Color colorCubeWithRed:6 green:6 blue:6.
] ifFalse:[
answer == #TrueColor ifTrue:[
depth == 6 ifTrue:[
fixColors := FixedPalette
redShift:4 redMask:3
greenShift:2 greenMask:3
blueShift:0 blueMask:3
].
depth == 9 ifTrue:[
fixColors := FixedPalette
redShift:6 redMask:7
greenShift:3 greenMask:7
blueShift:0 blueMask:7
].
depth == 12 ifTrue:[
fixColors := FixedPalette
redShift:8 redMask:16r0F
greenShift:4 greenMask:16r0F
blueShift:0 blueMask:16r0F
].
depth == 15 ifTrue:[
fixColors := FixedPalette
redShift:10 redMask:16r1F
greenShift:5 greenMask:16r1F
blueShift:0 blueMask:16r1F
].
depth == 16 ifTrue:[
fixColors := FixedPalette
redShift:11 redMask:16r1F
greenShift:5 greenMask:16r3F
blueShift:0 blueMask:16r1F
].
depth == 18 ifTrue:[
fixColors := FixedPalette
redShift:12 redMask:16r3F
greenShift:6 greenMask:16r3F
blueShift:0 blueMask:16r3F
].
] ifFalse:[
depth == 1 ifTrue:[
ditherColors := { Color black . Color white }.
].
depth == 2 ifTrue:[
ditherColors := { Color black . Color darkGray .Color lightGray . Color white }.
].
depth = 3 ifTrue:[
ditherColors := Color colorCubeWithRed:2 green:2 blue:2.
].
depth = 4 ifTrue:[
ditherColors := Color vgaColors.
].
depth = 5 ifTrue:[
ditherColors := Color colorCubeWithRed:3 green:4 blue:2.
].
depth = 6 ifTrue:[
ditherColors := Color colorCubeWithRed:4 green:4 blue:3.
].
depth = 7 ifTrue:[
ditherColors := Color colorCubeWithRed:5 green:5 blue:4.
].
depth == 8 ifTrue:[
ditherColors := Color standardDitherColorsForDepth8.
].
depth == 9 ifTrue:[
ditherColors := Color colorCubeWithRed:8 green:8 blue:8.
].
ditherColors isNil ifTrue:[
self error:'unsupported depth'.
].
"/ add as many gray colors as possible.
nGrey := (2 raisedTo:depth) - ditherColors size.
nGrey > 0 ifTrue:[
nGrey := nGrey min:100.
greyColorsAlready := ditherColors select:[:clr | clr isGreyColor].
d := 1 / nGrey.
moreColors := (1 to:nGrey-1)
collect:[:i | Color brightness:(d * i)]
thenReject:[:clr | greyColorsAlready includes:clr ].
ditherColors := ditherColors , moreColors.
].
].
].
].
self withExecuteCursorDo:[
|newImage|
doDither ifTrue:[
depth == 1 ifTrue:[
newImage := self image asErrorDitheredMonochromeImage
] ifFalse:[
answer == #TrueColor ifTrue:[
newImage := self image asDitheredImageUsing:fixColors depth:depth.
] ifFalse:[
newImage := self image asDitheredImageUsing:ditherColors depth:depth.
]
]
] ifFalse:[
answer == #TrueColor ifTrue:[
self halt.
] ifFalse:[
newImage := self image asNearestPaintImageDepth:depth colors:ditherColors
].
].
imageEditView newImageWithUndo:newImage.
].
"Created: / 30-08-2017 / 00:33:55 / cg"
"Modified: / 30-08-2017 / 02:13:03 / cg"
!
makeInvertedBits
"inverts the pixels - for palettes, this leads to funny results.
For others, this is the same as negating"
self updateImageAfterDoing:#makeInvertedBits.
"Created: / 31-08-2017 / 13:51:10 / cg"
! !
!ImageEditor methodsFor:'user actions-image sequences'!
editEachImageFromSequence
|seq|
self checkModified ifFalse:[ ^ self ].
imageEditView releaseUndos.
seq := self image imageSequence.
seq size > 10 ifTrue:[
(Dialog confirm:(resources string:'Ok to open %1 image editor windows?' with:seq size))
ifFalse:[^ self].
].
seq do:[:eachFrame |
ImageEditor openOnImage:eachFrame image
].
"Modified: / 21-10-2010 / 15:01:25 / cg"
!
gotoImageInSequence:index
"display the next image in the image sequence"
|img seq frame listOfColors|
imageEditView releaseUndos.
seq := self image imageSequence.
imageSeqNr := index.
frame := seq at:imageSeqNr.
imageEditView image:(frame image).
(img := self image) notNil ifTrue:[
listOfColors := self listOfColors.
img colorMap notNil ifTrue:[
listOfColors contents:(img usedColors asSet asOrderedCollection).
] ifFalse:[
listOfColors removeAll.
].
self findColorMapMode.
self updateLabelsAndHistory.
img := img onDevice:device.
imageEditView image:img.
] ifFalse:[
self updateForNoImage
].
"Created: / 21-10-2010 / 14:22:11 / cg"
!
nextImageInSequence
"display the next image in the image sequence"
|seq index|
seq := self image imageSequence.
(index := imageSeqNr) isNil ifTrue:[
index := 1.
].
index := index + 1.
index > seq size ifTrue:[
self information:'Back to first image in sequence'.
index := 1.
].
self gotoImageInSequence:index.
"Modified: / 21-10-2010 / 14:24:11 / cg"
!
previousImageInSequence
"display the previous image in the image sequence"
|seq index|
seq := self image imageSequence.
(index := imageSeqNr) isNil ifTrue:[
index := 1.
].
index := index - 1.
index < 1 ifTrue:[
self information:'Wrap to last image in sequence'.
index := seq size.
].
self gotoImageInSequence:index.
"Created: / 21-10-2010 / 14:25:03 / cg"
! !
!ImageEditor methodsFor:'user actions-loading'!
doLoadFromClass
"opens a dialog for loading an image from class and a (resource-) selector"
|img|
self checkModified ifFalse:[ ^ self ].
(imageEditView loadFromClass) notNil ifTrue:[
imageSeqNr := nil.
(img := self image) notNil ifTrue: [
self updateColorsFromImage:img.
self findColorMapMode.
self updateLabelsAndHistory.
] ifFalse: [
self updateForNoImage
].
]
!
doLoadFromFile
"opens a dialog for loading an image from a file"
|img file filters title|
self checkModified ifFalse:[ ^ self ].
imageSeqNr := nil.
img := self image.
img notNil ifTrue: [
file := img fileName
].
title := (resources string:'Load Image from File:').
(UserPreferences current useNativeFileDialog
and:[Screen current isWindowsPlatform]) ifTrue:[
self withWaitCursorDo:[
file := Screen current
nativeFileDialogFor:(self window topView id)
save:false
title:title
inDirectory:(file notNil ifTrue:[file asFilename directory pathName] ifFalse:[LastDirectory])
initialAnswer:(file notNil ifTrue:[file asFilename baseName] ifFalse:['image.png'])
"/ flags:#( ENABLESIZING "HIDEREADONLY" EXPLORER NOCHANGEDIR)
filter:
{
{ (resources string:'Image Files') . '*.tif;*.png;*.gif;*.bmp;*.jpg' } .
{ (resources string:'All Files') . '*.*' }
}
extension:nil
"blocking:false".
].
] ifFalse:[
filters := FileSelectionBrowser loadImageFileNameFilters.
file notNil ifTrue:[
file := FileSelectionBrowser
request:title
fileName:file
withFileFilters:filters.
] ifFalse:[
file := FileSelectionBrowser
request:title
inDirectory:LastDirectory
withFileFilters:filters.
].
].
file notNil ifTrue:[
LastDirectory := file asFilename directoryName.
self loadFromFile:file
]
"Modified: / 16-02-2017 / 10:53:41 / cg"
!
doLoadFromURL
"opens a dialog for loading an image from a URL"
|tempFile url response|
self checkModified ifFalse:[ ^ self ].
url := Dialog
request:(resources string:'Load Image from URL:')
initialAnswer:LastURL.
url notEmptyOrNil ifTrue:[
HTTPInterface isNil ifTrue:[ Smalltalk loadPackage:'stx:goodies/communication'].
LastURL := url.
tempFile := FileStream newTemporary close fileName.
self withWaitCursorDo:[
|newURL|
response := HTTPInterface get:url destinationFile:tempFile.
response isMovedResponse ifTrue:[
newURL := response location.
newURL ~= url ifTrue:[
response := HTTPInterface get:newURL destinationFile:tempFile.
].
].
].
response isErrorResponse ifTrue:[
Dialog warn:(resources string:'Could not load image ("%1")' with:response responseText).
] ifFalse:[
self loadFromFile:tempFile.
].
tempFile remove
]
"Created: / 20-09-2010 / 11:30:59 / cg"
"Modified: / 13-09-2017 / 17:00:28 / cg"
!
doNewImage
"opens a dialog with choices of size and color map for creating a new image"
|dialogAspects width height cMapString cMapMode cMap imageClass image szString defaultSize ext depth|
self checkModified ifFalse:[ ^ self ].
defaultSize := (self class listOfDefaultSizes includes:'32x32')
ifTrue:['32x32']
ifFalse:[self class listOfDefaultSizes first].
dialogAspects := IdentityDictionary new
at:#listOfSizes put: self class listOfDefaultSizes asValue;
at:#listOfColorMaps put: self class namesOfColorMaps values asSortedCollection asValue;
at:#selectionOfSize put: (LastSizeString ? defaultSize) asValue;
at:#selectionOfColorMap put: (LastColormapMode ? self class namesOfColorMaps values asSortedCollection first) asValue;
yourself.
(self openDialogInterface:#dialogSpecForNewImage withBindings:dialogAspects)
ifTrue:[
szString := (dialogAspects at:#selectionOfSize) value.
ext := self pointFromString:szString.
ext isNil ifTrue:[
width := height := 32
] ifFalse:[
width := ext x.
height := ext y.
].
"/ width := "128 min: "(Integer readFromString: (szString upTo: $x) onError:[32]).
"/ height := "128 min: " (Integer readFromString: (szString copy reverse upTo: $x) reverse onError:[32]).
cMapString := (dialogAspects at:#selectionOfColorMap) value.
cMapMode := self class namesOfColorMaps keyAtEqualValue:cMapString.
cMap := self class listOfColorMaps at:cMapMode.
depth := (cMapMode startsWith:'depth')
ifTrue:[ Integer readFrom:(cMapMode copyFrom:'depth' size + 1) ]
ifFalse:[
(cMapMode startsWith:'masked')
ifTrue:[ Integer readFrom:(cMapMode copyFrom:'masked' size + 1) ]
ifFalse:[ cMap size highBit-1 ]].
imageClass := Image implementorForDepth:depth.
image := imageClass width: width height: height.
image bits:(ByteArray new:(image bytesPerRow*height)).
LastSizeString := szString.
LastColormapMode := cMapString.
(cMapMode startsWith:'mask') ifTrue:[
image mask: (ImageMask width: width height: height depth: 1 fromArray: (ByteArray new: width*height)).
].
depth == 32 ifTrue:[
image photometric:#rgba
] ifFalse:[
image colorMap: cMap.
].
(imageEditView image: image) notNil ifTrue:[
self updateListOfColorsAndColormapMode.
self updateLabelsAndHistory.
].
image fillRectangleX:0 y:0 width:width height:height with:Color white.
]
"Modified: / 13-09-2017 / 23:57:52 / cg"
!
doNewImageEditor
"opens a new image editor"
ImageEditor open
"Created: / 17-08-2006 / 09:03:14 / cg"
!
doNewImageFromClipboard
|image|
self checkModified ifFalse:[ ^ self ].
image := imageEditView clipBoardImage.
image isImageOrForm ifFalse:[
image := Image readFrom:(image asString) onError:nil.
image isNil ifTrue:[
Dialog warn:'Clipboard does not contain an image I can use/understand'.
^ self.
].
].
imageEditView image:image.
image notNil ifTrue:[
self updateColorsFromImage:image.
self findColorMapMode.
self updateLabelsAndHistory.
]
"Modified (format): / 08-10-2017 / 08:58:03 / cg"
!
doNewMaskFromClipboard
|mask image newImage|
self checkModified ifFalse:[ ^ self ].
mask := imageEditView clipBoardImage.
mask isImageOrForm ifFalse:[
mask := Image readFrom:(mask asString) onError:nil.
mask isNil ifTrue:[
Dialog warn:'Clipboard does not contain an image I can use/understand'.
^ self.
].
].
(image:= imageEditView image) isNil ifTrue:[
image := mask.
].
mask extent ~= image extent ifTrue:[
mask := imageEditView resizedImage:mask to:image extent.
].
newImage := image copy.
newImage mask:mask.
imageEditView newImageWithUndo:newImage.
self updateAfterImageChange.
"Modified (format): / 08-10-2017 / 08:57:58 / cg"
!
grabFullScreenImage
"grab all for editing"
self grabScreenImageUsing:[
Image fromScreen
].
"Created: / 25-02-2017 / 12:41:29 / cg"
!
grabScreenImage
"let user choose an area and grab that area for editing"
self grabScreenImageUsing:[
|r|
[Screen current leftButtonPressed] whileTrue:[Delay waitForSeconds:0.05].
r := Rectangle fromUser.
(r width == 0 or:[r height == 0]) ifTrue:[
nil
] ifFalse:[
lastGrabbedScreenArea := r.
Image fromScreen:r
]
].
"Modified (comment): / 25-02-2017 / 12:41:00 / cg"
!
grabScreenImageFromLastArea
"grab again from the previous area for editing"
self grabScreenImageUsing:[
Image fromScreen:lastGrabbedScreenArea
].
!
grabScreenImageUsing:aBlock
"let user choose an area and grab that area for editing"
self checkModified ifFalse:[ ^ self ].
Processor
addTimedBlock:[
|image d8image img|
imageSeqNr := nil.
image := aBlock value.
image notNil ifTrue:[
image depth > 8 ifTrue:[
false ifTrue:[
Error handle:[:ex | |sig|
(sig := ex creator) == HaltInterrupt ifTrue:[ex reject].
sig == Signal noHandlerSignal ifTrue:[ex reject].
self warn:'Could not convert to depth8 image (too many colors)'.
d8image := nil.
] do:[
d8image := Depth8Image fromImage:image photometric:#palette.
].
d8image notNil ifTrue:[
image := d8image
]
].
].
(imageEditView image:image) notNil ifTrue:[
self listOfColors contents:(image colorMap).
self findColorMapMode.
self updateLabelsAndHistory.
]
]
]
afterSeconds:1
"Created: / 29-07-1998 / 21:24:42 / cg"
"Modified: / 16-11-2001 / 16:21:19 / cg"
"Modified (comment): / 25-02-2017 / 12:41:06 / cg"
!
grabWindowImage
"let user choose a window and grab its area for editing"
self grabScreenImageUsing:[
|v topView|
(v := Screen current viewFromUser) notNil ifTrue:[
topView := v topView.
topView raise; makeFullyVisible.
Delay waitForSeconds:0.5. "/ give view a chance to redraw itself.
Image fromView:topView
].
].
"Modified (comment): / 25-02-2017 / 12:41:20 / cg"
! !
!ImageEditor methodsFor:'user actions-saving'!
doPrint
"prints current image on the current printer"
self withWaitCursorDo:[
imageEditView print
]
!
doSaveButtonImageToFileAs
"opens a dialog for saving current image to a file.
Saved as a button image (i.e. with a frame around)"
imageEditView saveButtonImageToFileAs.
self updateLabelsAndHistory.
!
doSaveImageFile
"saves current image to current file"
imageEditView save.
self clearModifiedAndRememberImageSaved.
!
doSaveImageFileAs
"opens a dialog for saving an image to a file"
|img file filters|
img := self image.
img notNil ifTrue: [
file := img fileName
].
filters := FileSelectionBrowser saveImageFileNameFilters.
(UserPreferences current useNativeFileDialog
and:[Screen current isWindowsPlatform]) ifTrue:[
self withWaitCursorDo:[
"/ windows only
file := Screen current
nativeFileDialogFor:(self window topView id)
save:true
title:(resources string:'Save Image in File')
inDirectory:(file notNil ifTrue:[file asFilename directory pathName] ifFalse:[LastDirectory])
initialAnswer:(file notNil ifTrue:[file asFilename baseName] ifFalse:['image.png'])
"/ flags:#( ENABLESIZING "HIDEREADONLY" EXPLORER NOCHANGEDIR)
filter:
{
{ (resources string:'Image Files') . '*.tif;*.png;*.gif;*.bmp' } .
{ (resources string:'All Files') . '*.*' }
}
extension:nil
"blocking:false".
].
] ifFalse:[
img fileName isNil ifTrue:[
LastDirectory notNil ifTrue:[
file isNil ifTrue:[
file := 'image.png'.
].
file := LastDirectory asFilename construct:(file asFilename baseName).
].
].
(FileSelectionBrowser isNil or:[DirectoryView isNil]) ifTrue:[
file notNil ifTrue:[
file := Dialog requestFileName:'Save Image To'
default:file
pattern:(filters first).
] ifFalse:[
file := Dialog
requestFileName:'Save Image To'
default:'image.png'
pattern:(filters first)
fromDirectory:LastDirectory.
].
] ifFalse:[
file notNil ifTrue:[
file := FileSelectionBrowser
request:'Save Image To'
fileName:file
withFileFilters:filters.
] ifFalse:[
file := FileSelectionBrowser
request:'Save Image in File:'
inDirectory:LastDirectory
withFileFilters:filters.
].
].
].
file notNil ifTrue:[
imageEditView saveImageFileAs:file.
LastDirectory := file asFilename directoryName.
self updateLabelsAndHistory.
self clearModifiedAndRememberImageSavedAsFile:file.
]
"Modified: / 27-02-2017 / 01:26:05 / cg"
!
doSaveImageMaskFileAs
"opens a dialog for saving mask of current image to a file"
imageEditView saveImageMaskFileAs.
!
doSaveMethod
"saves the image in current class and selector"
imageEditView saveMethod ifTrue:[
self updateLabelsAndHistory.
self clearModifiedAndRememberImageSaved.
]
!
doSaveMethodAs
"opens a dialog for saving current image on a class and a selector"
imageEditView saveMethodAs ifTrue:[
self updateLabelsAndHistory.
self clearModifiedAndRememberImageSaved.
]
!
doShowPixelArrayLiteralString
"opens a dialog showing a literal array-like storeString
(sometimes useful to embed an image into source code)"
|img|
img := imageEditView image.
TextBox openOn:img bits storeString
!
doShowStoreString
"opens a dialog showing the storeString
(sometimes useful to embed an image into source code)"
|img|
img := imageEditView image.
TextBox openOn:img storeString
!
save
"saves current image on current class and selector"
self doSaveMethod
! !
!ImageEditor methodsFor:'user actions-settings'!
doChangeGridMagnification
"change grid magnification"
|box oldGridLimit newGridLimit|
oldGridLimit := imageEditView class gridMagnificationLimit asPoint.
box := EnterBox new.
box title:(resources string:'Grid Magnification Limit:').
box okText:(resources string:'OK').
box abortText:(resources string:'Cancel').
box initialText:(oldGridLimit x printString).
box showAtPointer.
(box accepted
and: [(newGridLimit := Number readFromString:(box contents) onError:[2]) notNil]
) ifTrue:[
newGridLimit := (99 min: (2 max:newGridLimit)) asPoint.
imageEditView class gridMagnificationLimit:newGridLimit.
imageEditView invalidate
]
!
penWidth:n
imageEditView penWidth:n
"Created: / 01-11-2007 / 23:47:48 / cg"
!
penWidthHolderChanged
imageEditView penWidth:(self penWidthHolder value)
"Created: / 15-02-2012 / 22:32:00 / cg"
!
spraySpot:n
imageEditView spraySpot:n
"Created: / 01-11-2007 / 23:47:48 / cg"
!
spraySpotHolderChanged
imageEditView spraySpot:(self spraySpotHolder value)
"Created: / 15-02-2012 / 22:37:08 / cg"
! !
!ImageEditor class methodsFor:'documentation'!
version
^ '$Header$'
!
version_CVS
^ '$Header$'
! !