--- a/ImageEditor.st Tue Aug 29 21:09:29 2017 +0200
+++ b/ImageEditor.st Wed Aug 30 15:42:00 2017 +0200
@@ -19,7 +19,7 @@
lastShiftUsedWrap lastGrabbedScreenArea
allowedToChangeImageDimensionAndDepth savedImage savedFile'
classVariableNames:'DefaultRelativeSizes LastColormapMode LastDirectory
- LastSizeString LastURL MaskClipboard'
+ LastSizeString LastURL MaskClipboard LastDepth'
poolDictionaries:''
category:'Interface-UIPainter'
!
@@ -3110,6 +3110,11 @@
translateLabel: true
)
(MenuItem
+ label: 'Threshold to Depth...'
+ itemValue: thresholdToDepth
+ translateLabel: true
+ )
+ (MenuItem
label: 'Make GrayScale with Depth (Dither)...'
itemValue: ditherGrayToDepth
translateLabel: true
@@ -3206,214 +3211,26 @@
nil
)
- "Modified: / 24-08-2017 / 17:49:04 / cg"
+ "Modified: / 30-08-2017 / 00:35:31 / cg"
!
menuEdit
+ <resource: #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:#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
- )
+ (Menu new fromLiteralArrayEncoding:(ImageEditor menuEdit)) startUp"
+
+ ^ #( #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 )
"Modified: / 12-04-2017 / 09:25:18 / cg"
+ "Modified (comment): / 30-08-2017 / 00:30:38 / cg"
!
menuFile
@@ -5773,7 +5590,14 @@
|oldDepth suggestion depth|
oldDepth := self image depth.
- suggestion := oldDepth > 8 ifTrue:[8] ifFalse:[(oldDepth // 2 - 1) nextPowerOf2].
+
+ 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].
@@ -5781,9 +5605,11 @@
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
@@ -7508,6 +7334,170 @@
"Created: / 20-02-2017 / 18:06:03 / cg"
!
+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"
+!
+
ditherGrayToDepth
self askForDepthThenDo:[:depth |
self ditherGrayToDepth:depth
@@ -7519,102 +7509,26 @@
ditherGrayToDepth:depth
self withExecuteCursorDo:[
|newImage|
-
- newImage := self image asGrayImageDepth:depth dither:true.
+
+ depth == 1 ifTrue:[
+ newImage := self image asErrorDitheredMonochromeImage
+ ] ifFalse:[
+ newImage := self image asGrayImageDepth:depth dither:#floydSteinberg.
+ ].
imageEditView newImageWithUndo:newImage.
].
"Created: / 24-08-2017 / 17:51:07 / cg"
+ "Modified: / 30-08-2017 / 01:18:43 / cg"
!
ditherToDepth
self askForDepthThenDo:[:depth |
- self ditherToDepth:depth
+ self convertToDepth:depth dither:true
].
"Created: / 07-07-2006 / 13:22:10 / cg"
- "Modified: / 24-08-2017 / 17:06:00 / cg"
-!
-
-ditherToDepth:depth
- |answer labels values ditherColors nGrey greyColorsAlready moreColors d|
-
- (depth >= 8) ifTrue:[
- labels := #('Cancel' 'Use Browser Palette' 'Use Standard' 'Compute' ).
- values := #(nil UseBrowserPalette UseStandard Compute).
- ] ifFalse:[
- labels := #('Cancel' 'Use Standard' 'Compute' ).
- values := #(nil UseStandard Compute).
- ].
-
- 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:[
- depth = 1 ifTrue:[
- ditherColors := Array with:(Color black) with:(Color white).
- ] ifFalse:[ depth = 2 ifTrue:[
- ditherColors := Array
- with:(Color black)
- with:(Color darkGray)
- with:(Color lightGray)
- with:(Color white).
- ] ifFalse:[ depth = 3 ifTrue:[
- ditherColors := Color colorCubeWithRed:2 green:2 blue:2.
- ] ifFalse:[ depth = 4 ifTrue:[
- ditherColors := Color vgaColors.
- ] ifFalse:[ depth = 5 ifTrue:[
- ditherColors := Color colorCubeWithRed:3 green:4 blue:2.
- ] ifFalse:[ depth = 6 ifTrue:[
- ditherColors := Color colorCubeWithRed:4 green:4 blue:3.
- ] ifFalse:[ depth = 7 ifTrue:[
- ditherColors := Color colorCubeWithRed:5 green:5 blue:4.
- ] ifFalse:[ depth == 8 ifTrue:[
- ditherColors := Color standardDitherColorsForDepth8.
- ] ifFalse:[
- self error:'unsupported depth'.
- ]]]]]]]].
-
-
- "/ add as many gray colors as possible.
- nGrey := (2 raisedTo:depth) - ditherColors size.
- nGrey > 0 ifTrue:[
- nGrey := nGrey min:128.
- 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|
-
- newImage := self image asDitheredImageUsing:ditherColors depth:depth.
- imageEditView newImageWithUndo:newImage.
- ].
-
- "Created: / 07-07-2006 / 13:20:56 / cg"
- "Modified: / 29-08-2017 / 21:08:34 / cg"
+ "Modified: / 30-08-2017 / 00:34:42 / cg"
!
do3DProjection
@@ -7856,33 +7770,25 @@
doMagnifyImageBy
"magnifies the current image (by a scale)"
- |oldSize newSize scaleString scale image antiAliased|
+ |oldSize newSize scaleString scale image antiAliased smoothing|
image := imageEditView image.
oldSize := image extent.
antiAliased := false asValue.
-
+ smoothing := false asValue.
+
Dialog modifyingBoxWith:[:box |
- box addCheckBox:(resources string:'Antialiased') on:antiAliased.
+ box verticalPanel add:(CheckBox label:(resources string:'Antialias/Smooth') model:antiAliased).
+ "/ 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:'1'
- list:#('0.25' '0.5' '2' '4').
+ list:#('0.1' '0.25' '0.3' '0.5' '1.5' '2' '3' '4').
].
scaleString isNil ifTrue:[^ self].
-"/ box := EnterBox new.
-"/ box title:(resources string:'Scale factor (<1 to shrink; >1 to magnify):').
-"/ box okText:(resources string:'OK').
-"/ box abortText:(resources string:'Cancel').
-"/ box initialText:1 printString.
-"/ box showAtPointer.
-"/ box accepted ifTrue:[
-"/ scaleString := box contents.
-"/ ].
-
scale := Object readFromString:scaleString onError:nil.
scale notNil ifTrue:[
@@ -7892,13 +7798,19 @@
].
newSize := oldSize * scale.
antiAliased value ifTrue:[
- imageEditView magnifyAntiAliasedImageTo:newSize.
+ 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
@@ -8130,6 +8042,14 @@
].
"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"
! !
!ImageEditor methodsFor:'user actions-image sequences'!