├── .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 | [](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 |
--------------------------------------------------------------------------------