ImageEditor.st
changeset 3476 2854769b212a
parent 3475 7eafbd0cad40
child 3477 52202af265c2
equal deleted inserted replaced
3475:7eafbd0cad40 3476:2854769b212a
  2848      by the MenuEditor of ST/X."
  2848      by the MenuEditor of ST/X."
  2849 
  2849 
  2850     "Do not manually edit this!! If it is corrupted,
  2850     "Do not manually edit this!! If it is corrupted,
  2851      the MenuEditor may not be able to read the specification."
  2851      the MenuEditor may not be able to read the specification."
  2852 
  2852 
       
  2853 
  2853     "
  2854     "
  2854      MenuEditor new openOnClass:ImageEditor andSelector:#menuColors
  2855      MenuEditor new openOnClass:ImageEditor andSelector:#menuColors
  2855      (Menu new fromLiteralArrayEncoding:(ImageEditor menuColors)) startUp
  2856      (Menu new fromLiteralArrayEncoding:(ImageEditor menuColors)) startUp
  2856     "
  2857     "
  2857 
  2858 
  2859 
  2860 
  2860     ^ 
  2861     ^ 
  2861      #(Menu
  2862      #(Menu
  2862         (
  2863         (
  2863          (MenuItem
  2864          (MenuItem
  2864             "/ enabled: imageIsLoadedAndAllowedToChangeImageDimensionAndDepth
       
  2865             enabled: imageIsLoaded
  2865             enabled: imageIsLoaded
  2866             label: 'Depth'
  2866             label: 'Depth'
  2867             translateLabel: true
       
  2868             submenu: 
  2867             submenu: 
  2869            (Menu
  2868            (Menu
  2870               (
  2869               (
  2871                (MenuItem
  2870                (MenuItem
  2872                   activeHelpKey: colorMap1
  2871                   activeHelpKey: colorMap1
       
  2872                   enabled: imageIsLoadedAndNotReadonlyHolder
  2873                   label: '1-Plane'
  2873                   label: '1-Plane'
  2874                   itemValue: colorMapMode:
  2874                   itemValue: colorMapMode:
  2875                   translateLabel: true
       
  2876                   argument: depth1
  2875                   argument: depth1
  2877                   choice: colorMapMode
  2876                   choice: colorMapMode
  2878                   choiceValue: depth1
  2877                   choiceValue: depth1
  2879             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2880                 )
  2878                 )
  2881                (MenuItem
  2879                (MenuItem
  2882                   activeHelpKey: colorMap1M
  2880                   activeHelpKey: colorMap1M
       
  2881                   enabled: imageIsLoadedAndNotReadonlyHolder
  2883                   label: '1-Plane + Mask'
  2882                   label: '1-Plane + Mask'
  2884                   itemValue: colorMapMode:
  2883                   itemValue: colorMapMode:
  2885                   translateLabel: true
       
  2886                   argument: masked1
  2884                   argument: masked1
  2887                   choice: colorMapMode
  2885                   choice: colorMapMode
  2888                   choiceValue: masked1
  2886                   choiceValue: masked1
  2889             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2890                 )
  2887                 )
  2891                (MenuItem
  2888                (MenuItem
  2892                   label: '-'
  2889                   label: '-'
  2893                 )
  2890                 )
  2894                (MenuItem
  2891                (MenuItem
  2895                   activeHelpKey: colorMap2
  2892                   activeHelpKey: colorMap2
       
  2893                   enabled: imageIsLoadedAndNotReadonlyHolder
  2896                   label: '2-Plane'
  2894                   label: '2-Plane'
  2897                   itemValue: colorMapMode:
  2895                   itemValue: colorMapMode:
  2898                   translateLabel: true
       
  2899                   argument: depth2
  2896                   argument: depth2
  2900                   choice: colorMapMode
  2897                   choice: colorMapMode
  2901                   choiceValue: depth2
  2898                   choiceValue: depth2
  2902             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2903                 )
  2899                 )
  2904                (MenuItem
  2900                (MenuItem
  2905                   activeHelpKey: colorMap2M
  2901                   activeHelpKey: colorMap2M
       
  2902                   enabled: imageIsLoadedAndNotReadonlyHolder
  2906                   label: '2-Plane + Mask'
  2903                   label: '2-Plane + Mask'
  2907                   itemValue: colorMapMode:
  2904                   itemValue: colorMapMode:
  2908                   translateLabel: true
       
  2909                   argument: masked2
  2905                   argument: masked2
  2910                   choice: colorMapMode
  2906                   choice: colorMapMode
  2911                   choiceValue: masked2
  2907                   choiceValue: masked2
  2912             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2913                 )
  2908                 )
  2914                (MenuItem
  2909                (MenuItem
  2915                   label: '-'
  2910                   label: '-'
  2916                 )
  2911                 )
  2917                (MenuItem
  2912                (MenuItem
  2918                   activeHelpKey: colorMap4
  2913                   activeHelpKey: colorMap4
       
  2914                   enabled: imageIsLoadedAndNotReadonlyHolder
  2919                   label: '4-Plane'
  2915                   label: '4-Plane'
  2920                   itemValue: colorMapMode:
  2916                   itemValue: colorMapMode:
  2921                   translateLabel: true
       
  2922                   argument: depth4
  2917                   argument: depth4
  2923                   choice: colorMapMode
  2918                   choice: colorMapMode
  2924                   choiceValue: depth4
  2919                   choiceValue: depth4
  2925             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2926                 )
  2920                 )
  2927                (MenuItem
  2921                (MenuItem
  2928                   activeHelpKey: colorMap4M
  2922                   activeHelpKey: colorMap4M
       
  2923                   enabled: imageIsLoadedAndNotReadonlyHolder
  2929                   label: '4-Plane + Mask'
  2924                   label: '4-Plane + Mask'
  2930                   itemValue: colorMapMode:
  2925                   itemValue: colorMapMode:
  2931                   translateLabel: true
       
  2932                   argument: masked4
  2926                   argument: masked4
  2933                   choice: colorMapMode
  2927                   choice: colorMapMode
  2934                   choiceValue: masked4
  2928                   choiceValue: masked4
  2935             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2936                 )
  2929                 )
  2937                (MenuItem
  2930                (MenuItem
  2938                   label: '-'
  2931                   label: '-'
  2939                 )
  2932                 )
  2940                (MenuItem
  2933                (MenuItem
  2941                   activeHelpKey: colorMap8
  2934                   activeHelpKey: colorMap8
       
  2935                   enabled: imageIsLoadedAndNotReadonlyHolder
  2942                   label: '8-Plane'
  2936                   label: '8-Plane'
  2943                   itemValue: colorMapMode:
  2937                   itemValue: colorMapMode:
  2944                   translateLabel: true
       
  2945                   argument: depth8
  2938                   argument: depth8
  2946                   choice: colorMapMode
  2939                   choice: colorMapMode
  2947                   choiceValue: depth8
  2940                   choiceValue: depth8
  2948             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2949                 )
  2941                 )
  2950                (MenuItem
  2942                (MenuItem
  2951                   activeHelpKey: colorMap8M
  2943                   activeHelpKey: colorMap8M
       
  2944                   enabled: imageIsLoadedAndNotReadonlyHolder
  2952                   label: '8-Plane + Mask'
  2945                   label: '8-Plane + Mask'
  2953                   itemValue: colorMapMode:
  2946                   itemValue: colorMapMode:
  2954                   translateLabel: true
       
  2955                   argument: masked8
  2947                   argument: masked8
  2956                   choice: colorMapMode
  2948                   choice: colorMapMode
  2957                   choiceValue: masked8
  2949                   choiceValue: masked8
  2958             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2959                 )
  2950                 )
  2960                (MenuItem
  2951                (MenuItem
  2961                   label: '-'
  2952                   label: '-'
  2962                 )
  2953                 )
  2963                (MenuItem
  2954                (MenuItem
  2964                   activeHelpKey: colorMap16
  2955                   activeHelpKey: colorMap16
       
  2956                   enabled: imageIsLoadedAndNotReadonlyHolder
  2965                   label: '16-Plane'
  2957                   label: '16-Plane'
  2966                   itemValue: colorMapMode:
  2958                   itemValue: colorMapMode:
  2967                   translateLabel: true
       
  2968                   argument: depth16
  2959                   argument: depth16
  2969                   choice: colorMapMode
  2960                   choice: colorMapMode
  2970                   choiceValue: depth16
  2961                   choiceValue: depth16
  2971             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2972                 )
  2962                 )
  2973                (MenuItem
  2963                (MenuItem
  2974                   activeHelpKey: colorMap16M
  2964                   activeHelpKey: colorMap16M
       
  2965                   enabled: imageIsLoadedAndNotReadonlyHolder
  2975                   label: '16-Plane + Mask'
  2966                   label: '16-Plane + Mask'
  2976                   itemValue: colorMapMode:
  2967                   itemValue: colorMapMode:
  2977                   translateLabel: true
       
  2978                   argument: masked16
  2968                   argument: masked16
  2979                   choice: colorMapMode
  2969                   choice: colorMapMode
  2980                   choiceValue: masked16
  2970                   choiceValue: masked16
  2981             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2982                 )
  2971                 )
  2983                (MenuItem
  2972                (MenuItem
  2984                   label: '-'
  2973                   label: '-'
  2985                 )
  2974                 )
  2986                (MenuItem
  2975                (MenuItem
  2987                   activeHelpKey: colorMap24
  2976                   activeHelpKey: colorMap24
       
  2977                   enabled: imageIsLoadedAndNotReadonlyHolder
  2988                   label: '24-Plane'
  2978                   label: '24-Plane'
  2989                   itemValue: colorMapMode:
  2979                   itemValue: colorMapMode:
  2990                   translateLabel: true
       
  2991                   argument: depth24
  2980                   argument: depth24
  2992                   choice: colorMapMode
  2981                   choice: colorMapMode
  2993                   choiceValue: depth24
  2982                   choiceValue: depth24
  2994             enabled: imageIsLoadedAndNotReadonlyHolder
       
  2995                 )
  2983                 )
  2996                (MenuItem
  2984                (MenuItem
  2997                   activeHelpKey: colorMap24M
  2985                   activeHelpKey: colorMap24M
       
  2986                   enabled: imageIsLoadedAndNotReadonlyHolder
  2998                   label: '24-Plane + Mask'
  2987                   label: '24-Plane + Mask'
  2999                   itemValue: colorMapMode:
  2988                   itemValue: colorMapMode:
  3000                   translateLabel: true
       
  3001                   argument: masked24
  2989                   argument: masked24
  3002                   choice: colorMapMode
  2990                   choice: colorMapMode
  3003                   choiceValue: masked24
  2991                   choiceValue: masked24
  3004             enabled: imageIsLoadedAndNotReadonlyHolder
       
  3005                 )
  2992                 )
  3006                (MenuItem
  2993                (MenuItem
  3007                   label: '-'
  2994                   label: '-'
  3008                 )
  2995                 )
  3009                (MenuItem
  2996                (MenuItem
  3010                   activeHelpKey: colorMap32
  2997                   activeHelpKey: colorMap32
       
  2998                   enabled: imageIsLoadedAndNotReadonlyHolder
  3011                   label: '32-Plane (rgba)'
  2999                   label: '32-Plane (rgba)'
  3012                   itemValue: colorMapMode:
  3000                   itemValue: colorMapMode:
  3013                   translateLabel: true
       
  3014                   argument: depth32
  3001                   argument: depth32
  3015                   choice: colorMapMode
  3002                   choice: colorMapMode
  3016                   choiceValue: depth32
  3003                   choiceValue: depth32
  3017             enabled: imageIsLoadedAndNotReadonlyHolder
       
  3018                 )
  3004                 )
  3019                )
  3005                )
  3020               nil
  3006               nil
  3021               nil
  3007               nil
  3022             )
  3008             )
  3023           )
  3009           )
  3024          (MenuItem
  3010          (MenuItem
  3025             enabled: imageIsLoadedAndNotReadonlyHolder
  3011             enabled: imageIsLoadedAndNotReadonlyHolder
  3026             label: 'ColorMap'
  3012             label: 'ColorMap'
  3027             translateLabel: true
       
  3028             submenu: 
  3013             submenu: 
  3029            (Menu
  3014            (Menu
  3030               (
  3015               (
  3031                (MenuItem
  3016                (MenuItem
  3032                   activeHelpKey: compressColormap
  3017                   activeHelpKey: compressColormap
  3033                   enabled: hasColormapHolder
  3018                   enabled: hasColormapHolder
  3034                   label: 'Compress Colormap'
  3019                   label: 'Compress Colormap'
  3035                   itemValue: #'menu_compressColorMap'
  3020                   itemValue: #'menu_compressColorMap'
  3036                   translateLabel: true
       
  3037                 )
  3021                 )
  3038                (MenuItem
  3022                (MenuItem
  3039                   enabled: hasColormapHolder
  3023                   enabled: hasColormapHolder
  3040                   label: 'Sort Colormap'
  3024                   label: 'Sort Colormap'
  3041                   itemValue: #'menu_sortColorMap'
  3025                   itemValue: #'menu_sortColorMap'
  3042                   translateLabel: true
       
  3043                 )
  3026                 )
  3044                (MenuItem
  3027                (MenuItem
  3045                   label: 'Reduce Number of Colors by Rounding...'
  3028                   label: 'Reduce Number of Colors by Rounding...'
  3046                   itemValue: reduceNumberOfColors2
  3029                   itemValue: reduceNumberOfColors2
  3047                   translateLabel: true
       
  3048                 )
  3030                 )
  3049                (MenuItem
  3031                (MenuItem
  3050                   label: 'Reduce Number of Colors by Masking Bits...'
  3032                   label: 'Reduce Number of Colors by Masking Bits...'
  3051                   itemValue: reduceNumberOfColors
  3033                   itemValue: reduceNumberOfColors
  3052                   translateLabel: true
       
  3053                 )
       
  3054                (MenuItem
       
  3055                   label: '-'
       
  3056                 )
       
  3057                (MenuItem
       
  3058                   enabled: imageIsLoadedHolder
       
  3059                   label: 'Brighten'
       
  3060                   itemValue: doBrightenImage
       
  3061                   translateLabel: true
       
  3062                 )
       
  3063                (MenuItem
       
  3064                   enabled: imageIsLoadedHolder
       
  3065                   label: 'Darken'
       
  3066                   itemValue: doDarkenImage
       
  3067                   translateLabel: true
       
  3068                 )
       
  3069                (MenuItem
       
  3070                   enabled: imageIsLoadedHolder
       
  3071                   label: 'Invert'
       
  3072                   itemValue: doNegativeImage
       
  3073                   translateLabel: true
       
  3074                 )
  3034                 )
  3075                )
  3035                )
  3076               nil
  3036               nil
  3077               nil
  3037               nil
  3078             )
  3038             )
  3079           )
  3039           )
  3080          (MenuItem
  3040          (MenuItem
  3081             enabled: imageIsLoadedAndNotReadonlyHolder
  3041             enabled: imageIsLoadedAndNotReadonlyHolder
  3082             label: 'Process'
  3042             label: 'Process'
  3083             translateLabel: true
       
  3084             submenu: 
  3043             submenu: 
  3085            (Menu
  3044            (Menu
  3086               (
  3045               (
  3087                (MenuItem
  3046                (MenuItem
  3088                   label: 'Make GrayScale'
  3047                   label: 'Negative'
  3089                   itemValue: makeGrayScaleImage
  3048                   itemValue: makeNegative
  3090                   translateLabel: true
       
  3091                 )
  3049                 )
  3092                (MenuItem
  3050                (MenuItem
  3093                   label: 'Make Monochrome...'
  3051                   label: 'Invert Pixel Bits'
  3094                   itemValue: makeMonochromeImage
  3052                   itemValue: makeInvertedBits
  3095                   translateLabel: true
  3053                   isVisible: hasColormap
  3096                 )
       
  3097                (MenuItem
       
  3098                   label: 'Make Inverse'
       
  3099                   itemValue: makeInverse
       
  3100                   translateLabel: true
       
  3101                 )
  3054                 )
  3102                (MenuItem
  3055                (MenuItem
  3103                   label: '-'
  3056                   label: '-'
  3104                 )
  3057                 )
  3105                (MenuItem
  3058                (MenuItem
  3106                   enabled: allowedToChangeImageDimensionAndDepth
  3059                   enabled: allowedToChangeImageDimensionAndDepth
  3107                   label: 'Make dithered 8Bit Palette'
  3060                   label: 'Make dithered 8Bit Palette'
  3108                   itemValue: makeDitheredPaletteImage
  3061                   itemValue: makeDitheredPaletteImage
  3109                   translateLabel: true
       
  3110                   isVisible: false
  3062                   isVisible: false
  3111                 )
  3063                 )
  3112                (MenuItem
  3064                (MenuItem
  3113                   label: 'Dither to Depth...'
  3065                   label: 'Dither to Depth...'
  3114                   itemValue: ditherToDepth
  3066                   itemValue: ditherToDepth
  3115                   translateLabel: true
       
  3116                 )
  3067                 )
  3117                (MenuItem
  3068                (MenuItem
  3118                   label: 'Threshold to Depth...'
  3069                   label: 'Threshold to Depth...'
  3119                   itemValue: thresholdToDepth
  3070                   itemValue: thresholdToDepth
  3120                   translateLabel: true
  3071                 )
       
  3072                (MenuItem
       
  3073                   label: '-'
       
  3074                 )
       
  3075                (MenuItem
       
  3076                   label: 'Make Monochrome...'
       
  3077                   itemValue: makeMonochromeImage
       
  3078                 )
       
  3079                (MenuItem
       
  3080                   label: 'Make GrayScale (same Depth)'
       
  3081                   itemValue: makeGrayScaleImage
  3121                 )
  3082                 )
  3122                (MenuItem
  3083                (MenuItem
  3123                   label: 'Make GrayScale with Depth (Dither)...'
  3084                   label: 'Make GrayScale with Depth (Dither)...'
  3124                   itemValue: ditherGrayToDepth
  3085                   itemValue: ditherGrayToDepth
  3125                   translateLabel: true
       
  3126                 )
  3086                 )
  3127                (MenuItem
  3087                (MenuItem
  3128                   label: 'Make GrayScale with Depth (Threshold)...'
  3088                   label: 'Make GrayScale with Depth (Threshold)...'
  3129                   itemValue: thresholdGrayToDepth
  3089                   itemValue: thresholdGrayToDepth
  3130                   translateLabel: true
       
  3131                 )
  3090                 )
  3132                (MenuItem
  3091                (MenuItem
  3133                   label: '-'
  3092                   label: '-'
  3134                 )
  3093                 )
  3135                (MenuItem
  3094                (MenuItem
  3136                   label: 'Make Slightly Brighter'
  3095                   label: 'Make Slightly Brighter'
  3137                   itemValue: makeSlightlyBrighter
  3096                   itemValue: makeSlightlyBrighter
  3138                   translateLabel: true
  3097                 )
       
  3098                (MenuItem
       
  3099                   label: 'Make Brighter'
       
  3100                   itemValue: makeBrighter
  3139                 )
  3101                 )
  3140                (MenuItem
  3102                (MenuItem
  3141                   label: 'Make Slightly Darker'
  3103                   label: 'Make Slightly Darker'
  3142                   itemValue: makeSlightlyDarker
  3104                   itemValue: makeSlightlyDarker
  3143                   translateLabel: true
       
  3144                 )
       
  3145                (MenuItem
       
  3146                   label: '-'
       
  3147                 )
       
  3148                (MenuItem
       
  3149                   label: 'Make Brighter'
       
  3150                   itemValue: makeBrighter
       
  3151                   translateLabel: true
       
  3152                 )
  3105                 )
  3153                (MenuItem
  3106                (MenuItem
  3154                   label: 'Make Darker'
  3107                   label: 'Make Darker'
  3155                   itemValue: makeDarker
  3108                   itemValue: makeDarker
  3156                   translateLabel: true
       
  3157                 )
  3109                 )
  3158                (MenuItem
  3110                (MenuItem
  3159                   label: '-'
  3111                   label: '-'
  3160                 )
  3112                 )
  3161                (MenuItem
  3113                (MenuItem
  3162                   label: 'Change HLS...'
  3114                   label: 'Change HLS...'
  3163                   itemValue: changeHLS
  3115                   itemValue: changeHLS
  3164                   translateLabel: true
       
  3165                 )
  3116                 )
  3166                (MenuItem
  3117                (MenuItem
  3167                   label: 'Colorize...'
  3118                   label: 'Colorize...'
  3168                   itemValue: colorize
  3119                   itemValue: colorize
  3169                   translateLabel: true
  3120                 )
       
  3121                (MenuItem
       
  3122                   enabled: imageIsLoadedHolder
       
  3123                   label: 'Brighten'
       
  3124                   itemValue: doBrightenImage
       
  3125                 )
       
  3126                (MenuItem
       
  3127                   enabled: imageIsLoadedHolder
       
  3128                   label: 'Darken'
       
  3129                   itemValue: doDarkenImage
  3170                 )
  3130                 )
  3171                )
  3131                )
  3172               nil
  3132               nil
  3173               nil
  3133               nil
  3174             )
  3134             )
  3175           )
  3135           )
  3176          (MenuItem
  3136          (MenuItem
  3177             enabled: imageIsLoadedAndNotReadonlyHolder
  3137             enabled: imageIsLoadedAndNotReadonlyHolder
  3178             label: 'Mask'
  3138             label: 'Mask'
  3179             translateLabel: true
       
  3180             submenu: 
  3139             submenu: 
  3181            (Menu
  3140            (Menu
  3182               (
  3141               (
  3183                (MenuItem
  3142                (MenuItem
  3184                   activeHelpKey: copyMask
  3143                   activeHelpKey: copyMask
  3185                   enabled: hasMask
  3144                   enabled: hasMask
  3186                   label: 'Copy Mask'
  3145                   label: 'Copy Mask'
  3187                   itemValue: #'menu_copyMask'
  3146                   itemValue: #'menu_copyMask'
  3188                   translateLabel: true
       
  3189                 )
  3147                 )
  3190                (MenuItem
  3148                (MenuItem
  3191                   activeHelpKey: pasteMask
  3149                   activeHelpKey: pasteMask
  3192                   enabled: hasMask
  3150                   enabled: hasMask
  3193                   label: 'Paste Mask'
  3151                   label: 'Paste Mask'
  3194                   itemValue: #'menu_pasteMask'
  3152                   itemValue: #'menu_pasteMask'
  3195                   translateLabel: true
       
  3196                 )
  3153                 )
  3197                (MenuItem
  3154                (MenuItem
  3198                   enabled: hasMask
  3155                   enabled: hasMask
  3199                   label: 'Clear Masked Pixels'
  3156                   label: 'Clear Masked Pixels'
  3200                   itemValue: #'menu_clearMaskedPixels'
  3157                   itemValue: #'menu_clearMaskedPixels'
  3201                   translateLabel: true
       
  3202                 )
  3158                 )
  3203                (MenuItem
  3159                (MenuItem
  3204                   enabled: hasMask
  3160                   enabled: hasMask
  3205                   label: 'Clear Colormap Entry for Masked Pixels'
  3161                   label: 'Clear Colormap Entry for Masked Pixels'
  3206                   itemValue: #'menu_clearColormapEntry0AndMaskedPixels'
  3162                   itemValue: #'menu_clearColormapEntry0AndMaskedPixels'
  3207                   translateLabel: true
       
  3208                 )
  3163                 )
  3209                )
  3164                )
  3210               nil
  3165               nil
  3211               nil
  3166               nil
  3212             )
  3167             )
  3214          )
  3169          )
  3215         nil
  3170         nil
  3216         nil
  3171         nil
  3217       )
  3172       )
  3218 
  3173 
  3219     "Modified: / 30-08-2017 / 00:35:31 / cg"
  3174     "Modified: / 31-08-2017 / 14:43:51 / cg"
  3220 !
  3175 !
  3221 
  3176 
  3222 menuEdit
  3177 menuEdit
  3223     <resource: #menu>
  3178     <resource: #menu>
  3224     "This resource specification was automatically generated
  3179     "This resource specification was automatically generated
  4586     "Modified: / 23-02-2017 / 09:57:45 / cg"
  4541     "Modified: / 23-02-2017 / 09:57:45 / cg"
  4587     "Modified (comment): / 31-08-2017 / 18:36:08 / cg"
  4542     "Modified (comment): / 31-08-2017 / 18:36:08 / cg"
  4588 !
  4543 !
  4589 
  4544 
  4590 hasColormapAndColorSelected
  4545 hasColormapAndColorSelected
  4591     ^ [ self hasColormapHolder value and:[self hasColorSelectedHolder value]]
  4546     ^ [ self hasColormap and:[self hasColorSelectedHolder value]]
  4592 
  4547 
  4593     "Modified: / 04-07-2010 / 10:13:13 / cg"
  4548     "Modified: / 31-08-2017 / 14:08:20 / cg"
  4594 !
  4549 !
  4595 
  4550 
  4596 hasColormapAndSingleColorSelected
  4551 hasColormapAndSingleColorSelected
  4597     ^ self hasColormapHolder value and:[self hasSingleColorSelectedHolder value]
  4552     ^ self hasColormapHolder value and:[self hasSingleColorSelectedHolder value]
  4598 
  4553 
  5127 !
  5082 !
  5128 
  5083 
  5129 updateLabelsAndHistory
  5084 updateLabelsAndHistory
  5130     "updates labels and history, if something has changed"
  5085     "updates labels and history, if something has changed"
  5131 
  5086 
  5132     |image|
  5087     |image rsrcClass rsrcSelector imgFile|
  5133 
  5088 
  5134     image := self image.
  5089     image := self image.
  5135 
  5090 
  5136     self imageIsLoadedHolder value: image notNil.
  5091     self imageIsLoadedHolder value: image notNil.
  5137     image isNil ifTrue: [^nil].
  5092     image isNil ifTrue: [^nil].
  5138 
  5093 
  5139     self updateInfoLabel.
  5094     self updateInfoLabel.
  5140 
  5095 
  5141     imageEditView resourceClass notNil ifTrue:[
  5096     ((rsrcClass := imageEditView resourceClass) notNil 
  5142         imageEditView resourceSelector notNil ifTrue:[
  5097     and:[ (rsrcSelector := imageEditView resourceSelector) notNil ]) ifTrue:[
  5143             self addHistoryEntryForClass:imageEditView resourceClass selector:imageEditView resourceSelector.
  5098         self addHistoryEntryForClass:rsrcClass selector:rsrcSelector.
  5144         ]
  5099     ] ifFalse:[
  5145     ].
  5100         (imgFile := image fileName) notNil ifTrue: [
  5146 
  5101             self addHistoryEntryForFile:imgFile.
  5147     image fileName notNil ifTrue: [
  5102         ].
  5148         self addHistoryEntryForFile:image fileName.
  5103     ].
  5149     ].
  5104 
  5150 
  5105     "Modified: / 01-09-2017 / 10:10:12 / cg"
  5151     "Modified: / 04-07-2010 / 10:16:02 / cg"
       
  5152 !
  5106 !
  5153 
  5107 
  5154 updateListOfColorsAndColormapMode
  5108 updateListOfColorsAndColormapMode
  5155     |selectedColor colorMap image|
  5109     |selectedColor colorMap image|
  5156 
  5110 
  5982 ! !
  5936 ! !
  5983 
  5937 
  5984 !ImageEditor methodsFor:'user actions-colormap'!
  5938 !ImageEditor methodsFor:'user actions-colormap'!
  5985 
  5939 
  5986 addColorToColormap
  5940 addColorToColormap
  5987     self addColorToColormap:(Color black)
  5941     "undoable: add black (a new color) to the map"
       
  5942     
       
  5943     self addColorToColormap:(Color black) undoable:true
       
  5944 
       
  5945     "Modified: / 31-08-2017 / 14:30:32 / cg"
  5988 !
  5946 !
  5989 
  5947 
  5990 addColorToColormap:newColor
  5948 addColorToColormap:newColor
  5991     "when editing a palette image, the new color is added to the images colorMap
  5949     "undoable
       
  5950      when editing a palette image, the new color is added to the image's colorMap
  5992      (unless it is full).
  5951      (unless it is full).
  5993      when editing a true-color image, it is added to my own list-of-colors,
  5952      When editing a true-color image, it is added to my own list-of-colors,
  5994      which only holds drawing colors, but is not the colormap's image"
  5953      which only holds drawing colors, but is not the colormap's image"
  5995      
  5954      
  5996     |depth img cMap newColorMap newImage oldCListSize newMode listOfColors|
  5955     |depth img cMap newColorMap newImage oldCListSize newMode listOfColors|
  5997 
  5956 
  5998     img := self image.
  5957     img := self image.
  6061         self updateLabelsAndHistory.
  6020         self updateLabelsAndHistory.
  6062     ]
  6021     ]
  6063 
  6022 
  6064     "Created: / 12-03-1999 / 00:20:28 / cg"
  6023     "Created: / 12-03-1999 / 00:20:28 / cg"
  6065     "Modified: / 16-02-2017 / 10:17:25 / cg"
  6024     "Modified: / 16-02-2017 / 10:17:25 / cg"
       
  6025     "Modified (comment): / 31-08-2017 / 14:28:11 / cg"
       
  6026 !
       
  6027 
       
  6028 addColorToColormap:newColor undoable:undoable
       
  6029     "when editing a palette image, the new color is added to the image's colorMap
       
  6030      (unless it is full).
       
  6031      When editing a true-color image, it is added to my own list-of-colors,
       
  6032      which only holds drawing colors, but is not the colormap's image"
       
  6033      
       
  6034     |depth img cMap newColorMap newImage oldCListSize newMode listOfColors|
       
  6035 
       
  6036     img := self image.
       
  6037     img isNil ifTrue:[
       
  6038         self warn:'No Image.'.
       
  6039         ^ self
       
  6040     ].
       
  6041 
       
  6042     depth := img depth.
       
  6043     cMap := img colorMap.
       
  6044     (cMap isNil or:[cMap isMappedPalette or:[cMap isFixedPalette]]) ifTrue:[
       
  6045         drawingColormap isNil ifTrue:[
       
  6046             self information:(resources stringWithCRs:'Image has no colormap.\The shown colorMap is for drawing only.').
       
  6047             drawingColormap := OrderedCollection new.
       
  6048         ].
       
  6049         drawingColormap add:newColor.
       
  6050         self listOfColors contents:drawingColormap.
       
  6051         self selectedColors value:{drawingColormap size}.
       
  6052         "/ self warn:'Image has no colormap.\Change colorMap mode first.' withCRs.
       
  6053         ^ self
       
  6054     ].
       
  6055 
       
  6056     (cMap size == (1 bitShift:depth)) ifTrue:[
       
  6057         depth >= 8 ifTrue:[
       
  6058             self warn:'No space for more colors in colormap.'.
       
  6059             ^ self
       
  6060         ].
       
  6061         (self confirm:(resources stringWithCRs:'No space for more colors in colormap.\Change depth ?'))
       
  6062         ifFalse:[
       
  6063             ^ self
       
  6064         ].
       
  6065 
       
  6066         undoable ifTrue:[ imageEditView makeUndo ].
       
  6067         img mask notNil ifTrue:[
       
  6068             newMode := 'masked' , (depth*2) printString.
       
  6069         ] ifFalse:[
       
  6070             newMode := 'depth' , (depth*2) printString.
       
  6071         ].
       
  6072         self colorMapMode:newMode.
       
  6073     ] ifFalse:[
       
  6074         undoable ifTrue:[ imageEditView makeUndo ].
       
  6075     ].
       
  6076 
       
  6077     cMap := cMap asArray.
       
  6078     listOfColors := self listOfColors.
       
  6079     oldCListSize := listOfColors size.
       
  6080 
       
  6081     newColorMap := cMap copyWith:newColor.
       
  6082 
       
  6083     newImage := img species new
       
  6084                     width:(img width) height:(img height) depth:depth
       
  6085                     fromArray:img bits.
       
  6086 
       
  6087     newImage colorMap:newColorMap.  
       
  6088     newImage fileName:img fileName.
       
  6089     newImage mask:(img mask copy).
       
  6090 
       
  6091     (imageEditView image:newImage) notNil ifTrue:[
       
  6092         listOfColors contents: newImage colorMap.
       
  6093         self findColorMapMode.
       
  6094         "/ mhmh - somehow, we get two colors added ... (sigh findColorMapMode adds another one ...)
       
  6095         listOfColors size > (oldCListSize + 1) ifTrue:[
       
  6096             listOfColors removeLast
       
  6097         ].
       
  6098         self selectedColors value:{listOfColors size}.
       
  6099         self updateLabelsAndHistory.
       
  6100     ]
       
  6101 
       
  6102     "Created: / 31-08-2017 / 14:30:01 / cg"
  6066 !
  6103 !
  6067 
  6104 
  6068 changeHLS
  6105 changeHLS
  6069     "interactive Hue/Light/Saturation editing with thumbWheels"
  6106     "interactive Hue/Light/Saturation editing with thumbWheels"
  6070 
  6107 
  6332      0 and then clear all masked pixels (to pixelValue 0).
  6369      0 and then clear all masked pixels (to pixelValue 0).
  6333      This is required for windows icons to be really transparent"
  6370      This is required for windows icons to be really transparent"
  6334 
  6371 
  6335     |index colorMap| 
  6372     |index colorMap| 
  6336 
  6373 
  6337     self compressColorMap.
  6374     self nonUndoableCompressColorMap.
       
  6375     
  6338     colorMap := self image colorMap.
  6376     colorMap := self image colorMap.
  6339     (colorMap includes:(Color black)) ifFalse:[
  6377     (colorMap includes:(Color black)) ifFalse:[
  6340         self addColorToColormap:(Color black).
  6378         self addColorToColormap:(Color black) undoable:false.
  6341         colorMap := self image colorMap.
  6379         colorMap := self image colorMap.
  6342     ].
  6380     ].
  6343     index := colorMap indexOf:(Color black).
  6381     index := colorMap indexOf:(Color black).
  6344     index == 1 ifFalse:[
  6382     index == 1 ifFalse:[
  6345         self sortColorMap.
  6383         self nonUndoableSortColorMapWith:self sortBlockForColorsByRGB.
  6346         colorMap := self image colorMap.
  6384         colorMap := self image colorMap.
  6347     ].
  6385     ].
  6348     self clearMaskedPixels
  6386     self nonUndoableClearMaskedPixels
       
  6387 
       
  6388     "Modified: / 31-08-2017 / 14:30:28 / cg"
  6349 !
  6389 !
  6350 
  6390 
  6351 clearMaskedPixels
  6391 clearMaskedPixels
  6352     "clear all masked pixels (to pixelValue 0)"
  6392     "clear all masked pixels (to pixelValue 0)"
  6353 
  6393 
  6469                             oldImage depth == 8 ifTrue:[
  6509                             oldImage depth == 8 ifTrue:[
  6470                                 tmpBits := oldImage bits
  6510                                 tmpBits := oldImage bits
  6471                             ] ifFalse:[
  6511                             ] ifFalse:[
  6472                                 colorMapMode value:prevMode.
  6512                                 colorMapMode value:prevMode.
  6473                                 self findColorMapMode.    
  6513                                 self findColorMapMode.    
  6474                                 self warn:('Too many used colors in image (', oldImage usedColors size printString , ').').
  6514                                 self warn:(resources 
       
  6515                                             stringWithCRs:'Too many used colors (%1) in image.\\You should choose one of:\\- convert the image to grey\- reduce the number of colors\- dither to depth\- choose another depth'
       
  6516                                             with: oldImage realUsedColors size ).
  6475                                 ^ self
  6517                                 ^ self
  6476     "/                            (self confirm:('Too many used colors in image (', oldImage usedColors size printString , ').\\Dither ?' withCRs))
  6518     "/                            (self confirm:('Too many used colors in image (', oldImage usedColors size printString , ').\\Dither ?' withCRs))
  6477     "/                            ifFalse:[.
  6519     "/                            ifFalse:[.
  6478     "/                                ^ self
  6520     "/                                ^ self
  6479     "/                            ].
  6521     "/                            ].
  6634         (imageEditView image: image) notNil ifTrue:[
  6676         (imageEditView image: image) notNil ifTrue:[
  6635             self fetchImageData.
  6677             self fetchImageData.
  6636         ]
  6678         ]
  6637     ]
  6679     ]
  6638 
  6680 
  6639     "Modified: / 24-08-2017 / 18:16:02 / cg"
  6681     "Modified: / 31-08-2017 / 14:41:06 / cg"
  6640 !
  6682 !
  6641 
  6683 
  6642 colorize
  6684 colorize
  6643     "interactive Hue editing"
  6685     "interactive Hue editing"
  6644 
  6686 
  6806         self image colorMap inspect
  6848         self image colorMap inspect
  6807     ].
  6849     ].
  6808 !
  6850 !
  6809 
  6851 
  6810 makeBrighter
  6852 makeBrighter
  6811     | anyChange|
  6853     self updateImageAfterDoing:#makeBrighter.
  6812 
  6854 
  6813     self withExecuteCursorDo:[
  6855     "Modified: / 31-08-2017 / 12:16:30 / cg"
  6814         anyChange := imageEditView makeBrighter.
       
  6815         anyChange ifFalse:[
       
  6816             Dialog warn:'Image unchanged'.
       
  6817         ] ifTrue:[
       
  6818             self updateImage.
       
  6819         ]
       
  6820     ].
       
  6821 !
  6856 !
  6822 
  6857 
  6823 makeDarker
  6858 makeDarker
  6824     | anyChange|
  6859     self updateImageAfterDoing:#makeDarker.
  6825 
  6860 
  6826     self withExecuteCursorDo:[
  6861     "Modified: / 31-08-2017 / 12:16:24 / cg"
  6827         anyChange := imageEditView makeDarker.
       
  6828         anyChange ifFalse:[
       
  6829             Dialog warn:'Image unchanged'.
       
  6830         ] ifTrue:[
       
  6831             self updateImage.
       
  6832         ]
       
  6833     ].
       
  6834 !
  6862 !
  6835 
  6863 
  6836 makeGrayScaleImage
  6864 makeGrayScaleImage
  6837     |anyChange|
  6865     self updateImageAfterDoing:#makeGrayScaleImage.
  6838 
  6866 
  6839     self withExecuteCursorDo:[
  6867     "Modified: / 31-08-2017 / 12:16:15 / cg"
  6840         anyChange := imageEditView makeGrayScaleImage.
       
  6841         anyChange ifFalse:[
       
  6842             Dialog warn:'Image unchanged'.
       
  6843         ] ifTrue:[
       
  6844             self updateImage.
       
  6845         ]
       
  6846     ].
       
  6847 !
       
  6848 
       
  6849 makeInverse
       
  6850     | anyChange|
       
  6851 
       
  6852     self withExecuteCursorDo:[
       
  6853         anyChange := imageEditView makeInverse.
       
  6854         anyChange ifFalse:[
       
  6855             Dialog warn:'Image unchanged'.
       
  6856         ] ifTrue:[
       
  6857             self updateImage.
       
  6858         ]
       
  6859     ].
       
  6860 !
  6868 !
  6861 
  6869 
  6862 makeSelectedColorBrighter
  6870 makeSelectedColorBrighter
  6863     self processSelectedColorsWith:[:clr | clr lightened]
  6871     self processSelectedColorsWith:[:clr | clr lightened]
  6864 !
  6872 !
  6870 makeSelectedColorGray
  6878 makeSelectedColorGray
  6871     self processSelectedColorsWith:[:clr | Color brightness:(clr brightness)]
  6879     self processSelectedColorsWith:[:clr | Color brightness:(clr brightness)]
  6872 !
  6880 !
  6873 
  6881 
  6874 makeSelectedColorShifted
  6882 makeSelectedColorShifted
  6875     |cMap colors|
  6883     "shift the selected color (in the colormap)
       
  6884      using the hls/rgb shifting slider dialog"
       
  6885      
       
  6886     |cMap colors cmapOffset|
  6876 
  6887 
  6877     cMap := self image colorMap.
  6888     cMap := self image colorMap.
  6878     self hasMask ifTrue:[
  6889     
  6879         colors := self selectedColors value collect:[:idx | cMap at:idx-1].
  6890     "/ if there is a mask, it is at position 1 in the table
  6880     ] ifFalse:[
  6891     cmapOffset := self hasMask ifTrue:[1] ifFalse:[0].
  6881         colors := self selectedColors value collect:[:idx | cMap at:idx].
  6892     colors := self selectedColors value collect:[:idx | cMap at:idx-cmapOffset].
  6882     ].
       
  6883     self changeHLSOfColors:colors.
  6893     self changeHLSOfColors:colors.
       
  6894 
       
  6895     "Modified: / 31-08-2017 / 14:15:03 / cg"
  6884 !
  6896 !
  6885 
  6897 
  6886 makeSlightlyBrighter
  6898 makeSlightlyBrighter
  6887     | anyChange|
  6899     self updateImageAfterDoing:#makeSlightlyBrighter.
  6888 
       
  6889     self withExecuteCursorDo:[
       
  6890         anyChange := imageEditView makeSlightlyBrighter.
       
  6891         anyChange ifFalse:[
       
  6892             Dialog warn:'Image unchanged'.
       
  6893         ] ifTrue:[
       
  6894             self updateImage.
       
  6895         ]
       
  6896     ].
       
  6897 
  6900 
  6898     "Created: / 24-11-2010 / 11:06:11 / cg"
  6901     "Created: / 24-11-2010 / 11:06:11 / cg"
       
  6902     "Modified: / 31-08-2017 / 12:16:01 / cg"
  6899 !
  6903 !
  6900 
  6904 
  6901 makeSlightlyDarker
  6905 makeSlightlyDarker
  6902     | anyChange|
  6906     self updateImageAfterDoing:#makeSlightlyDarker.
  6903 
       
  6904     self withExecuteCursorDo:[
       
  6905         anyChange := imageEditView makeSlightlyDarker.
       
  6906         anyChange ifFalse:[
       
  6907             Dialog warn:'Image unchanged'.
       
  6908         ] ifTrue:[
       
  6909             self updateImage.
       
  6910         ]
       
  6911     ].
       
  6912 
  6907 
  6913     "Created: / 24-11-2010 / 11:06:23 / cg"
  6908     "Created: / 24-11-2010 / 11:06:23 / cg"
       
  6909     "Modified: / 31-08-2017 / 12:15:55 / cg"
  6914 !
  6910 !
  6915 
  6911 
  6916 menu_clearColormapEntry0AndMaskedPixels
  6912 menu_clearColormapEntry0AndMaskedPixels
  6917     "ensure that there is a colorMap entry with 0/0/0 at position
  6913     "ensure that there is a colorMap entry with 0/0/0 at position
  6918      0 and then clear all masked pixels (to pixelValue 0)"
  6914      0 and then clear all masked pixels (to pixelValue 0)"
  6919 
  6915 
  6920     imageEditView makeUndo.
  6916     imageEditView makeUndo.
  6921     self withExecuteCursorDo:[
  6917     self withExecuteCursorDo:[
  6922         self clearColormapEntry0AndMaskedPixels
  6918         self nonUndoableClearColormapEntry0AndMaskedPixels
  6923     ]
  6919     ]
       
  6920 
       
  6921     "Modified: / 31-08-2017 / 14:31:21 / cg"
  6924 !
  6922 !
  6925 
  6923 
  6926 menu_clearMaskedPixels
  6924 menu_clearMaskedPixels
  6927     "clear all masked pixels (to pixelValue 0)"
  6925     "clear all masked pixels (to pixelValue 0)"
  6928 
  6926 
  6929     imageEditView makeUndo.
  6927     imageEditView makeUndo.
  6930 
       
  6931     self withExecuteCursorDo:[
  6928     self withExecuteCursorDo:[
  6932         self clearMaskedPixels
  6929         self nonUndoableClearMaskedPixels
  6933     ]
  6930     ]
       
  6931 
       
  6932     "Modified: / 31-08-2017 / 14:23:20 / cg"
  6934 !
  6933 !
  6935 
  6934 
  6936 menu_compressColorMap
  6935 menu_compressColorMap
  6937     "calculates a new color map for the image, using only used colors"
  6936     "calculates a new color map for the image, using only used colors"
  6938 
  6937 
  6951         self information:'Compress colorMap: Colormap already compressed - no compression.'.
  6950         self information:'Compress colorMap: Colormap already compressed - no compression.'.
  6952         ^ self
  6951         ^ self
  6953     ].
  6952     ].
  6954 
  6953 
  6955     imageEditView makeUndo.
  6954     imageEditView makeUndo.
  6956 
       
  6957     self withExecuteCursorDo:[
  6955     self withExecuteCursorDo:[
  6958         self compressColorMap
  6956         self nonUndoableCompressColorMap
  6959     ]
  6957     ]
       
  6958 
       
  6959     "Modified: / 31-08-2017 / 14:22:19 / cg"
  6960 !
  6960 !
  6961 
  6961 
  6962 menu_copyMask
  6962 menu_copyMask
  6963     |mask|
  6963     |mask|
  6964 
  6964 
  6999         self information:'Compress colorMap: Only palette images have colormaps.'.
  6999         self information:'Compress colorMap: Only palette images have colormaps.'.
  7000         ^ self
  7000         ^ self
  7001     ].
  7001     ].
  7002 
  7002 
  7003     imageEditView makeUndo.
  7003     imageEditView makeUndo.
  7004 
       
  7005     self withExecuteCursorDo:[
  7004     self withExecuteCursorDo:[
  7006         self sortColorMapWith:sortBlock
  7005         self nonUndoableSortColorMapWith:sortBlock
  7007     ]
  7006     ]
  7008 
  7007 
  7009     "Modified: / 15.9.1998 / 17:53:32 / cg"
  7008     "Created: / 30-09-1998 / 23:51:23 / cg"
  7010     "Created: / 30.9.1998 / 23:51:23 / cg"
  7009     "Modified: / 31-08-2017 / 14:20:14 / cg"
  7011 !
  7010 !
  7012 
  7011 
  7013 pasteColorIntoColormap
  7012 pasteColorIntoColormap
  7014     |copyBufferColor cmap|
  7013     |copyBufferColor cmap|
  7015 
  7014 
  7037 
  7036 
  7038     "Modified: / 03-02-2017 / 21:45:45 / cg"
  7037     "Modified: / 03-02-2017 / 21:45:45 / cg"
  7039 !
  7038 !
  7040 
  7039 
  7041 pickAndAddColorToColormap
  7040 pickAndAddColorToColormap
  7042     self addColorToColormap:(Color fromUser)
  7041     self addColorToColormap:(Color fromUser) undoable:true
       
  7042 
       
  7043     "Modified: / 31-08-2017 / 14:30:22 / cg"
  7043 !
  7044 !
  7044 
  7045 
  7045 pickAndPasteColor
  7046 pickAndPasteColor
  7046     self pickColor.
  7047     self pickColor.
  7047     self pasteColorIntoColormap.
  7048     self pasteColorIntoColormap.
  7299 !
  7300 !
  7300 
  7301 
  7301 sortColorMap
  7302 sortColorMap
  7302     "calculates a new color map for the image, sorting colors"
  7303     "calculates a new color map for the image, sorting colors"
  7303 
  7304 
  7304     self sortColorMapWith:self sortBlockForColorsByRGB
  7305     self nonUndoableSortColorMapWith:self sortBlockForColorsByRGB
       
  7306 
       
  7307     "Modified: / 31-08-2017 / 14:20:07 / cg"
  7305 !
  7308 !
  7306 
  7309 
  7307 sortColorMapWith:sortBlock
  7310 sortColorMapWith:sortBlock
  7308     "calculates a new color map for the image, sorting colors"
  7311     "warning: not undoable
       
  7312      calculates a new color map for the image, sorting colors"
  7309 
  7313 
  7310     |depth newColorMap newImage oldImage usedColors oldToNew oldBits newBits tmpBits
  7314     |depth newColorMap newImage oldImage usedColors oldToNew oldBits newBits tmpBits
  7311      expectedSize w h| 
  7315      expectedSize w h| 
  7312 
  7316 
  7313     oldImage := self image.
  7317     oldImage := self image.
  7371 
  7375 
  7372     (imageEditView image:newImage) notNil ifTrue:[
  7376     (imageEditView image:newImage) notNil ifTrue:[
  7373         self fetchImageData.
  7377         self fetchImageData.
  7374     ]
  7378     ]
  7375 
  7379 
  7376     "Modified: / 15.9.1998 / 17:53:32 / cg"
  7380     "Modified: / 15-09-1998 / 17:53:32 / cg"
  7377     "Created: / 30.9.1998 / 23:51:23 / cg"
  7381     "Created: / 30-09-1998 / 23:51:23 / cg"
       
  7382     "Modified (comment): / 31-08-2017 / 14:19:21 / cg"
       
  7383 !
       
  7384 
       
  7385 updateImageAfterDoing:aBlockOrSelector
       
  7386     self withExecuteCursorDo:[
       
  7387         aBlockOrSelector value:imageEditView.
       
  7388         self updateImage.
       
  7389     ].
       
  7390 
       
  7391     "Created: / 31-08-2017 / 12:14:39 / cg"
       
  7392 ! !
       
  7393 
       
  7394 !ImageEditor methodsFor:'user actions-colormap-basic'!
       
  7395 
       
  7396 nonUndoableClearColormapEntry0AndMaskedPixels
       
  7397     "ensure that there is a colorMap entry with 0/0/0 at position
       
  7398      0 and then clear all masked pixels (to pixelValue 0).
       
  7399      This is required for windows icons to be really transparent"
       
  7400 
       
  7401     |index colorMap| 
       
  7402 
       
  7403     self nonUndoableCompressColorMap.
       
  7404     
       
  7405     colorMap := self image colorMap.
       
  7406     (colorMap includes:(Color black)) ifFalse:[
       
  7407         self addColorToColormap:(Color black) undoable:false.
       
  7408         colorMap := self image colorMap.
       
  7409     ].
       
  7410     index := colorMap indexOf:(Color black).
       
  7411     index == 1 ifFalse:[
       
  7412         self nonUndoableSortColorMapWith:self sortBlockForColorsByRGB.
       
  7413         colorMap := self image colorMap.
       
  7414     ].
       
  7415     self nonUndoableClearMaskedPixels
       
  7416 
       
  7417     "Created: / 31-08-2017 / 14:31:09 / cg"
       
  7418 !
       
  7419 
       
  7420 nonUndoableClearMaskedPixels
       
  7421     "clear all masked pixels (to pixelValue 0)"
       
  7422 
       
  7423     |newImage| 
       
  7424 
       
  7425     newImage := self image clearMaskedPixels.
       
  7426     0 to:newImage height - 1 do:[:y |
       
  7427         0 to:newImage width - 1 do:[:x |
       
  7428             (newImage maskAtX:x y:y) == 0 ifTrue:[
       
  7429                 newImage pixelAtX:x y:y put:0
       
  7430             ]
       
  7431         ]
       
  7432     ].
       
  7433 
       
  7434     (imageEditView image:newImage) notNil ifTrue:[
       
  7435         self fetchImageData.
       
  7436     ]
       
  7437 
       
  7438     "Created: / 31-08-2017 / 14:22:58 / cg"
       
  7439 !
       
  7440 
       
  7441 nonUndoableCompressColorMap
       
  7442     "not undoable
       
  7443      calculates a new color map for the image, using only used colors"
       
  7444 
       
  7445     |newImage| 
       
  7446 
       
  7447     newImage := self image.
       
  7448     newImage compressColorMap.
       
  7449 
       
  7450     (imageEditView image:newImage) notNil ifTrue:[
       
  7451         self fetchImageData.
       
  7452     ]
       
  7453 
       
  7454     "Created: / 31-08-2017 / 14:21:51 / cg"
       
  7455 !
       
  7456 
       
  7457 nonUndoableSortColorMapWith:sortBlock
       
  7458     "not undoable
       
  7459      calculates a new color map for the image, sorting colors"
       
  7460 
       
  7461     |depth newColorMap newImage oldImage usedColors oldToNew oldBits newBits tmpBits
       
  7462      expectedSize w h| 
       
  7463 
       
  7464     oldImage := self image.
       
  7465     depth := oldImage depth.
       
  7466     w := oldImage width.
       
  7467     h := oldImage height.
       
  7468 
       
  7469     usedColors := oldImage realColorMap.
       
  7470 
       
  7471     "/ translation table
       
  7472     oldToNew := ByteArray new:(1 bitShift:depth).
       
  7473     newColorMap := usedColors asArray.
       
  7474     newColorMap sort:sortBlock.
       
  7475 
       
  7476     oldImage colorMap asArray keysAndValuesDo:[:oldIdx :clr |
       
  7477         |newPixel|
       
  7478 
       
  7479         (usedColors includes:clr) ifTrue:[
       
  7480             newPixel := newColorMap indexOf:clr.
       
  7481             oldToNew at:oldIdx put:newPixel-1.
       
  7482         ]
       
  7483     ].
       
  7484 
       
  7485     oldBits := oldImage bits.
       
  7486     "/ sanity check...
       
  7487     expectedSize := ((w * h * depth + 7) // 8).
       
  7488     (oldBits size < expectedSize) ifTrue:[
       
  7489         self halt:'incorrect pixeldata size'.
       
  7490         oldBits := (ByteArray new:expectedSize) replaceFrom:1 with:oldBits; yourself.
       
  7491     ].
       
  7492     newBits := ByteArray new:(oldBits size).
       
  7493     depth ~~ 8 ifTrue:[
       
  7494 
       
  7495         "/ expand/compress can only handle 8bits
       
  7496         tmpBits := ByteArray uninitializedNew:(w*h).
       
  7497         oldBits
       
  7498             expandPixels:depth
       
  7499             width:w height:h 
       
  7500             into:tmpBits
       
  7501             mapping:oldToNew.
       
  7502         tmpBits
       
  7503             compressPixels:depth 
       
  7504             width:w height:h 
       
  7505             into:newBits 
       
  7506             mapping:nil
       
  7507     ] ifFalse:[
       
  7508         oldBits
       
  7509             expandPixels:depth
       
  7510             width:w height:h 
       
  7511             into:newBits
       
  7512             mapping:oldToNew.
       
  7513     ].
       
  7514 
       
  7515     newImage := oldImage species new
       
  7516                     width:w height:h depth:depth
       
  7517                     fromArray:newBits.
       
  7518 
       
  7519     newImage colorMap:newColorMap.  
       
  7520     newImage fileName:oldImage fileName.
       
  7521     newImage mask:(oldImage mask copy).
       
  7522 
       
  7523     (imageEditView image:newImage) notNil ifTrue:[
       
  7524         self fetchImageData.
       
  7525     ]
       
  7526 
       
  7527     "Created: / 31-08-2017 / 14:19:42 / cg"
  7378 ! !
  7528 ! !
  7379 
  7529 
  7380 !ImageEditor methodsFor:'user actions-editing'!
  7530 !ImageEditor methodsFor:'user actions-editing'!
  7381 
  7531 
  7382 autoCropAll
  7532 autoCropAll
  7421     imageEditView autoCropLeft:false right:false top:true bottom:false.   
  7571     imageEditView autoCropLeft:false right:false top:true bottom:false.   
  7422     self updateInfoLabel
  7572     self updateInfoLabel
  7423 
  7573 
  7424     "Created: / 20-02-2017 / 18:06:03 / cg"
  7574     "Created: / 20-02-2017 / 18:06:03 / cg"
  7425 !
  7575 !
       
  7576 
       
  7577 ditherGrayToDepth
       
  7578     self askForDepthThenDo:[:depth |
       
  7579         self ditherGrayToDepth:depth
       
  7580     ].
       
  7581 
       
  7582     "Created: / 24-08-2017 / 17:49:42 / cg"
       
  7583 !
       
  7584 
       
  7585 ditherGrayToDepth:depth
       
  7586     self withExecuteCursorDo:[
       
  7587         |newImage|
       
  7588 
       
  7589         depth == 1 ifTrue:[
       
  7590             newImage := self image asErrorDitheredMonochromeImage
       
  7591         ] ifFalse:[
       
  7592             newImage := self image asGrayImageDepth:depth dither:#floydSteinberg.
       
  7593         ].
       
  7594         imageEditView newImageWithUndo:newImage.
       
  7595     ].
       
  7596 
       
  7597     "Created: / 24-08-2017 / 17:51:07 / cg"
       
  7598     "Modified: / 30-08-2017 / 01:18:43 / cg"
       
  7599 !
       
  7600 
       
  7601 ditherToDepth
       
  7602     self askForDepthThenDo:[:depth |
       
  7603         self convertToDepth:depth dither:true
       
  7604     ].
       
  7605 
       
  7606     "Created: / 07-07-2006 / 13:22:10 / cg"
       
  7607     "Modified: / 30-08-2017 / 00:34:42 / cg"
       
  7608 !
       
  7609 
       
  7610 do3DProjection
       
  7611     "make a naive 3D projection;
       
  7612      can be used to create those typical marketing images as seen in web pages"
       
  7613      
       
  7614     |box dx1 dx2 image|
       
  7615 
       
  7616     image := imageEditView image.
       
  7617 
       
  7618     box := EnterBox new.
       
  7619     box title:(resources string:'dX1 (0 < dx < 0.5):').
       
  7620     box okText:(resources string:'OK').
       
  7621     box abortText:(resources string:'Cancel').
       
  7622     box initialText:'0.1'.
       
  7623     box showAtPointer.
       
  7624 
       
  7625     (box accepted 
       
  7626     and: [(dx1 := Number readFrom:(box contents) onError:nil) notNil])
       
  7627     ifTrue:[
       
  7628         box title:(resources string:'dX2 (0 < dx < 0.5):').
       
  7629         box initialText:(dx1 printString).
       
  7630         box showAtPointer.
       
  7631         (box accepted 
       
  7632         and: [(dx2 := Number readFrom:(box contents) onError:nil) notNil])
       
  7633         ifTrue:[
       
  7634             imageEditView threeDProjection:dx1 and:dx2.
       
  7635         ]
       
  7636     ].
       
  7637 
       
  7638     self updateInfoLabel
       
  7639 
       
  7640     "Modified (comment): / 31-08-2017 / 13:58:03 / cg"
       
  7641 !
       
  7642 
       
  7643 doBrightenImage
       
  7644     imageEditView brightenImage.
       
  7645     self listOfColors removeAll.
       
  7646     self findColorMapMode.     
       
  7647     "/ imageEditView removelastUndo
       
  7648 !
       
  7649 
       
  7650 doBrowseClass
       
  7651     "opens a System Browser on the resourceClass and the resourceSelector"
       
  7652 
       
  7653     |cls|
       
  7654 
       
  7655     cls := imageEditView resourceClass.
       
  7656     cls isNil ifTrue:[^ self warn:'No Class specified'].
       
  7657 
       
  7658     cls browserClass
       
  7659         openInClass:cls class 
       
  7660         selector:(imageEditView resourceSelector)
       
  7661 
       
  7662     "Modified: / 31.7.1998 / 02:01:15 / cg"
       
  7663 !
       
  7664 
       
  7665 doCopyImageToClipboard
       
  7666     imageEditView copyImageToClipboard.
       
  7667 !
       
  7668 
       
  7669 doCropManual
       
  7670     "let user specify borders and cut them off"
       
  7671 
       
  7672     |bindings left top right bottom img firstChange cropAction acceptChannel|
       
  7673 
       
  7674     acceptChannel := TriggerValue new.
       
  7675 
       
  7676     firstChange := true.
       
  7677 
       
  7678     cropAction := 
       
  7679         [:lV :rV :tV :bV | |l r t b|
       
  7680             acceptChannel value:true.
       
  7681 
       
  7682             l := lV value.
       
  7683             r := rV value.
       
  7684             t := tV value.
       
  7685             b := bV value.
       
  7686             (l + r + t + b) == 0 ifTrue:[
       
  7687                 UserPreferences current beepInEditor ifTrue:[                
       
  7688                     self window beep
       
  7689                 ]
       
  7690             ] ifFalse:[
       
  7691                 img := imageEditView image.
       
  7692                 firstChange ifTrue:[
       
  7693                     imageEditView makeUndo.
       
  7694                     firstChange := false.
       
  7695                 ].
       
  7696                 imageEditView
       
  7697                     makeSubImageX:l y:t 
       
  7698                     width:(img width - l - r)
       
  7699                     height:(img height - t - b).
       
  7700 
       
  7701                 self updateImagePreView.
       
  7702                 self updateInfoLabel
       
  7703             ].
       
  7704         ].
       
  7705 
       
  7706     bindings := IdentityDictionary new.
       
  7707     bindings at:#cropLeftAmount put:(left := 1 asValue).
       
  7708     bindings at:#cropRightAmount put:(right := 1 asValue).
       
  7709     bindings at:#cropTopAmount put:(top := 1 asValue).
       
  7710     bindings at:#cropBottomAmount put:(bottom := 1 asValue).
       
  7711     bindings at:#acceptChannel put:acceptChannel.
       
  7712 
       
  7713     bindings at:#cropLeftNow   put:[ cropAction value:left value:0 value:0 value:0 ].
       
  7714     bindings at:#cropRightNow  put:[ cropAction value:0 value:right value:0 value:0 ].
       
  7715     bindings at:#cropTopNow    put:[ cropAction value:0 value:0 value:top value:0 ].
       
  7716     bindings at:#cropBottomNow put:[ cropAction value:0 value:0 value:0 value:bottom ].
       
  7717 
       
  7718     bindings at:#applyCropAction   put:[ cropAction value:left value:right value:top value:bottom ].
       
  7719     bindings at:#cropBoxIsDialog   put:true.
       
  7720     
       
  7721     (self openDialogInterface:#cropSpec withBindings:bindings) 
       
  7722     ifFalse:[ 
       
  7723         firstChange ~~ true ifTrue:[
       
  7724             imageEditView undo.
       
  7725             self updateImagePreView.
       
  7726         ]
       
  7727     ].
       
  7728 
       
  7729     "Created: / 07-09-1998 / 18:16:07 / cg"
       
  7730     "Modified: / 19-02-2017 / 15:43:50 / cg"
       
  7731 !
       
  7732 
       
  7733 doDarkenImage
       
  7734     imageEditView darkenImage.
       
  7735     self listOfColors removeAll.
       
  7736     self findColorMapMode.     
       
  7737     "/ imageEditView removelastUndo
       
  7738 !
       
  7739 
       
  7740 doEditMask
       
  7741     |mask|
       
  7742 
       
  7743     (mask := self image mask) notNil ifTrue:[
       
  7744         mask edit
       
  7745     ].
       
  7746 
       
  7747     "Modified: / 18-02-2017 / 00:38:51 / cg"
       
  7748 !
       
  7749 
       
  7750 doFlipHorizontal
       
  7751     "flips horizontally current image"
       
  7752 
       
  7753     imageEditView flipHorizontal
       
  7754 !
       
  7755 
       
  7756 doFlipVertical
       
  7757     "flips vertically current image"
       
  7758 
       
  7759     imageEditView flipVertical
       
  7760 !
       
  7761 
       
  7762 doInsertTextFromUser
       
  7763     |text tempForm tempImage maskImage font w h paintColor|
       
  7764 
       
  7765     text := Dialog request:'Text to be inserted (placed as bitmap into clipboard for paste):'.
       
  7766     text isEmptyOrNil ifTrue:[^ self ].
       
  7767 
       
  7768     font := Font family:'arial' size:20.
       
  7769     font := font onDevice:Screen current.
       
  7770     w := font widthOf:text.
       
  7771     h := font heightOf:text.
       
  7772 
       
  7773     tempForm := Form extent:(w@h) depth:1 onDevice:(Screen current).
       
  7774     tempForm clear.
       
  7775     tempForm font:font.
       
  7776     tempForm paint:(Color colorId:1).
       
  7777     tempForm displayString:text at:(0@font ascent).
       
  7778 
       
  7779     tempImage := tempForm asImage.
       
  7780     maskImage := tempForm asImage.
       
  7781 
       
  7782     paintColor := imageEditView selectedColor.
       
  7783     paintColor  colorId == 0 ifTrue:[
       
  7784         paintColor := Color black
       
  7785     ].
       
  7786     tempImage   
       
  7787         photometric:#palette;
       
  7788         colorMap:(Array 
       
  7789                     with:Color white 
       
  7790                     with:paintColor);
       
  7791         mask:maskImage.
       
  7792 
       
  7793     ImageEditView copyImageToClipboard:tempImage.
       
  7794     self editMode value:#paste.
       
  7795 
       
  7796     "Modified: / 11-11-2007 / 12:32:55 / cg"
       
  7797 !
       
  7798 
       
  7799 doInspectImage
       
  7800     "opens a System Browser on the resourceClass and the resourceSelector"
       
  7801 
       
  7802     self image inspect
       
  7803 !
       
  7804 
       
  7805 doInvertedBitsImage
       
  7806     "inverts the pixels"
       
  7807 
       
  7808     self withExecuteCursorDo:[
       
  7809         imageEditView makeInvertedBits.
       
  7810         self updateImage.
       
  7811     ].
       
  7812 "/
       
  7813 "/    imageEditView negativeImage.
       
  7814 "/    self listOfColors removeAll.
       
  7815 "/    self findColorMapMode.     
       
  7816 "/    "/ imageEditView removelastUndo
       
  7817 "/
       
  7818 "/
       
  7819 
       
  7820     "Created: / 31-08-2017 / 12:49:13 / cg"
       
  7821 !
       
  7822 
       
  7823 doMagnifyDown
       
  7824     "magnifies the current image one step down"
       
  7825 
       
  7826     |magHolder mag|
       
  7827 
       
  7828     magHolder := self magnificationHolder.
       
  7829     (mag := magHolder value) > 1 ifTrue: [
       
  7830         magHolder value: mag - 1
       
  7831     ]
       
  7832 
       
  7833     "Modified: / 26.7.1998 / 20:24:08 / cg"
       
  7834 !
       
  7835 
       
  7836 doMagnifyImage
       
  7837     "magnifies the current image to a new size"
       
  7838 
       
  7839     |box newSize image antiAliased|
       
  7840 
       
  7841     antiAliased := false asValue.
       
  7842     image := imageEditView image.
       
  7843 
       
  7844     box := EnterBox new.
       
  7845     box title:(resources string:'Images new size:').
       
  7846     box okText:(resources string:'OK').
       
  7847     box abortText:(resources string:'Cancel').
       
  7848     box initialText:image extent printString.
       
  7849     box verticalPanel add:(CheckBox label:(resources string:'Antialias/Smooth') model:antiAliased).
       
  7850     box showAtPointer.
       
  7851     
       
  7852     (box accepted 
       
  7853     and: [(newSize := self pointFromString:(box contents)) notNil])
       
  7854     ifTrue:[
       
  7855         newSize isPoint ifFalse:[
       
  7856             self warn:'Please enter the new size as ''x @ y''.'.
       
  7857             ^ self.    
       
  7858         ].
       
  7859         antiAliased value ifTrue:[
       
  7860             ((newSize x < image width) or:[(newSize y < image height)]) ifTrue:[
       
  7861                 imageEditView magnifySmoothingTo:newSize.    
       
  7862             ] ifFalse:[    
       
  7863                 imageEditView magnifyAntiAliasedImageTo:newSize.
       
  7864             ].
       
  7865         ] ifFalse:[
       
  7866             imageEditView magnifyImageTo:newSize.
       
  7867         ].
       
  7868     ].
       
  7869 
       
  7870     self updateInfoLabel
       
  7871 
       
  7872     "Modified: / 30-08-2017 / 15:46:02 / cg"
       
  7873 !
       
  7874 
       
  7875 doMagnifyImageBy
       
  7876     "magnifies the current image (by a scale)"
       
  7877 
       
  7878     |oldSize newSize scaleString scale image antiAliased smoothing|
       
  7879 
       
  7880     image := imageEditView image.
       
  7881     oldSize := image extent.
       
  7882 
       
  7883     antiAliased := false asValue.
       
  7884     smoothing := false asValue.
       
  7885     
       
  7886     Dialog modifyingBoxWith:[:box |
       
  7887         box verticalPanel add:(CheckBox label:(resources string:'Antialias/Smooth') model:antiAliased).
       
  7888         "/ box verticalPanel add:(CheckBox label:(resources string:'Smoothing') model:smoothing).
       
  7889     ] do:[
       
  7890         scaleString := Dialog 
       
  7891                    request:(resources string:'Scale factor (<1 to shrink; >1 to magnify):') 
       
  7892                    initialAnswer:'1'
       
  7893                    list:#('0.1' '0.25' '0.3' '0.5' '1.5' '2' '3' '4').     
       
  7894     ].
       
  7895     scaleString isNil ifTrue:[^ self].
       
  7896 
       
  7897     scale := Object readFromString:scaleString onError:nil.
       
  7898 
       
  7899     scale notNil ifTrue:[
       
  7900         scale isNumber ifFalse:[
       
  7901             self warn:'please enter a scale factor (<1 to shrink; >1 to magnify).'.
       
  7902             ^ self.    
       
  7903         ].
       
  7904         newSize := oldSize * scale.
       
  7905         antiAliased value ifTrue:[
       
  7906             scale < 1 ifTrue:[
       
  7907                 imageEditView magnifySmoothingBy:scale.
       
  7908             ] ifFalse:[    
       
  7909                 imageEditView magnifyAntiAliasedImageTo:newSize.
       
  7910             ].
       
  7911         ] ifFalse:[
       
  7912             imageEditView magnifyImageTo:newSize.
       
  7913         ].
       
  7914     ].
       
  7915 
       
  7916     self updateInfoLabel
       
  7917 
       
  7918     "Modified: / 30-08-2017 / 15:34:56 / cg"
       
  7919 !
       
  7920 
       
  7921 doMagnifyUp
       
  7922     "magnifies the current image one step up"
       
  7923 
       
  7924     |magHolder mag|
       
  7925 
       
  7926     magHolder := self magnificationHolder.
       
  7927     (mag := magHolder value) < 63 ifTrue: [
       
  7928         magHolder value: mag + 1
       
  7929     ]
       
  7930 
       
  7931     "Modified: / 26.7.1998 / 20:23:52 / cg"
       
  7932 !
       
  7933 
       
  7934 doNegativeImage
       
  7935     "negates current image by negating the color map"
       
  7936 
       
  7937     self withExecuteCursorDo:[
       
  7938         imageEditView negativeImage.
       
  7939         self updateImage.
       
  7940     ].
       
  7941 "/
       
  7942 "/    imageEditView negativeImage.
       
  7943 "/    self listOfColors removeAll.
       
  7944 "/    self findColorMapMode.     
       
  7945 "/    "/ imageEditView removelastUndo
       
  7946 "/
       
  7947 "/
       
  7948 
       
  7949     "Modified: / 31-08-2017 / 12:44:25 / cg"
       
  7950 !
       
  7951 
       
  7952 doResizeImage
       
  7953     "resizes the current image"
       
  7954 
       
  7955     |box newSize image|
       
  7956 
       
  7957     image := imageEditView image.
       
  7958 
       
  7959     box := EnterBox new.
       
  7960     box title:(resources string:'Images new size:').
       
  7961     box okText:(resources string:'OK').
       
  7962     box abortText:(resources string:'Cancel').
       
  7963     box initialText:image extent printString.
       
  7964     box showAtPointer.
       
  7965     (box accepted 
       
  7966     and: [(newSize := self pointFromString:(box contents)) notNil])
       
  7967     ifTrue:[
       
  7968         imageEditView resizeImageTo:newSize.
       
  7969     ].
       
  7970 !
       
  7971 
       
  7972 doRotateImage
       
  7973     "rotates current image"
       
  7974 
       
  7975     |rotationString box rotation|
       
  7976 
       
  7977     rotationString := Dialog 
       
  7978                         request:(resources string:'Rotate by (degrees, clockwise):')
       
  7979                         list:#( '-90' '90' '180' '45' '-45'  '135' '-135' ) 
       
  7980                         initialAnswer:90.
       
  7981     rotationString isEmptyOrNil ifTrue:[^ self].    "/ canceled
       
  7982     rotation := Number readFrom:rotationString onError:[nil].
       
  7983     rotation isNil ifTrue:[^ self].   
       
  7984 
       
  7985 "/    box := EnterBox new.
       
  7986 "/    box title:(resources string:'Rotate by (degrees, clockwise):').
       
  7987 "/    box okText:(resources string:'OK').
       
  7988 "/    box abortText:(resources string:'Cancel').
       
  7989 "/    box initialText: '0'.
       
  7990 "/    box showAtPointer.
       
  7991 "/    (box accepted and: [(rotation := Number readFromString: box contents onError:nil) notNil])
       
  7992 "/    ifFalse:[ ^ self ].
       
  7993 
       
  7994     imageEditView rotateImageBy:rotation.
       
  7995     self updateInfoLabel.
       
  7996 
       
  7997     "Modified: / 18-03-2012 / 14:41:14 / cg"
       
  7998     "Modified (comment): / 24-08-2017 / 15:02:57 / cg"
       
  7999 !
       
  8000 
       
  8001 doShiftManual
       
  8002     "let user specify amount and shift"
       
  8003 
       
  8004     |bindings amount img firstChange shiftAction acceptChannel wrapHolder|
       
  8005 
       
  8006     acceptChannel := TriggerValue new.
       
  8007     wrapHolder := (lastShiftUsedWrap ? true) asValue.
       
  8008 
       
  8009     firstChange := true.
       
  8010 
       
  8011     shiftAction := 
       
  8012         [:shiftH :shiftV | 
       
  8013             acceptChannel value:true.
       
  8014 
       
  8015             img := imageEditView image.
       
  8016             firstChange ifTrue:[
       
  8017                 imageEditView makeUndo.
       
  8018                 firstChange := false.
       
  8019             ].
       
  8020             imageEditView shiftImageHorizontal:(shiftH value) vertical:(shiftV value) wrap:(wrapHolder value).
       
  8021             self updateInfoLabel
       
  8022         ].
       
  8023 
       
  8024     bindings := IdentityDictionary new.
       
  8025     bindings at:#shiftAmount put:(amount := 1 asValue).
       
  8026     bindings at:#wrap put:wrapHolder.
       
  8027     bindings at:#acceptChannel put:acceptChannel.
       
  8028 
       
  8029     bindings at:#shiftLeftNow   put:[ shiftAction value:(-1*amount value) value:0 ].
       
  8030     bindings at:#shiftRightNow  put:[ shiftAction value:amount value value:0 ].
       
  8031     bindings at:#shiftUpNow     put:[ shiftAction value:0 value:(-1*amount value) ].
       
  8032     bindings at:#shiftDownNow   put:[ shiftAction value:0 value:amount value ].
       
  8033 
       
  8034     (self openDialogInterface:#shiftDialogSpec withBindings:bindings) 
       
  8035     ifFalse:[ 
       
  8036         firstChange ~~ true ifTrue:[
       
  8037           imageEditView undo
       
  8038         ]
       
  8039     ].
       
  8040     lastShiftUsedWrap := wrapHolder value.
       
  8041 
       
  8042     "Created: / 7.9.1998 / 18:16:07 / cg"
       
  8043     "Modified: / 7.9.1998 / 18:20:42 / cg"
       
  8044 !
       
  8045 
       
  8046 doUnCropManual
       
  8047     "let user specify borders and add them"
       
  8048 
       
  8049     |bindings leftAmount topAmount rightAmount bottomAmount img|
       
  8050 
       
  8051     bindings := IdentityDictionary new.
       
  8052     bindings at:#cropLeftAmount put:(leftAmount := 1 asValue).
       
  8053     bindings at:#cropRightAmount put:(rightAmount := 1 asValue).
       
  8054     bindings at:#cropTopAmount put:(topAmount := 1 asValue).
       
  8055     bindings at:#cropBottomAmount  put:(bottomAmount := 1 asValue).
       
  8056     bindings at:#cropBoxIsDialog   put:true.
       
  8057 
       
  8058     (self openDialogInterface:#uncropSpec withBindings:bindings)
       
  8059     ifTrue:[
       
  8060         leftAmount := leftAmount value.
       
  8061         rightAmount := rightAmount value.
       
  8062         topAmount := topAmount value.
       
  8063         bottomAmount := bottomAmount value.
       
  8064         img := imageEditView image.
       
  8065 
       
  8066         imageEditView
       
  8067             makeBorderedImageX:leftAmount y:topAmount 
       
  8068             width:(img width + leftAmount + rightAmount)
       
  8069             height:(img height + topAmount + bottomAmount).
       
  8070         self updateInfoLabel
       
  8071     ].
       
  8072 
       
  8073     "Created: / 07-09-1998 / 18:16:07 / cg"
       
  8074     "Modified: / 19-02-2017 / 15:31:00 / cg"
       
  8075 !
       
  8076 
       
  8077 doUndo
       
  8078     "reverses last edit action"
       
  8079 
       
  8080     imageEditView undo.
       
  8081     self updateImagePreView
       
  8082 !
       
  8083 
       
  8084 makeInverse
       
  8085     "inverts the pixels - for palettes, this leads to funny results"
       
  8086 
       
  8087     self updateImageAfterDoing:#makeInverse.
       
  8088 
       
  8089     "Modified: / 31-08-2017 / 12:16:07 / cg"
       
  8090     "Modified (comment): / 31-08-2017 / 13:51:28 / cg"
       
  8091 !
       
  8092 
       
  8093 makeMonochromeImage
       
  8094     "let user choose a threshold, then convert to monochrome"
       
  8095     
       
  8096     |image userInput thresholdBrighness|
       
  8097 
       
  8098     image := imageEditView image.
       
  8099     
       
  8100     Dialog modifyingBoxWith:[:box |
       
  8101         |preview slider update thresholdValue|
       
  8102 
       
  8103         thresholdValue := 0.5 asValue.
       
  8104 
       
  8105         box enterField 
       
  8106             converter:(PrintConverter new initForNumber);
       
  8107             model:thresholdValue.
       
  8108             
       
  8109         box verticalPanel extent:1.0 @ 300.
       
  8110         
       
  8111         box verticalPanel add:(slider := HorizontalSlider new start:0 stop:1 step:0.05).
       
  8112         slider model:thresholdValue.
       
  8113         slider width:1.0; leftInset:4; rightInset:4.
       
  8114 
       
  8115         box verticalPanel add:(preview := ImageView new).
       
  8116         preview extent:300 @300.
       
  8117         preview level:-1.
       
  8118         box verticalPanel horizontalLayout:#fitSpace.
       
  8119         
       
  8120         update := 
       
  8121             [
       
  8122                 |s t|
       
  8123 
       
  8124                 t := thresholdValue value clampBetween:0 and:1.   
       
  8125                 preview image:((image asThresholdMonochromeImage:t)
       
  8126                             magnifiedPreservingRatioTo:preview extent).
       
  8127             ].
       
  8128         update value.
       
  8129         box enterField acceptOnLostFocus:true.
       
  8130         box enterField acceptOnLeave:true.
       
  8131         thresholdValue onChangeEvaluate:update.
       
  8132 
       
  8133     ] do:[
       
  8134         userInput := Dialog request:'Threshold (0=black; 1=white) ?' initialAnswer:0.5.
       
  8135     ].
       
  8136     userInput isEmptyOrNil ifTrue:[^ self].
       
  8137     thresholdBrighness := Number readFrom:userInput onError:nil.
       
  8138     thresholdBrighness isNil ifTrue:[^ self].
       
  8139 
       
  8140     thresholdBrighness := thresholdBrighness clampBetween:0 and:1.
       
  8141     imageEditView newImageWithUndo:(image asThresholdMonochromeImage:thresholdBrighness)
       
  8142 
       
  8143     "Created: / 24-08-2017 / 15:26:44 / cg"
       
  8144     "Modified: / 24-08-2017 / 17:54:21 / cg"
       
  8145 !
       
  8146 
       
  8147 makeNegative
       
  8148     "negates current image by negating the color map"
       
  8149 
       
  8150     self withExecuteCursorDo:[
       
  8151         imageEditView negativeImage.
       
  8152         self updateImage.
       
  8153     ].
       
  8154 "/
       
  8155 "/    imageEditView negativeImage.
       
  8156 "/    self listOfColors removeAll.
       
  8157 "/    self findColorMapMode.     
       
  8158 "/    "/ imageEditView removelastUndo
       
  8159 "/
       
  8160 "/
       
  8161 
       
  8162     "Created: / 31-08-2017 / 13:49:47 / cg"
       
  8163 !
       
  8164 
       
  8165 thresholdGrayToDepth
       
  8166     self askForDepthThenDo:[:depth |
       
  8167         self thresholdGrayToDepth:depth
       
  8168     ].
       
  8169 
       
  8170     "Created: / 24-08-2017 / 17:49:23 / cg"
       
  8171 !
       
  8172 
       
  8173 thresholdGrayToDepth:depth
       
  8174     self withExecuteCursorDo:[
       
  8175         |newImage|
       
  8176 
       
  8177         newImage := self image asThresholdGrayImageDepth:depth.
       
  8178         imageEditView newImageWithUndo:newImage.
       
  8179     ].
       
  8180 
       
  8181     "Created: / 24-08-2017 / 17:49:30 / cg"
       
  8182 !
       
  8183 
       
  8184 thresholdToDepth
       
  8185     self askForDepthThenDo:[:depth |
       
  8186         self convertToDepth:depth dither:false
       
  8187     ].
       
  8188 
       
  8189     "Created: / 30-08-2017 / 00:31:33 / cg"
       
  8190 ! !
       
  8191 
       
  8192 !ImageEditor methodsFor:'user actions-editing-colors'!
  7426 
  8193 
  7427 convertToDepth:depth dither:doDither
  8194 convertToDepth:depth dither:doDither
  7428     |answer labels values 
  8195     |answer labels values 
  7429      ditherColors fixColors
  8196      ditherColors fixColors
  7430      nGrey greyColorsAlready moreColors d|
  8197      nGrey greyColorsAlready moreColors d|
  7586 
  8353 
  7587     "Created: / 30-08-2017 / 00:33:55 / cg"
  8354     "Created: / 30-08-2017 / 00:33:55 / cg"
  7588     "Modified: / 30-08-2017 / 02:13:03 / cg"
  8355     "Modified: / 30-08-2017 / 02:13:03 / cg"
  7589 !
  8356 !
  7590 
  8357 
  7591 ditherGrayToDepth
  8358 makeInvertedBits
  7592     self askForDepthThenDo:[:depth |
  8359     "inverts the pixels - for palettes, this leads to funny results.
  7593         self ditherGrayToDepth:depth
  8360      For others, this is the same as negating"
  7594     ].
  8361 
  7595 
  8362     self updateImageAfterDoing:#makeInvertedBits.
  7596     "Created: / 24-08-2017 / 17:49:42 / cg"
  8363 
  7597 !
  8364     "Created: / 31-08-2017 / 13:51:10 / cg"
  7598 
       
  7599 ditherGrayToDepth:depth
       
  7600     self withExecuteCursorDo:[
       
  7601         |newImage|
       
  7602 
       
  7603         depth == 1 ifTrue:[
       
  7604             newImage := self image asErrorDitheredMonochromeImage
       
  7605         ] ifFalse:[
       
  7606             newImage := self image asGrayImageDepth:depth dither:#floydSteinberg.
       
  7607         ].
       
  7608         imageEditView newImageWithUndo:newImage.
       
  7609     ].
       
  7610 
       
  7611     "Created: / 24-08-2017 / 17:51:07 / cg"
       
  7612     "Modified: / 30-08-2017 / 01:18:43 / cg"
       
  7613 !
       
  7614 
       
  7615 ditherToDepth
       
  7616     self askForDepthThenDo:[:depth |
       
  7617         self convertToDepth:depth dither:true
       
  7618     ].
       
  7619 
       
  7620     "Created: / 07-07-2006 / 13:22:10 / cg"
       
  7621     "Modified: / 30-08-2017 / 00:34:42 / cg"
       
  7622 !
       
  7623 
       
  7624 do3DProjection
       
  7625     |box dx1 dx2 image|
       
  7626 
       
  7627     image := imageEditView image.
       
  7628 
       
  7629     box := EnterBox new.
       
  7630     box title:(resources string:'dX1 (0 < dx < 0.5):').
       
  7631     box okText:(resources string:'OK').
       
  7632     box abortText:(resources string:'Cancel').
       
  7633     box initialText:'0.1'.
       
  7634     box showAtPointer.
       
  7635 
       
  7636     (box accepted 
       
  7637     and: [(dx1 := Number readFrom:(box contents) onError:nil) notNil])
       
  7638     ifTrue:[
       
  7639         box title:(resources string:'dX2 (0 < dx < 0.5):').
       
  7640         box initialText:(dx1 printString).
       
  7641         box showAtPointer.
       
  7642         (box accepted 
       
  7643         and: [(dx2 := Number readFrom:(box contents) onError:nil) notNil])
       
  7644         ifTrue:[
       
  7645             imageEditView threeDProjection:dx1 and:dx2.
       
  7646         ]
       
  7647     ].
       
  7648 
       
  7649     self updateInfoLabel
       
  7650 !
       
  7651 
       
  7652 doBrightenImage
       
  7653     imageEditView brightenImage.
       
  7654     self listOfColors removeAll.
       
  7655     self findColorMapMode.     
       
  7656     "/ imageEditView removelastUndo
       
  7657 !
       
  7658 
       
  7659 doBrowseClass
       
  7660     "opens a System Browser on the resourceClass and the resourceSelector"
       
  7661 
       
  7662     |cls|
       
  7663 
       
  7664     cls := imageEditView resourceClass.
       
  7665     cls isNil ifTrue:[^ self warn:'No Class specified'].
       
  7666 
       
  7667     cls browserClass
       
  7668         openInClass:cls class 
       
  7669         selector:(imageEditView resourceSelector)
       
  7670 
       
  7671     "Modified: / 31.7.1998 / 02:01:15 / cg"
       
  7672 !
       
  7673 
       
  7674 doCopyImageToClipboard
       
  7675     imageEditView copyImageToClipboard.
       
  7676 !
       
  7677 
       
  7678 doCropManual
       
  7679     "let user specify borders and cut them off"
       
  7680 
       
  7681     |bindings left top right bottom img firstChange cropAction acceptChannel|
       
  7682 
       
  7683     acceptChannel := TriggerValue new.
       
  7684 
       
  7685     firstChange := true.
       
  7686 
       
  7687     cropAction := 
       
  7688         [:lV :rV :tV :bV | |l r t b|
       
  7689             acceptChannel value:true.
       
  7690 
       
  7691             l := lV value.
       
  7692             r := rV value.
       
  7693             t := tV value.
       
  7694             b := bV value.
       
  7695             (l + r + t + b) == 0 ifTrue:[
       
  7696                 UserPreferences current beepInEditor ifTrue:[                
       
  7697                     self window beep
       
  7698                 ]
       
  7699             ] ifFalse:[
       
  7700                 img := imageEditView image.
       
  7701                 firstChange ifTrue:[
       
  7702                     imageEditView makeUndo.
       
  7703                     firstChange := false.
       
  7704                 ].
       
  7705                 imageEditView
       
  7706                     makeSubImageX:l y:t 
       
  7707                     width:(img width - l - r)
       
  7708                     height:(img height - t - b).
       
  7709 
       
  7710                 self updateImagePreView.
       
  7711                 self updateInfoLabel
       
  7712             ].
       
  7713         ].
       
  7714 
       
  7715     bindings := IdentityDictionary new.
       
  7716     bindings at:#cropLeftAmount put:(left := 1 asValue).
       
  7717     bindings at:#cropRightAmount put:(right := 1 asValue).
       
  7718     bindings at:#cropTopAmount put:(top := 1 asValue).
       
  7719     bindings at:#cropBottomAmount put:(bottom := 1 asValue).
       
  7720     bindings at:#acceptChannel put:acceptChannel.
       
  7721 
       
  7722     bindings at:#cropLeftNow   put:[ cropAction value:left value:0 value:0 value:0 ].
       
  7723     bindings at:#cropRightNow  put:[ cropAction value:0 value:right value:0 value:0 ].
       
  7724     bindings at:#cropTopNow    put:[ cropAction value:0 value:0 value:top value:0 ].
       
  7725     bindings at:#cropBottomNow put:[ cropAction value:0 value:0 value:0 value:bottom ].
       
  7726 
       
  7727     bindings at:#applyCropAction   put:[ cropAction value:left value:right value:top value:bottom ].
       
  7728     bindings at:#cropBoxIsDialog   put:true.
       
  7729     
       
  7730     (self openDialogInterface:#cropSpec withBindings:bindings) 
       
  7731     ifFalse:[ 
       
  7732         firstChange ~~ true ifTrue:[
       
  7733             imageEditView undo.
       
  7734             self updateImagePreView.
       
  7735         ]
       
  7736     ].
       
  7737 
       
  7738     "Created: / 07-09-1998 / 18:16:07 / cg"
       
  7739     "Modified: / 19-02-2017 / 15:43:50 / cg"
       
  7740 !
       
  7741 
       
  7742 doDarkenImage
       
  7743     imageEditView darkenImage.
       
  7744     self listOfColors removeAll.
       
  7745     self findColorMapMode.     
       
  7746     "/ imageEditView removelastUndo
       
  7747 !
       
  7748 
       
  7749 doEditMask
       
  7750     |mask|
       
  7751 
       
  7752     (mask := self image mask) notNil ifTrue:[
       
  7753         mask edit
       
  7754     ].
       
  7755 
       
  7756     "Modified: / 18-02-2017 / 00:38:51 / cg"
       
  7757 !
       
  7758 
       
  7759 doFlipHorizontal
       
  7760     "flips horizontally current image"
       
  7761 
       
  7762     imageEditView flipHorizontal
       
  7763 !
       
  7764 
       
  7765 doFlipVertical
       
  7766     "flips vertically current image"
       
  7767 
       
  7768     imageEditView flipVertical
       
  7769 !
       
  7770 
       
  7771 doInsertTextFromUser
       
  7772     |text tempForm tempImage maskImage font w h paintColor|
       
  7773 
       
  7774     text := Dialog request:'Text to be inserted (placed as bitmap into clipboard for paste):'.
       
  7775     text isEmptyOrNil ifTrue:[^ self ].
       
  7776 
       
  7777     font := Font family:'arial' size:20.
       
  7778     font := font onDevice:Screen current.
       
  7779     w := font widthOf:text.
       
  7780     h := font heightOf:text.
       
  7781 
       
  7782     tempForm := Form extent:(w@h) depth:1 onDevice:(Screen current).
       
  7783     tempForm clear.
       
  7784     tempForm font:font.
       
  7785     tempForm paint:(Color colorId:1).
       
  7786     tempForm displayString:text at:(0@font ascent).
       
  7787 
       
  7788     tempImage := tempForm asImage.
       
  7789     maskImage := tempForm asImage.
       
  7790 
       
  7791     paintColor := imageEditView selectedColor.
       
  7792     paintColor  colorId == 0 ifTrue:[
       
  7793         paintColor := Color black
       
  7794     ].
       
  7795     tempImage   
       
  7796         photometric:#palette;
       
  7797         colorMap:(Array 
       
  7798                     with:Color white 
       
  7799                     with:paintColor);
       
  7800         mask:maskImage.
       
  7801 
       
  7802     ImageEditView copyImageToClipboard:tempImage.
       
  7803     self editMode value:#paste.
       
  7804 
       
  7805     "Modified: / 11-11-2007 / 12:32:55 / cg"
       
  7806 !
       
  7807 
       
  7808 doInspectImage
       
  7809     "opens a System Browser on the resourceClass and the resourceSelector"
       
  7810 
       
  7811     self image inspect
       
  7812 !
       
  7813 
       
  7814 doMagnifyDown
       
  7815     "magnifies the current image one step down"
       
  7816 
       
  7817     |magHolder mag|
       
  7818 
       
  7819     magHolder := self magnificationHolder.
       
  7820     (mag := magHolder value) > 1 ifTrue: [
       
  7821         magHolder value: mag - 1
       
  7822     ]
       
  7823 
       
  7824     "Modified: / 26.7.1998 / 20:24:08 / cg"
       
  7825 !
       
  7826 
       
  7827 doMagnifyImage
       
  7828     "magnifies the current image to a new size"
       
  7829 
       
  7830     |box newSize image antiAliased|
       
  7831 
       
  7832     antiAliased := false asValue.
       
  7833     image := imageEditView image.
       
  7834 
       
  7835     box := EnterBox new.
       
  7836     box title:(resources string:'Images new size:').
       
  7837     box okText:(resources string:'OK').
       
  7838     box abortText:(resources string:'Cancel').
       
  7839     box initialText:image extent printString.
       
  7840     box verticalPanel add:(CheckBox label:(resources string:'Antialias/Smooth') model:antiAliased).
       
  7841     box showAtPointer.
       
  7842     
       
  7843     (box accepted 
       
  7844     and: [(newSize := self pointFromString:(box contents)) notNil])
       
  7845     ifTrue:[
       
  7846         newSize isPoint ifFalse:[
       
  7847             self warn:'Please enter the new size as ''x @ y''.'.
       
  7848             ^ self.    
       
  7849         ].
       
  7850         antiAliased value ifTrue:[
       
  7851             ((newSize x < image width) or:[(newSize y < image height)]) ifTrue:[
       
  7852                 imageEditView magnifySmoothingTo:newSize.    
       
  7853             ] ifFalse:[    
       
  7854                 imageEditView magnifyAntiAliasedImageTo:newSize.
       
  7855             ].
       
  7856         ] ifFalse:[
       
  7857             imageEditView magnifyImageTo:newSize.
       
  7858         ].
       
  7859     ].
       
  7860 
       
  7861     self updateInfoLabel
       
  7862 
       
  7863     "Modified: / 30-08-2017 / 15:46:02 / cg"
       
  7864 !
       
  7865 
       
  7866 doMagnifyImageBy
       
  7867     "magnifies the current image (by a scale)"
       
  7868 
       
  7869     |oldSize newSize scaleString scale image antiAliased smoothing|
       
  7870 
       
  7871     image := imageEditView image.
       
  7872     oldSize := image extent.
       
  7873 
       
  7874     antiAliased := false asValue.
       
  7875     smoothing := false asValue.
       
  7876     
       
  7877     Dialog modifyingBoxWith:[:box |
       
  7878         box verticalPanel add:(CheckBox label:(resources string:'Antialias/Smooth') model:antiAliased).
       
  7879         "/ box verticalPanel add:(CheckBox label:(resources string:'Smoothing') model:smoothing).
       
  7880     ] do:[
       
  7881         scaleString := Dialog 
       
  7882                    request:(resources string:'Scale factor (<1 to shrink; >1 to magnify):') 
       
  7883                    initialAnswer:'1'
       
  7884                    list:#('0.1' '0.25' '0.3' '0.5' '1.5' '2' '3' '4').     
       
  7885     ].
       
  7886     scaleString isNil ifTrue:[^ self].
       
  7887 
       
  7888     scale := Object readFromString:scaleString onError:nil.
       
  7889 
       
  7890     scale notNil ifTrue:[
       
  7891         scale isNumber ifFalse:[
       
  7892             self warn:'please enter a scale factor (<1 to shrink; >1 to magnify).'.
       
  7893             ^ self.    
       
  7894         ].
       
  7895         newSize := oldSize * scale.
       
  7896         antiAliased value ifTrue:[
       
  7897             scale < 1 ifTrue:[
       
  7898                 imageEditView magnifySmoothingBy:scale.
       
  7899             ] ifFalse:[    
       
  7900                 imageEditView magnifyAntiAliasedImageTo:newSize.
       
  7901             ].
       
  7902         ] ifFalse:[
       
  7903             imageEditView magnifyImageTo:newSize.
       
  7904         ].
       
  7905     ].
       
  7906 
       
  7907     self updateInfoLabel
       
  7908 
       
  7909     "Modified: / 30-08-2017 / 15:34:56 / cg"
       
  7910 !
       
  7911 
       
  7912 doMagnifyUp
       
  7913     "magnifies the current image one step up"
       
  7914 
       
  7915     |magHolder mag|
       
  7916 
       
  7917     magHolder := self magnificationHolder.
       
  7918     (mag := magHolder value) < 63 ifTrue: [
       
  7919         magHolder value: mag + 1
       
  7920     ]
       
  7921 
       
  7922     "Modified: / 26.7.1998 / 20:23:52 / cg"
       
  7923 !
       
  7924 
       
  7925 doNegativeImage
       
  7926     "negates current image by negating the color map"
       
  7927 
       
  7928     self image depth ~~ 1 ifTrue:[
       
  7929         Dialog warn:'Only useful for depth 1 images'.
       
  7930         ^ self
       
  7931     ].
       
  7932     imageEditView negativeImage.
       
  7933     self listOfColors removeAll.
       
  7934     self findColorMapMode.     
       
  7935     "/ imageEditView removelastUndo
       
  7936 !
       
  7937 
       
  7938 doResizeImage
       
  7939     "resizes the current image"
       
  7940 
       
  7941     |box newSize image|
       
  7942 
       
  7943     image := imageEditView image.
       
  7944 
       
  7945     box := EnterBox new.
       
  7946     box title:(resources string:'Images new size:').
       
  7947     box okText:(resources string:'OK').
       
  7948     box abortText:(resources string:'Cancel').
       
  7949     box initialText:image extent printString.
       
  7950     box showAtPointer.
       
  7951     (box accepted 
       
  7952     and: [(newSize := self pointFromString:(box contents)) notNil])
       
  7953     ifTrue:[
       
  7954         imageEditView resizeImageTo:newSize.
       
  7955     ].
       
  7956 !
       
  7957 
       
  7958 doRotateImage
       
  7959     "rotates current image"
       
  7960 
       
  7961     |rotationString box rotation|
       
  7962 
       
  7963     rotationString := Dialog 
       
  7964                         request:(resources string:'Rotate by (degrees, clockwise):')
       
  7965                         list:#( '-90' '90' '180' '45' '-45'  '135' '-135' ) 
       
  7966                         initialAnswer:90.
       
  7967     rotationString isEmptyOrNil ifTrue:[^ self].    "/ canceled
       
  7968     rotation := Number readFrom:rotationString onError:[nil].
       
  7969     rotation isNil ifTrue:[^ self].   
       
  7970 
       
  7971 "/    box := EnterBox new.
       
  7972 "/    box title:(resources string:'Rotate by (degrees, clockwise):').
       
  7973 "/    box okText:(resources string:'OK').
       
  7974 "/    box abortText:(resources string:'Cancel').
       
  7975 "/    box initialText: '0'.
       
  7976 "/    box showAtPointer.
       
  7977 "/    (box accepted and: [(rotation := Number readFromString: box contents onError:nil) notNil])
       
  7978 "/    ifFalse:[ ^ self ].
       
  7979 
       
  7980     imageEditView rotateImageBy:rotation.
       
  7981     self updateInfoLabel.
       
  7982 
       
  7983     "Modified: / 18-03-2012 / 14:41:14 / cg"
       
  7984     "Modified (comment): / 24-08-2017 / 15:02:57 / cg"
       
  7985 !
       
  7986 
       
  7987 doShiftManual
       
  7988     "let user specify amount and shift"
       
  7989 
       
  7990     |bindings amount img firstChange shiftAction acceptChannel wrapHolder|
       
  7991 
       
  7992     acceptChannel := TriggerValue new.
       
  7993     wrapHolder := (lastShiftUsedWrap ? true) asValue.
       
  7994 
       
  7995     firstChange := true.
       
  7996 
       
  7997     shiftAction := 
       
  7998         [:shiftH :shiftV | 
       
  7999             acceptChannel value:true.
       
  8000 
       
  8001             img := imageEditView image.
       
  8002             firstChange ifTrue:[
       
  8003                 imageEditView makeUndo.
       
  8004                 firstChange := false.
       
  8005             ].
       
  8006             imageEditView shiftImageHorizontal:(shiftH value) vertical:(shiftV value) wrap:(wrapHolder value).
       
  8007             self updateInfoLabel
       
  8008         ].
       
  8009 
       
  8010     bindings := IdentityDictionary new.
       
  8011     bindings at:#shiftAmount put:(amount := 1 asValue).
       
  8012     bindings at:#wrap put:wrapHolder.
       
  8013     bindings at:#acceptChannel put:acceptChannel.
       
  8014 
       
  8015     bindings at:#shiftLeftNow   put:[ shiftAction value:(-1*amount value) value:0 ].
       
  8016     bindings at:#shiftRightNow  put:[ shiftAction value:amount value value:0 ].
       
  8017     bindings at:#shiftUpNow     put:[ shiftAction value:0 value:(-1*amount value) ].
       
  8018     bindings at:#shiftDownNow   put:[ shiftAction value:0 value:amount value ].
       
  8019 
       
  8020     (self openDialogInterface:#shiftDialogSpec withBindings:bindings) 
       
  8021     ifFalse:[ 
       
  8022         firstChange ~~ true ifTrue:[
       
  8023           imageEditView undo
       
  8024         ]
       
  8025     ].
       
  8026     lastShiftUsedWrap := wrapHolder value.
       
  8027 
       
  8028     "Created: / 7.9.1998 / 18:16:07 / cg"
       
  8029     "Modified: / 7.9.1998 / 18:20:42 / cg"
       
  8030 !
       
  8031 
       
  8032 doUnCropManual
       
  8033     "let user specify borders and add them"
       
  8034 
       
  8035     |bindings leftAmount topAmount rightAmount bottomAmount img|
       
  8036 
       
  8037     bindings := IdentityDictionary new.
       
  8038     bindings at:#cropLeftAmount put:(leftAmount := 1 asValue).
       
  8039     bindings at:#cropRightAmount put:(rightAmount := 1 asValue).
       
  8040     bindings at:#cropTopAmount put:(topAmount := 1 asValue).
       
  8041     bindings at:#cropBottomAmount  put:(bottomAmount := 1 asValue).
       
  8042     bindings at:#cropBoxIsDialog   put:true.
       
  8043 
       
  8044     (self openDialogInterface:#uncropSpec withBindings:bindings)
       
  8045     ifTrue:[
       
  8046         leftAmount := leftAmount value.
       
  8047         rightAmount := rightAmount value.
       
  8048         topAmount := topAmount value.
       
  8049         bottomAmount := bottomAmount value.
       
  8050         img := imageEditView image.
       
  8051 
       
  8052         imageEditView
       
  8053             makeBorderedImageX:leftAmount y:topAmount 
       
  8054             width:(img width + leftAmount + rightAmount)
       
  8055             height:(img height + topAmount + bottomAmount).
       
  8056         self updateInfoLabel
       
  8057     ].
       
  8058 
       
  8059     "Created: / 07-09-1998 / 18:16:07 / cg"
       
  8060     "Modified: / 19-02-2017 / 15:31:00 / cg"
       
  8061 !
       
  8062 
       
  8063 doUndo
       
  8064     "reverses last edit action"
       
  8065 
       
  8066     imageEditView undo.
       
  8067     self updateImagePreView
       
  8068 !
       
  8069 
       
  8070 makeMonochromeImage
       
  8071     "let user choose a threshold, then convert to monochrome"
       
  8072     
       
  8073     |image userInput thresholdBrighness|
       
  8074 
       
  8075     image := imageEditView image.
       
  8076     
       
  8077     Dialog modifyingBoxWith:[:box |
       
  8078         |preview slider update thresholdValue|
       
  8079 
       
  8080         thresholdValue := 0.5 asValue.
       
  8081 
       
  8082         box enterField 
       
  8083             converter:(PrintConverter new initForNumber);
       
  8084             model:thresholdValue.
       
  8085             
       
  8086         box verticalPanel extent:1.0 @ 300.
       
  8087         
       
  8088         box verticalPanel add:(slider := HorizontalSlider new start:0 stop:1 step:0.05).
       
  8089         slider model:thresholdValue.
       
  8090         slider width:1.0; leftInset:4; rightInset:4.
       
  8091 
       
  8092         box verticalPanel add:(preview := ImageView new).
       
  8093         preview extent:300 @300.
       
  8094         preview level:-1.
       
  8095         box verticalPanel horizontalLayout:#fitSpace.
       
  8096         
       
  8097         update := 
       
  8098             [
       
  8099                 |s t|
       
  8100 
       
  8101                 t := thresholdValue value clampBetween:0 and:1.   
       
  8102                 preview image:((image asThresholdMonochromeImage:t)
       
  8103                             magnifiedPreservingRatioTo:preview extent).
       
  8104             ].
       
  8105         update value.
       
  8106         box enterField acceptOnLostFocus:true.
       
  8107         box enterField acceptOnLeave:true.
       
  8108         thresholdValue onChangeEvaluate:update.
       
  8109 
       
  8110     ] do:[
       
  8111         userInput := Dialog request:'Threshold (0=black; 1=white) ?' initialAnswer:0.5.
       
  8112     ].
       
  8113     userInput isEmptyOrNil ifTrue:[^ self].
       
  8114     thresholdBrighness := Number readFrom:userInput onError:nil.
       
  8115     thresholdBrighness isNil ifTrue:[^ self].
       
  8116 
       
  8117     thresholdBrighness := thresholdBrighness clampBetween:0 and:1.
       
  8118     imageEditView newImageWithUndo:(image asThresholdMonochromeImage:thresholdBrighness)
       
  8119 
       
  8120     "Created: / 24-08-2017 / 15:26:44 / cg"
       
  8121     "Modified: / 24-08-2017 / 17:54:21 / cg"
       
  8122 !
       
  8123 
       
  8124 thresholdGrayToDepth
       
  8125     self askForDepthThenDo:[:depth |
       
  8126         self thresholdGrayToDepth:depth
       
  8127     ].
       
  8128 
       
  8129     "Created: / 24-08-2017 / 17:49:23 / cg"
       
  8130 !
       
  8131 
       
  8132 thresholdGrayToDepth:depth
       
  8133     self withExecuteCursorDo:[
       
  8134         |newImage|
       
  8135 
       
  8136         newImage := self image asThresholdGrayImageDepth:depth.
       
  8137         imageEditView newImageWithUndo:newImage.
       
  8138     ].
       
  8139 
       
  8140     "Created: / 24-08-2017 / 17:49:30 / cg"
       
  8141 !
       
  8142 
       
  8143 thresholdToDepth
       
  8144     self askForDepthThenDo:[:depth |
       
  8145         self convertToDepth:depth dither:false
       
  8146     ].
       
  8147 
       
  8148     "Created: / 30-08-2017 / 00:31:33 / cg"
       
  8149 ! !
  8365 ! !
  8150 
  8366 
  8151 !ImageEditor methodsFor:'user actions-image sequences'!
  8367 !ImageEditor methodsFor:'user actions-image sequences'!
  8152 
  8368 
  8153 editEachImageFromSequence
  8369 editEachImageFromSequence