├── .gitattributes ├── LICENSE ├── README.md └── magick-slicer.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=lf 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 VoidVolker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MagickSlicer 2 | 3 | [![Join the chat at https://gitter.im/VoidVolker/MagickSlicer](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/VoidVolker/MagickSlicer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | DZI and custom map tiles generator. 6 | 7 | ## Dependencies 8 | * [ImageMagick](http://www.imagemagick.org/script/index.php) - convert, identify 9 | * Bash 10 | 11 | ## OS support 12 | * Linux 13 | * OSX 14 | 15 | ## Viewers support 16 | * [OpenSeadragon](https://github.com/openseadragon/openseadragon) 17 | 18 | ## Usage 19 | magick-slicer.sh [options] [-i] /source/image [[-o] result/dir] 20 | magick-slicer.sh /source/image [options] [result/dir] 21 | magick-slicer.sh /source/image [result/dir] [options] 22 | 23 | Use quotes for path or options with spaces. First unknown string interpreting as source image, if it not defined. Second unknown string is interpreting as result path, if it not defined. Also, for source and result you can use options `-i` and `-o`. As result you will get sliced image in default format (basic DZI). 24 | 25 | ### Example: 26 | 27 | ./magick-slicer.sh foo.jpg 28 | 29 | Result: 30 | 31 | ```html 32 | [file] foo.dzi 33 | [dir] foo_files 34 | [dir] 0 35 | [file] 0_0.jpg (1x1px) 36 | 1 37 | 0_0.jpg (1x1) 38 | 2 39 | 0_0.jpg (2x2) 40 | 3 41 | 0_0.jpg (4x4) 42 | ... 43 | 44 | 8 45 | 0_0.jpg (WxH) W<=256, H<=256 46 | 9 47 | 0_0.jpg (256x256) 48 | x_y.jpg (WxH) W<=256, H<=256 49 | 10 50 | 0_0.jpg 51 | 0_1.jpg 52 | 1_0.jpg 53 | 1_1.jpg 54 | ... 55 | x_y.jpg 56 | ... 57 | N (max zoom level) 58 | 0_0.jpg 59 | ... 60 | x_y.jpg 61 | ``` 62 | 63 | Example OSD render: 64 | 65 | ``` 66 | 67 | 68 | 69 | 86 | 87 | 88 |
89 | 96 | 97 | 98 | ``` 99 | 100 | --- 101 | 102 | ## Help options 103 | 104 | ### -?, --help [option] 105 | 106 | Show basic help or show help for selected option. 107 | 108 | Type: str 109 | 110 | ### -m, --man 111 | 112 | Show full help for all options. 113 | 114 | --- 115 | 116 | ## Options list 117 | 118 | ### [ -v, --verbose <level> ] 119 | 120 | User-selected verbosity levels: 121 | - 0 = none 122 | - 1 = warnings 123 | - 2 = warnings + info 124 | - 3 = warnings + info + debug 125 | 126 | ### [ -v0, -v1, -v2, -v3 ] 127 | 128 | Short commands for each verbosity level. 129 | 130 | Default: 0 131 | 132 | Type: int 133 | 134 | ### [ -i, --in <file_path> ] 135 | 136 | Input file to slice. 137 | 138 | Type: str 139 | 140 | ### [ -o, --out <directory_path> ] 141 | 142 | Output directory for result. 143 | 144 | Default: same as source 145 | 146 | Type: str 147 | 148 | ### [ -e, --extension <file_extesion> ] 149 | 150 | Set result files extension. 151 | 152 | Default: same as source 153 | 154 | Type: str 155 | 156 | ### [ -w, --width <tile_width> ] 157 | 158 | Set tile width. 159 | 160 | Default: 256 pixels or same as height, if height is present. 161 | 162 | Type: int 163 | 164 | ### [ -h, --height <tile_height> ] 165 | 166 | Set tile height 167 | 168 | Default: 256 pixels or same as width, if width is present. 169 | 170 | Type: int 171 | 172 | ### [ -s, --step <zoom_step_value> ] 173 | 174 | Zoom step value. Formula: 175 | 176 | `image_size[i+1] = image_size[i] * 100 / step` (1) 177 | 178 | ``` 179 | 200 -> 200% or 2x -> 100% * 100 / 200 = 50% 180 | 175 -> 175% or 1.75x -> 100% * 100 / 175 = 57.(142857)% 181 | 120 -> 120% or 1.2x -> 100% * 100 / 120 = 83.(3)% 182 | 300 -> 300% or 3x -> 100% * 100 / 300 = 33.(3)% 183 | 100 -> 100% or 1x (no resize) -> infinity loop. Don't use it. 184 | ``` 185 | 186 | Default: 200 187 | 188 | Type: int 189 | 190 | ### [ -p, --options 'imagemagick options string' ] 191 | 192 | Specifies additional imagemagick options for `convert`. 193 | 194 | Type: str 195 | 196 | ### [ -g, --gravity <type> ] 197 | 198 | Types: `NorthWest North NorthEast West Center East SouthWest South SouthEast` 199 | 200 | The direction you choose specifies where to position image, when it will be sliced. Use `-list gravity` to get a complete list of `-gravity` settings available in your ImageMagick installation. 201 | http://www.imagemagick.org/script/command-line-options.php#gravity 202 | 203 | Default: NorthWest 204 | 205 | Type: str 206 | 207 | ### [ -x, --extent ] 208 | 209 | Specifies the edge tiles size: cropped or extent them to full size and fill transparent color. 210 | 211 | Default: false 212 | 213 | Type: logic switch 214 | 215 | ### [ -d, --dzi ] 216 | 217 | Specifies output format. 218 | 219 | Default: true 220 | 221 | Type: logic switch 222 | 223 | ### [ -a, --slicea ] 224 | 225 | Type of slicing - slice A. Image scale starts from image size to down. Inverts option `--sliceb`. 226 | 227 | Default: true 228 | 229 | Type: logic switch 230 | 231 | ### [ -b, --sliceb ] 232 | 233 | Type of slicing - slice B. Image scale starts from tile size and grow up. Inverts option `--slicea`. 234 | 235 | Default: false 236 | 237 | Type: logic switch 238 | 239 | ### [ -c, --scaleover ] 240 | 241 | Create upscaled image for maximum zoom (last zoom be equal or grater, then image). 242 | ```` 243 | zoom[i-1]_size < source_image_size < zoom[i]_size 244 | ```` 245 | `zoom[i]_size` - this is upscaled image. 246 | 247 | Work only in slice B mode. In other cases ignored. 248 | 249 | Default: false 250 | 251 | Type: logic switch 252 | 253 | ### [ -r, --horizontal ] 254 | 255 | Tiles divide image on horizontal side without remains. On this side tiles will not be croped. 256 | 257 | Work only in slice B mode. In other cases ignored. 258 | 259 | ``` 260 | ___ ___ ___ _ _ 261 | | | | | ^ 262 | |___|___|___| Image 263 | |___|___|___| _v_ <- Not full tiles. 264 | |_._|_._|_._| <-- Transparent color (extent=true) or cropped (extent=false) 265 | ``` 266 | 267 | Default: true 268 | 269 | Type: logic switch 270 | 271 | ### [ -t, --vertical ] 272 | 273 | Tiles divide image on vertical side without remains. On this side tiles will not be croped. 274 | 275 | Work only in slice B mode. In other cases ignored. 276 | 277 | ``` 278 | |<-image->| 279 | ___ ___ _ _ _ _ 280 | | | | |.| ^ 281 | |___|___|_|_| _v_Tile 282 | | | | |.| 283 | |___|___|_|_| 284 | ^-- Transparent color (extent=true) or cropped (extent=false) 285 | ^--- Not full tiles 286 | ``` 287 | 288 | Default: false 289 | 290 | Type: logic switch 291 | 292 | -------------------------------------------------------------------------------- /magick-slicer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | version="0.004" 3 | date="05/08/2015" 4 | 5 | # ####### Options ####### # 6 | # resultExt='png' 7 | resultExt='' 8 | resizeFilter='' # http://www.imagemagick.org/Usage/filter/ 9 | # resultDir='./sliceResult' 10 | resultDir='' 11 | 12 | # Selector fo slicer: A or B 13 | scaleFromImage=true # Type of scaling: if true - scale calculates from image size to down (slicer A), if false - image scale starts from tile size and grow up (slicer B) 14 | gravity='NorthWest' # Image positioning (from this option depends, which tiles sides can be cropped, if it not full size). Choices include: 'NorthWest', 'North', 'NorthEast', 'West', 'Center', 'East', 'SouthWest', 'South', 'SouthEast'. Use -list gravity to get a complete list of -gravity settings available in your ImageMagick installation. 15 | extent=false # Extent option (false - tiles be cropped, true - will be added transparent color to get all tiles of full size) 16 | scale64=false 17 | zoomReverse=false # false: maxZoom=100%; true: minZoom=100% 18 | 19 | # Options only for slicerB 20 | scaleover=true # Maximum zoom: bigger or less then image. False - will not create upscaled image for maximum zoom; true - last zoom be equal or grater, then image. 21 | horizontal=true # Type of positioning of image: horizontal or vertical. 22 | 23 | # ####### Options end ####### # 24 | 25 | # ——————————————————————————————————————————————————————————————————————————————————— 26 | # ####### Variables ####### # 27 | imageSource='' 28 | tileW=256 29 | tileH=256 30 | step=200 31 | imageW='' 32 | imageH='' 33 | imOptions='' 34 | dziFormat=true 35 | verboseLevel=0 36 | overlap=0 # TODO: Overlap handling. 37 | # ——————————————————————————————————————————————————————————————————————————————————— 38 | # ####### Verbose functions ####### # 39 | # (0=none, 1=warnings, 2=warnings+info, 3=warning+info+debug) 40 | 41 | warnMsg(){ 42 | if [ $verboseLevel -ge 1 ] 43 | then 44 | echo $1 45 | fi 46 | } 47 | 48 | infoMsg(){ 49 | if [ $verboseLevel -ge 2 ] 50 | then 51 | echo $1 52 | fi 53 | } 54 | 55 | debugMsg(){ 56 | if [ $verboseLevel -ge 3 ] 57 | then 58 | echo $1 59 | fi 60 | } 61 | 62 | # ——————————————————————————————————————————————————————————————————————————————————— 63 | # ####### CLI ####### # 64 | 65 | qHelp(){ 66 | echo " -?, --help [option]" 67 | if [ "$1" = true ] 68 | then 69 | echo " Show basic help or show help for selected option." 70 | echo 71 | echo " Type: str" 72 | echo 73 | fi 74 | } 75 | 76 | mHelp(){ 77 | echo " -m, --man" 78 | if [ "$1" = true ] 79 | then 80 | echo " Show full help for all options." 81 | echo 82 | echo " Type: str" 83 | echo 84 | fi 85 | } 86 | 87 | iHelp(){ 88 | echo " [ -i, --in ]" 89 | if [ "$1" = true ] 90 | then 91 | echo " Input file to slice." 92 | echo 93 | echo " Type: str" 94 | echo 95 | fi 96 | } 97 | 98 | oHelp(){ 99 | echo " [ -o, --out ]" 100 | if [ "$1" = true ] 101 | then 102 | echo " Output directory for result." 103 | echo 104 | echo " Default: same as source" 105 | echo " Type: str" 106 | echo 107 | fi 108 | # sliceResult///" 109 | } 110 | 111 | eHelp(){ 112 | echo " [ -e, --extension ]" 113 | if [ "$1" = true ] 114 | then 115 | echo " Set result files extension." 116 | echo 117 | echo " Default: same as source" 118 | echo " Type: str" 119 | echo 120 | fi 121 | } 122 | 123 | wHelp(){ 124 | echo " [ -w, --width ]" 125 | if [ "$1" = true ] 126 | then 127 | echo " Set tile width." 128 | echo 129 | echo " Default: 256 pixels or same as height, if height is present." 130 | echo " Type: int" 131 | echo 132 | fi 133 | } 134 | 135 | hHelp(){ 136 | echo " [ -h, --height ]" 137 | if [ "$1" = true ] 138 | then 139 | echo " Set tile height" 140 | echo 141 | echo " Default: 256 pixels or same as width, if width is present." 142 | echo " Type: int" 143 | echo 144 | fi 145 | } 146 | 147 | sHelp(){ 148 | echo " [ -s, --step ]" 149 | if [ "$1" = true ] 150 | then 151 | echo " Zoom step value. Formula:" 152 | echo " (1) image_size[i+1] = image_size[i] * 100 / step" 153 | echo " 200 -> 200% or 2x -> 100% * 100 / 200 = 50%" 154 | echo " 175 -> 175% or 1.75x -> 100% * 100 / 175 = 57.(142857)%" 155 | echo " 120 -> 120% or 1.2x -> 100% * 100 / 120 = 83.(3)%" 156 | echo " 300 -> 300% or 3x -> 100% * 100 / 300 = 33.(3)%" 157 | echo " 100 -> 100% or 1x (no resize) -> infinity loop. Don't use it." 158 | echo 159 | echo " Default: 200" 160 | echo " Type: int" 161 | echo 162 | fi 163 | } 164 | 165 | pHelp(){ 166 | echo " [ -p, --options 'imagemagick options string']" 167 | if [ "$1" = true ] 168 | then 169 | echo " Specifies additional imagemagick options for 'convert'." 170 | echo 171 | echo " Type: str" 172 | echo 173 | fi 174 | } 175 | 176 | gHelp(){ 177 | echo " [ -g, --gravity ]" 178 | if [ "$1" = true ] 179 | then 180 | echo " Types: NorthWest North NorthEast West Center East SouthWest South SouthEast" 181 | echo " The direction you choose specifies where to position of cuts start on image. Use -list gravity to get a complete list of -gravity settings available in your ImageMagick installation." 182 | echo " http://www.imagemagick.org/script/command-line-options.php#gravity" 183 | echo 184 | echo " Default: NorthWest" 185 | echo " Type: str" 186 | echo 187 | fi 188 | } 189 | 190 | xHelp(){ 191 | echo " [ -x, --extent ]" 192 | if [ "$1" = true ] 193 | then 194 | echo " Specifies the edge tiles size: cropped or extent them to full size and fill transparent color." 195 | echo 196 | echo " Default: false" 197 | echo " Type: logic switch" 198 | echo 199 | fi 200 | } 201 | 202 | dHelp(){ 203 | echo " [ -d, --dzi ]" 204 | if [ "$1" = true ] 205 | then 206 | echo " Specifies output format." 207 | echo 208 | echo " Default: true" 209 | echo " Type: logic switch" 210 | echo 211 | fi 212 | } 213 | 214 | aHelp(){ 215 | echo " [ -a, --slicea ]" 216 | if [ "$1" = true ] 217 | then 218 | echo " Type of slicing - slice A. Image scale starts from image size to down. Inverts option '--sliceb'." 219 | echo 220 | echo " Default: true" 221 | echo " Type: logic switch" 222 | echo 223 | fi 224 | } 225 | 226 | bHelp(){ 227 | echo " [ -b, --sliceb ]" 228 | if [ "$1" = true ] 229 | then 230 | echo " Type of slicing - slice B. Image scale starts from tile size and grow up. Inverts option '--slicea'." 231 | echo 232 | echo " Default: false" 233 | echo " Type: logic switch" 234 | echo 235 | fi 236 | } 237 | 238 | cHelp(){ 239 | echo " [ -c, --scaleover ] " 240 | if [ "$1" = true ] 241 | then 242 | echo " Create upscaled image for maximum zoom (last zoom be equal or grater, then image). zoom[i-1]_size < source_image_size < zoom[i]_size" 243 | echo " Work only in slice B mode. In other cases ignored." 244 | echo 245 | echo " Default: false" 246 | echo " Type: logic switch" 247 | echo 248 | fi 249 | } 250 | 251 | rHelp(){ 252 | echo " [ -r, --horizontal ] " 253 | if [ "$1" = true ] 254 | then 255 | echo " Tiles divide image on horizontal side without remains. On this side tiles will not be croped." 256 | echo " Work only in slice B mode. In other cases ignored." 257 | echo 258 | echo " ___ ___ ___ _ _" 259 | echo " | | | | ^" 260 | echo " |___|___|___| Image" 261 | echo " |___|___|___| _v_ <- Not full tiles." 262 | echo " |_._|_._|_._| <-- Transparent color (extent=true) or cropped (extent=false)" 263 | echo 264 | echo " Default: true" 265 | echo " Type: logic switch" 266 | echo 267 | fi 268 | } 269 | 270 | tHelp(){ 271 | echo " [ -t, --vertical ] " 272 | if [ "$1" = true ] 273 | then 274 | echo " Tiles divide image on vertical side without remains. On this side tiles will not be croped." 275 | echo " Work only in slice B mode. In other cases ignored." 276 | echo 277 | echo " |<-image->|" 278 | echo " ___ ___ _ _ _ _" 279 | echo " | | | |.| ^" 280 | echo " |___|___|_|_| _v_Tile" 281 | echo " | | | |.|" 282 | echo " |___|___|_|_|" 283 | echo " ^-- Transparent color (extent=true) or cropped (extent=false)" 284 | echo " ^--- Not full tiles" 285 | echo 286 | echo " Default: false" 287 | echo " Type: logic switch" 288 | echo 289 | fi 290 | } 291 | 292 | vHelp(){ 293 | echo " [ -v, --verbose ]" 294 | if [ "$1" = true ] 295 | then 296 | echo " User-selected verbosity levels:" 297 | echo " - 0 = none" 298 | echo " - 1 = warnings" 299 | echo " - 2 = warnings + info" 300 | echo " - 3 = warnings + info + debug" 301 | echo 302 | fi 303 | echo " [ -v0, -v1, -v2, -v3 ]" 304 | if [ "$1" = true ] 305 | then 306 | echo " Short commands for each verbosity level." 307 | echo 308 | echo " Default: 0" 309 | echo " Type: logic switch" 310 | echo 311 | fi 312 | } 313 | 314 | lHelp(){ 315 | echo " [ -l, --overlap ] " 316 | if [ "$1" = true ] 317 | then 318 | echo " Tiles overlap in pixels." 319 | echo 320 | echo " Default: 1" 321 | echo " Type: int" 322 | echo 323 | fi 324 | } 325 | 326 | uHelp(){ 327 | echo " Usage:" 328 | echo " magick-slicer.sh -u|--usage" 329 | echo " magick-slicer.sh -?|--help|-m|--man [option_name]" 330 | echo " magick-slicer.sh [options] [-i] /source/image [[-o] result/dir]" 331 | echo " magick-slicer.sh /source/image [options] [result/dir]" 332 | echo " magick-slicer.sh /source/image [result/dir] [options]" 333 | echo 334 | echo " Use quotes for path or options with spaces. First unknown string interpreting as source image, if it not defined. Second unknown string is interpreting as result path, if it not defined. Also, for source and result you can use options '-i' and '-o'." 335 | echo 336 | } 337 | 338 | cliHelp(){ 339 | echo " Map tiles generator. License: MIT." 340 | echo " Version: $version" 341 | echo " Date: $date" 342 | echo 343 | 344 | case $1 in 345 | 346 | -i|--in) iHelp true ;; 347 | -o|--out) oHelp true ;; 348 | -e|--extension) eHelp true ;; 349 | -w|--width) wHelp true ;; 350 | -h|--height) hHelp true ;; 351 | -s|--step) sHelp true ;; 352 | # -l|--overlap) lHelp true ;; 353 | -p|--options) pHelp true ;; 354 | -g|--gravity) gHelp true ;; 355 | -x|--extent) xHelp true ;; 356 | -d|--dzi) dHelp true ;; 357 | -a|--slicea) aHelp true ;; 358 | -b|--sliceb) bHelp true ;; 359 | -c|--scaleover) cHelp true ;; 360 | -r|--horizontal) rHelp true ;; 361 | -t|--vertical) tHelp true ;; 362 | -v|--verbose) vHelp true ;; 363 | -u|--usage) uHelp true ;; 364 | -\?|--help) qHelp true ;; 365 | -m|--man) mHelp true ;; 366 | 367 | "") 368 | uHelp $2 369 | echo " Options list: " 370 | qHelp $2 371 | mHelp $2 372 | vHelp $2 373 | iHelp $2 374 | oHelp $2 375 | eHelp $2 376 | wHelp $2 377 | hHelp $2 378 | sHelp $2 379 | # lHelp $2 380 | pHelp $2 381 | gHelp $2 382 | xHelp $2 383 | dHelp $2 384 | aHelp $2 385 | bHelp $2 386 | cHelp $2 387 | rHelp $2 388 | tHelp $2 389 | ;; 390 | 391 | *) 392 | echo " Unknown option: $1" 393 | echo 394 | ;; 395 | esac 396 | 397 | echo 398 | exit 0 399 | } 400 | 401 | # ### CLI parsing ### 402 | debugMsg "CLI parsing" 403 | 404 | # Test number of arguments 405 | if [ $# -eq 0 ] 406 | then 407 | cliHelp 408 | fi 409 | 410 | # Temp variables for parser 411 | WnotDefined=true 412 | HnotDefined=true 413 | SourceNotDefined=true 414 | ResDirNotDefined=true 415 | ExtNotDefined=true 416 | 417 | # Arguments parsing 418 | while [[ $# > 0 ]] # cmd tools 419 | do 420 | debugMsg "Parsing key: $1" 421 | key="$1" # Get current key 422 | case $key in # Do key work 423 | 424 | -i|--in) 425 | imageSource="$2" 426 | SourceNotDefined=false 427 | shift # past argument 428 | ;; 429 | 430 | -o|--out) 431 | resultDir="$2" 432 | ResDirNotDefined=false 433 | shift # past argument 434 | ;; 435 | 436 | -e|--extension) 437 | resultExt="$2" 438 | ExtNotDefined=false 439 | shift # past argument 440 | ;; 441 | 442 | -w|--width) 443 | tileW="$2" 444 | if $HnotDefined 445 | then 446 | tileH="$2" # Set h=w by default, if it not defined yet 447 | fi 448 | WnotDefined=false 449 | shift # past argument 450 | ;; 451 | 452 | -h|--height) 453 | tileH="$2" 454 | if $WnotDefined 455 | then 456 | tileW="$2" # Set w=h by default, if it not defined yet 457 | fi 458 | HnotDefined=false 459 | shift # past argument 460 | ;; 461 | 462 | -s|--step) 463 | step="$2" 464 | shift # past argument 465 | ;; 466 | 467 | -l|--overlap) 468 | overlap="$2" 469 | shift # past argument 470 | ;; 471 | 472 | -p|--options) 473 | imOptions="$2" 474 | shift # past argument 475 | ;; 476 | 477 | -g|--gravity) 478 | gravity="$2" 479 | shift # past argument 480 | ;; 481 | 482 | -x|--extent) 483 | extent=true 484 | ;; 485 | 486 | -d|--dzi) 487 | dziFormat=true 488 | ;; 489 | 490 | -a|--slicea) 491 | scaleFromImage=true 492 | ;; 493 | 494 | -b|--sliceb) 495 | scaleFromImage=false 496 | ;; 497 | 498 | -c|--scaleover) 499 | scaleover=false 500 | ;; 501 | 502 | -r|--horizontal) 503 | horizontal=true 504 | ;; 505 | 506 | -t|--vertical) 507 | horizontal=false 508 | ;; 509 | 510 | -v|--verbose) 511 | verboseLevel="$2" 512 | shift # past argument 513 | ;; 514 | 515 | -v0|--verbose0) 516 | verboseLevel=0 517 | ;; 518 | 519 | -v1|--verbose1) 520 | verboseLevel=1 521 | ;; 522 | 523 | -v2|--verbose1) 524 | verboseLevel=2 525 | ;; 526 | 527 | -v3|--verbose1) 528 | verboseLevel=3 529 | ;; 530 | 531 | -u|--usage) 532 | uHelp 533 | exit 0 534 | ;; 535 | 536 | -\?|--help) 537 | cliHelp "$2" 538 | shift # past argument 539 | ;; 540 | 541 | -m|--man) 542 | cliHelp "" true 543 | ;; 544 | 545 | # --default) 546 | # DEFAULT=YES 547 | # ;; 548 | 549 | *) 550 | if $SourceNotDefined # Interpreting first unknown command as source 551 | then 552 | imageSource="$1" 553 | SourceNotDefined=false 554 | else 555 | if $ResDirNotDefined # Interpreting second unknown command as source 556 | then 557 | resultDir="$1" 558 | ResDirNotDefined=false 559 | else # Interpreting third unknown command as unknown command 560 | echo "Unknown option: $1" 561 | fi 562 | fi 563 | ;; 564 | esac 565 | 566 | shift # Get next key 567 | done 568 | 569 | # Cheking for installed applications 570 | command -v convert >/dev/null 2>&1 || { echo >&2 "I require ImageMagick tool 'convert', but it's not installed. Aborting."; exit 1; } 571 | command -v identify >/dev/null 2>&1 || { echo >&2 "I require ImageMagick tool 'identify', but it's not installed. Aborting."; exit 1; } 572 | 573 | # Checking if file was defined 574 | if $SourceNotDefined 575 | then 576 | echo "No source file present. Canceled." 577 | exit 1 578 | fi 579 | 580 | # Cheking if source file not exists 581 | if [ ! -f "$imageSource" ] 582 | then 583 | echo "Error! Input file 'images source' not found! File path: $imageSource" 584 | exit 1 585 | fi 586 | 587 | # Set extension 588 | fullName=$(basename "$imageSource") 589 | fileBase="${fullName%.*}" 590 | fileExt="${fullName##*.}" 591 | 592 | if $ExtNotDefined 593 | then 594 | resultExt="$fileExt" 595 | fi 596 | 597 | # Set out name 598 | if $ResDirNotDefined 599 | then 600 | resultDir="$fileBase" 601 | fi 602 | 603 | # ——————————————————————————————————————————————————————————————————————————————————— 604 | # ####### Functions ####### # 605 | debugMsg "Section: Functions" 606 | 607 | getImgW(){ # image_file 608 | echo `identify -format "%[fx:w]" $1` 609 | } 610 | 611 | getImgH(){ # image_file 612 | echo `identify -format "%[fx:h]" $1` 613 | } 614 | 615 | # ——————————————————————————————————————————————————————————————————————————————————— 616 | # ######################## # 617 | # ####### Slicer A ####### # 618 | debugMsg "Section: Slicer A" 619 | 620 | # Constants 621 | scaleBase=100 # Scale in percents - 100% (TODO: add option to use image sizes) 622 | scaleMult=100000 # Scale multiplier (bash works only with int) 623 | scaleMult64=100000000000000 # Scale multiplier for x64 bash and x64 convert (if you have very many zoom level and need more accuracy) 624 | scaleStart=0 625 | # declare -a scaledW 626 | # declare -a scaledH 627 | # scaledW=() 628 | # scaledH=() 629 | 630 | setScale(){ 631 | if $scale64 632 | then 633 | local arch=`uname -m` 634 | if [ "${arch}" == "x86_64" ] 635 | then 636 | scaleMult=$scaleMult64 637 | else 638 | echo "Your system (${arch}) isn't x86_64" 639 | exit 1 640 | fi 641 | fi 642 | scaleStart=$(( $scaleBase * $scaleMult )) 643 | } 644 | 645 | getZoomLevels(){ # imgLen(pixels) tileLen(pixels) step(int) # Calculate zoom levels for current step 646 | local imgLen=$1 647 | local tileLen=$2 648 | local zoomStep=$3 649 | local r=(0) 650 | local cnt=1 651 | 652 | # Drop zooms less tile size 653 | # while [ "$imgLen" -gt "$tileLen" ] 654 | # do 655 | # r[$cnt]=$imgLen 656 | # let "cnt+=1" 657 | # let "imgLen = imgLen * 100 / zoomStep" 658 | # done 659 | 660 | # Do all zooms down to 1x1 px 661 | while [ "$imgLen" -ge 1 ] 662 | do 663 | r[$cnt]=$imgLen 664 | let "cnt+=1" 665 | let "imgLen = imgLen * 100 / zoomStep" 666 | done 667 | 668 | r[$cnt]=$imgLen 669 | r[0]=$cnt 670 | echo ${r[*]} 671 | } 672 | 673 | nextScale(){ # oldScale -> newScale 674 | # Calculate image zoom in percents - it need for imagemagick for image resize 675 | echo $(( $1 * 100 / $step )) 676 | } 677 | 678 | scaleToPercents(){ # scale 679 | local s=$1 680 | local sInt=0 681 | local sFloat=0 682 | let "sInt = s / $scaleMult" 683 | let "sFloat = s - sInt * $scaleMult" 684 | echo "${sInt}.${sFloat}%" 685 | } 686 | 687 | # scaleImage(){ # zoom scale -> file_path 688 | # local zoom=$1 689 | # local s=$2 690 | # local dir="${resultDir}/${zoom}" 691 | # local file="${dir}.${resultExt}" 692 | # local size=`scaleToPercents $s` 693 | # mkdir -p $dir # Imagemagick can't create directories 694 | # convert $imageSource $resizeFilter -resize $size $file 695 | # echo $file 696 | # } 697 | 698 | zoomImage(){ # zoom size -> file_path 699 | local zoom=$1 700 | local size=$2 701 | local dir="${resultDir}/${zoom}" 702 | local file="${dir}.${resultExt}" 703 | # local file="${dir}.png" 704 | # local size=`scaleToPercents $s` 705 | mkdir -p $dir # Imagemagick can't create directories 706 | convert $imageSource $resizeFilter -resize $size $imOptions $file 707 | echo $file 708 | } 709 | 710 | sliceImage(){ # zoom image 711 | local zoom=$1 712 | local src=$2 713 | local wxh="${tileW}x${tileH}" 714 | 715 | local xyDelim='/' 716 | if $dziFormat 717 | then 718 | xyDelim='_' 719 | fi 720 | 721 | local tilesFormat="%[fx:page.x/${tileW}]${xyDelim}%[fx:page.y/${tileH}]" # This very important magic! It allow imagemagick to generate tile names with it position and place it in corect folders (but folders need to generate manually) 722 | local file="${resultDir}/${zoom}/%[filename:tile].${resultExt}" 723 | 724 | if [ ! $dziFormat ] 725 | then 726 | # Creating subdirectories for tiles (one vertical line of tiles is in one folder) 727 | local srcSize=`getImgW $src` # Getting image width 728 | local dirNum=$(( $srcSize / $tileW )) # Calculating number of tiles in line 729 | local i=0 730 | for(( i=0; i<=$dirNum; i++ )) 731 | do 732 | mkdir -p "${resultDir}/${zoom}/$i" # Imagemagick can't create directories 733 | done 734 | sync 735 | fi 736 | 737 | # extent option 738 | local ext='' 739 | if $extent 740 | then 741 | ext="-background none -extent ${wxh}" 742 | fi 743 | 744 | # Slice image to tiles 745 | # convert $src -crop $wxh -set filename:tile $tilesFormat +repage +adjoin -background none -gravity $gravity $ext $file 746 | convert $src -gravity $gravity -crop $wxh -set filename:tile $tilesFormat +repage +adjoin -gravity $gravity $ext $file 747 | } 748 | 749 | sliceA(){ 750 | infoMsg " Slicer A is running..." 751 | local scalesW=( `getZoomLevels $imageW $tileW $step` ) # Get width for each zoom level 752 | local scalesH=( `getZoomLevels $imageH $tileH $step` ) # Get height for each zoom level 753 | local zw=${scalesW[0]} # Get zoom level for width 754 | local zh=${scalesH[0]} # Get zoom level for height 755 | local scales=() # Creating empty array 756 | local zoomMax=0 757 | local zoom=0 758 | local hMod='' 759 | local s=0 760 | local file='' 761 | 762 | if [ "$zw" -ge "$zh" ] 763 | then 764 | zoomMax=$zw 765 | scales=( ${scalesW[*]} ) 766 | hMod='' 767 | else 768 | zoomMax=$zh 769 | scales=( ${scalesH[*]} ) 770 | hMod='x' 771 | fi 772 | 773 | # local scale=$scaleStart 774 | # local scalep='' 775 | while [ "$s" -lt "$zoomMax" ] 776 | do 777 | if $zoomReverse 778 | then 779 | let "zoom = s" 780 | else 781 | let "zoom = zoomMax - s" 782 | fi 783 | 784 | infoMsg "    Resizing next file..." 785 | debugMsg "    zoomMax=$zoomMax, zoomLevel=$s, wxhInex=$zoom, wxh=${hMod}${scales[$zoom]}" 786 | file=`zoomImage $s "${hMod}${scales[$zoom]}"` 787 | infoMsg "    File resized: ${file}" 788 | infoMsg "    Slicing file..." 789 | sliceImage $s $file 790 | rm -rf $file 791 | 792 | # scalep=`scaleToPercents $scale` 793 | # s=${scales[zoom-1]} 794 | # echo $zoom "$s" 795 | # file=`scaleImage $zoom "${hMod}${scales[$zoom]}"` 796 | # echo "zoom, scalep, scale: $zoom $scalep $scale $file" 797 | # echo ${scaledW[$i]} 798 | # echo ${scaledH[$i]} 799 | # scale=`nextScale $scale` 800 | 801 | let "s+=1" 802 | done 803 | 804 | infoMsg " Slicer A complete" 805 | 806 | # s=`nextScale $scaleStart` 807 | # s=`nextScale $s` 808 | # scaleToPercents $s 809 | } 810 | 811 | # ——————————————————————————————————————————————————————————————————————————————————— 812 | # ########################## 813 | # ####### Slicer B ####### # 814 | debugMsg "Section: Slicer B" 815 | 816 | zoomPixels(){ # zoom tileSize 817 | local zoom=$1 818 | local pixels=$2 819 | if [ "$zoom" -ne 0 ] 820 | then 821 | let "pixels = pixels * 100" 822 | for(( i=0; i file_path 832 | local zoom=$1 833 | local dir="${resultDir}/${zoom}" 834 | local file="${dir}.${resultExt}" 835 | local size=`zoomPixels $zoom $tileW` 836 | mkdir -p $dir # Imagemagick can't create directories 837 | convert $imageSource $resizeFilter -resize $size $imOptions $file 838 | echo $file 839 | } 840 | 841 | resizeImageV(){ # zoom -> file_path 842 | local zoom=$1 843 | local dir="${resultDir}/${zoom}" 844 | local file="${dir}.${resultExt}" 845 | local size=`zoomPixels $zoom $tileH` 846 | mkdir -p $dir # Imagemagick can't create directories 847 | convert $imageSource $resizeFilter -resize "x${size}" $imOptions $file 848 | echo $file 849 | } 850 | 851 | resizeImage(){ # zoom -> file_path 852 | if $horizontal 853 | then 854 | echo `resizeImageH $1` 855 | else 856 | echo `resizeImageV $1` 857 | fi 858 | } 859 | 860 | sliceB(){ 861 | echo "Slicer B is running..." 862 | local size=0 863 | local sizeMax=0 864 | local zoom=0 865 | 866 | if $horizontal 867 | then 868 | let "size = $tileW" 869 | let "sizeMax = $imageW" 870 | else 871 | let "size = $tileH" 872 | let "sizeMax = $imageH" 873 | fi 874 | 875 | if $scaleover 876 | then 877 | let "sizeMax += $size" 878 | fi 879 | 880 | local px=$size 881 | while [ "$px" -lt "$sizeMax" ] 882 | do 883 | echo " Slicing zoom level \"${zoom}\"; image main size is \"${px}\"" 884 | sliceImage $zoom `resizeImage $zoom` 885 | let "zoom++" 886 | px=`zoomPixels $zoom $size` 887 | done 888 | echo "Slicer B complete" 889 | } 890 | 891 | 892 | mainScale(){ # min zoom = tile width 893 | if $scaleFromImage 894 | then 895 | sliceA 896 | else 897 | sliceB 898 | fi 899 | echo 900 | } 901 | 902 | setDziFormat(){ 903 | local dziFileName="${resultDir}.dzi" 904 | resultDir="${resultDir}_files" 905 | tileH=$tileW 906 | 907 | mkdir -p "$(dirname "${dziFileName}")" 908 | touch ${dziFileName} 909 | 910 | echo '' > "$dziFileName" 911 | echo "" >> "$dziFileName" 912 | echo "" >> "$dziFileName" 913 | echo '' >> "$dziFileName" 914 | # 915 | # 916 | # 917 | # 918 | } 919 | 920 | setFormat(){ 921 | if $dziFormat 922 | then 923 | setDziFormat 924 | fi 925 | } 926 | 927 | init(){ 928 | if [ "$step" -le 100 ] 929 | then 930 | echo "You get infinity loop. Minimum step value = 101% (101)" 931 | exit 1 932 | fi 933 | # Getting image sizes 934 | imageW=`getImgW $imageSource` 935 | imageH=`getImgH $imageSource` 936 | 937 | # Set options for selected format 938 | setFormat 939 | 940 | # Set scale 941 | setScale 942 | 943 | rm -rf $resultDir # removing old results 944 | mkdir -p $resultDir # creating new results folder 945 | 946 | } 947 | 948 | # ——————————————————————————————————————————————————————————————————————————————————— 949 | # ###################### # 950 | # ### Programm start ### # 951 | debugMsg "Section: Programm" 952 | 953 | init 954 | mainScale 955 | 956 | # ### Programm end ##### # 957 | # ###################### # 958 | # ——————————————————————————————————————————————————————————————————————————————————— 959 | --------------------------------------------------------------------------------