Skip to content

Instantly share code, notes, and snippets.

@emilio-rst
Forked from markusfisch/README.md
Created July 28, 2014 22:05
Show Gist options
  • Select an option

  • Save emilio-rst/baae894fa62cb08bb306 to your computer and use it in GitHub Desktop.

Select an option

Save emilio-rst/baae894fa62cb08bb306 to your computer and use it in GitHub Desktop.

Revisions

  1. @markusfisch markusfisch revised this gist Jul 1, 2014. 2 changed files with 3 additions and 3 deletions.
    4 changes: 2 additions & 2 deletions mkatlas
    Original file line number Diff line number Diff line change
    @@ -187,7 +187,7 @@ atlas_create()

    # prepare source files
    local SRC
    for SRC in "$@"
    for SRC
    do
    local COPY="$TMPDIR/${SRC##*/}"

    @@ -222,4 +222,4 @@ readonly BORDER=${BORDER:-0}
    if [ "$BASH_SOURCE" == "$0" ]
    then
    atlas_create "$@"
    fi
    fi
    2 changes: 1 addition & 1 deletion patchatlas
    Original file line number Diff line number Diff line change
    @@ -28,7 +28,7 @@ atlas_patch()
    local PATCH="s^{/\*${NAME}\*/[\"xywh:0-9,]*}^{/*${NAME}*/${FRAME%,}^g"
    local TMP=".${0##*/}-$$.tmp"
    local SRC
    for SRC in "$@"
    for SRC
    do
    sed -e "$PATCH" < $SRC > $TMP && mv $TMP $SRC
    done
  2. @markusfisch markusfisch revised this gist Jun 25, 2014. 2 changed files with 8 additions and 2 deletions.
    5 changes: 4 additions & 1 deletion mkatlas
    Original file line number Diff line number Diff line change
    @@ -219,4 +219,7 @@ atlas_create()

    readonly BORDER=${BORDER:-0}

    [ "$0" == "$BASH_SOURCE" ] && atlas_create "$@"
    if [ "$BASH_SOURCE" == "$0" ]
    then
    atlas_create "$@"
    fi
    5 changes: 4 additions & 1 deletion patchatlas
    Original file line number Diff line number Diff line change
    @@ -35,4 +35,7 @@ atlas_patch()
    done
    }

    [ "$0" == "$BASH_SOURCE" ] && atlas_patch "$@"
    if [ "$BASH_SOURCE" == "$0" ]
    then
    atlas_patch "$@"
    fi
  3. @markusfisch markusfisch revised this gist May 7, 2014. 2 changed files with 149 additions and 115 deletions.
    11 changes: 2 additions & 9 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -45,22 +45,15 @@ Just put them before invocation, e.g.:

    $ ATLAS=atlas.jpg ./mkatlas img/*

    #### WIDTH
    Maximum width of atlas. Default is 2048.

    #### HEIGHT
    Maximum height of atlas. Default is 2048.
    #### MAX_SIZE
    Maximum width/height of atlas. Default is 2048.

    #### BORDER
    Padding around sprites. Default is 0.

    #### ATLAS
    File name (and image format) of atlas image.

    #### PREFER_LARGER_CELLS
    Prefer larger cells for lay out if set. Depending on your sprite set,
    that may make a smaller atlas. Just try.

    [1]: http://en.wikipedia.org/wiki/Bash_(Unix_shell)
    [2]: http://en.wikipedia.org/wiki/Texture_atlas
    [3]: http://www.imagemagick.org/
    253 changes: 147 additions & 106 deletions mkatlas
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,35 @@
    #!/usr/bin/env bash

    # Horizontal cut
    atlas_cut_horizontal()
    # Compose images into atlas
    atlas_cache_compose()
    {
    echo $(( X+$1 )) $Y $W $2 > $NODE/child0/rect
    echo $X $(( Y+$2 )) $NW $H > $NODE/child1/rect
    [ -f $CACHE/args ] && convert \
    -size "`< $CACHE/width`x`< $CACHE/height`" \
    xc:transparent \
    `< $CACHE/args` \
    -strip \
    -trim \
    -bordercolor none -border $BORDER \
    "${ATLAS:-atlas.png}"
    }

    # Vertical cut
    atlas_cut_vertical()
    # Print JSON and build arguments for convert
    atlas_cache_summarize()
    {
    echo $X $(( Y+$2 )) $1 $H > $NODE/child0/rect
    echo $(( X+$1 )) $Y $W $NH > $NODE/child1/rect
    echo "var atlas={"

    find $CACHE -type f -name image | while read
    do
    local X Y W H FILE
    read X Y W H FILE < $REPLY

    echo "$FILE -geometry +$X+$Y -composite" >> $CACHE/args

    local NAME=${FILE##*/}
    echo "${NAME%.*}:{x:$X,y:$Y,w:$W,h:$H},"
    done

    echo "};"
    }

    # Insert image, packing algorithm from
    @@ -20,162 +38,185 @@ atlas_cut_vertical()
    # @param 1 - image width
    # @param 2 - image height
    # @param 3 - image file
    atlas_insert()
    atlas_cache_insert()
    {
    if [ -d "$NODE/child0" ]
    then
    local N=$NODE
    [ -f $CACHE/candidates ] || return 1

    NODE=$N/child0
    atlas_insert $1 $2 $3 && return 0
    local INDEX TARGET
    while read INDEX TARGET
    do
    break
    done <<< "`sort $CACHE/candidates`"

    [ -f $TARGET/rect ] || return 1

    NODE=$N/child1
    atlas_insert $1 $2 $3 && return 0
    local X Y W H
    read X Y W H < $TARGET/rect

    if (( W < $1 )) || (( H < $2 ))
    then
    return 1
    fi

    [ -f $NODE/rect ] || return 1
    mkdir $TARGET/child0 $TARGET/child1 || return $?

    local X Y NW NH
    read X Y NW NH < $NODE/rect
    local RW=$(( W-$1 ))
    local RH=$(( H-$2 ))

    if (( $1 > NW )) || (( $2 > NH ))
    if (( RW > RH ))
    then
    return 1
    # +-------+---+
    # | image | |
    # +-------+ |
    # | | r |
    # | b | |
    # | | |
    # +-------+---+
    echo $(( X+$1 )) $Y $RW $H > $TARGET/child0/rect
    echo $X $(( Y+$2 )) $1 $RH > $TARGET/child1/rect
    else
    # +-------+---+
    # | image | r |
    # +-------+---+
    # | |
    # | b |
    # | |
    # +-----------+
    echo $(( X+$1 )) $Y $RW $2 > $TARGET/child0/rect
    echo $X $(( Y+$2 )) $W $RH > $TARGET/child1/rect
    fi

    local W=$(( NW-$1 ))
    local H=$(( NH-$2 ))
    local RIGHT=$(( X+$1 ))
    (( $RIGHT > `< $CACHE/width` )) && echo $RIGHT > $CACHE/width

    local BOTTOM=$(( Y+$2 ))
    (( $BOTTOM > `< $CACHE/height` )) && echo $BOTTOM > $CACHE/height

    mkdir $NODE/child0 $NODE/child1
    echo $X $Y $1 $2 $3 > $TARGET/image
    }

    if (( H > W ))
    # Find possible candidates and give them a sort index
    #
    # @param 1 - image width
    # @param 2 - image height
    # @param 3 - image file
    atlas_cache_find_nodes()
    {
    if [ -d "$NODE/child0" ]
    then
    if (( PREFER_LARGER_CELLS ))
    then
    atlas_cut_horizontal $1 $2
    else
    atlas_cut_vertical $1 $2
    fi
    else
    if (( PREFER_LARGER_CELLS ))
    then
    atlas_cut_vertical $1 $2
    else
    atlas_cut_horizontal $1 $2
    fi
    NODE=$NODE/child0 atlas_cache_find_nodes $1 $2 $3
    NODE=$NODE/child1 atlas_cache_find_nodes $1 $2 $3

    return
    fi

    echo \
    $(( X+BORDER )) \
    $(( Y+BORDER )) \
    $(( $1-BORDER*2 )) \
    $(( $2-BORDER*2 )) \
    $3 > $NODE/image
    [ -f $NODE/rect ] || return 1

    local X Y W H
    read X Y W H < $NODE/rect

    if (( W < $1 )) || (( H < $2 ))
    then
    return
    fi

    local MAX_WIDTH=`< $CACHE/width`
    local MAX_HEIGHT=`< $CACHE/height`
    local RIGHT=$(( X+$1 ))
    local BOTTOM=$(( Y+$2 ))

    (( RIGHT > MAX_WIDTH )) && MAX_WIDTH=$RIGHT
    (( BOTTOM > MAX_HEIGHT )) && MAX_HEIGHT=$BOTTOM

    return 0
    printf '%08d %s\n' \
    $(( MAX_WIDTH+MAX_HEIGHT )) \
    $NODE >> $CACHE/candidates
    }

    # Create texture atlas from a listing in the format "width height filename"
    atlas_from_list()
    # Sort files and insert them into the atlas
    atlas_cache_compile()
    {
    local CACHE
    CACHE=`mktemp -d ${0##*/}.XXXXXXXXXX` || return 1

    local WIDTH=${WIDTH:-2048}
    local HEIGHT=${HEIGHT:-2048}
    echo 0 0 $WIDTH $HEIGHT > $CACHE/rect
    local NODE=$CACHE
    local W H FILE

    # sort files and insert them into the atlas
    local MAX W H FILE
    while read W H FILE
    do
    [ "$FILE" ] || continue

    if (( W > H ))
    then
    MAX=$W
    else
    MAX=$H
    fi

    printf '%08d %d %d %s\n' $MAX $W $H $FILE
    printf '%08d %d %d %s\n' $(( W+H )) $W $H $FILE
    done | sort -r | while read MAX W H FILE
    do
    local NODE=$CACHE
    atlas_insert $W $H $FILE || {
    echo 'error: canvas too small' >&2
    break
    }
    done

    # print JSON and build arguments for convert
    echo "var atlas={"
    rm -f $CACHE/candidates

    find $CACHE -type f -name image | while read
    do
    local X Y W H FILE
    read X Y W H FILE < $REPLY
    if ! atlas_cache_find_nodes $W $H $FILE ||
    ! atlas_cache_insert $W $H $FILE
    then
    echo 'error: cannot insert' $FILE >&2
    return 1
    fi
    done
    }

    echo "$FILE -geometry +$X+$Y -composite" >> $CACHE/args
    # Read 'width height file' from standard input and create atlas
    atlas_create_from_list()
    {
    local CACHE
    CACHE=`mktemp -d ${0##*/}.XXXXXXXXXX` || return $?

    local NAME=${FILE##*/}
    echo "${NAME%.*}:{x:$X,y:$Y,w:$W,h:$H},"
    done
    local MAX_SIZE=${MAX_SIZE:-2048}
    echo 0 0 $MAX_SIZE $MAX_SIZE > $CACHE/rect

    echo "};"
    echo 0 > $CACHE/width
    echo 0 > $CACHE/height

    # compose images into atlas
    convert -size "${WIDTH}x${HEIGHT}" xc:transparent \
    `< $CACHE/args` \
    -strip -trim -bordercolor none -border $BORDER \
    "${ATLAS:-atlas.png}"
    atlas_cache_compile &&
    atlas_cache_summarize &&
    atlas_cache_compose

    rm -rf $CACHE
    }

    # Create texture atlas
    # Create texture atlas from given image files
    #
    # @param ... - image files
    atlas_from_files()
    atlas_create()
    {
    local INKSCAPE=${INKSCAPE:-`which inkscape`}
    local TMPDIR
    TMPDIR=`mktemp -d ${0##*/}.XXXXXXXXXX` || return $?

    local TRIMDIR
    TRIMDIR=`mktemp -d ${0##*/}.XXXXXXXXXX` || return 1

    # trim/raster input files first
    local FILE
    for FILE in "$@"
    # prepare source files
    local SRC
    for SRC in "$@"
    do
    local TRIM="$TRIMDIR/${FILE##*/}"
    local COPY="$TMPDIR/${SRC##*/}"

    case ${TRIM##*.} in
    case ${SRC##*.} in
    svg)
    TRIM="${TRIM%.*}.png"
    COPY="${COPY%.*}.png"

    # use inkscape if available
    [ "$INKSCAPE" ] &&
    $INKSCAPE "$FILE" \
    -z -e "$TRIM" &>/dev/null &&
    FILE=${TRIM}
    $INKSCAPE "$SRC" \
    -z -e "$COPY" &>/dev/null &&
    SRC=${COPY}
    ;;
    esac

    convert \
    -background none \
    "$FILE" \
    "$SRC" \
    -strip \
    -bordercolor none -border 3x3 \
    -trim \
    -bordercolor none -border $BORDER \
    "$TRIM"
    -bordercolor none -border ${BORDER} \
    "$COPY"
    done

    identify -format '%w %h %d/%f\n' "$TRIMDIR/*" | atlas_from_list
    rm -rf $TRIMDIR
    identify -format '%w %h %d/%f\n' "$TMPDIR/*" | atlas_create_from_list
    rm -rf $TMPDIR
    }

    readonly BORDER=${BORDER:-0}

    [ "$0" == "$BASH_SOURCE" ] && atlas_from_files "$@"
    [ "$0" == "$BASH_SOURCE" ] && atlas_create "$@"
  4. @markusfisch markusfisch revised this gist Apr 25, 2014. 1 changed file with 9 additions and 1 deletion.
    10 changes: 9 additions & 1 deletion mkatlas
    Original file line number Diff line number Diff line change
    @@ -140,10 +140,12 @@ atlas_from_list()
    # @param ... - image files
    atlas_from_files()
    {
    local INKSCAPE=${INKSCAPE:-`which inkscape`}

    local TRIMDIR
    TRIMDIR=`mktemp -d ${0##*/}.XXXXXXXXXX` || return 1

    # trim input files first
    # trim/raster input files first
    local FILE
    for FILE in "$@"
    do
    @@ -152,6 +154,12 @@ atlas_from_files()
    case ${TRIM##*.} in
    svg)
    TRIM="${TRIM%.*}.png"

    # use inkscape if available
    [ "$INKSCAPE" ] &&
    $INKSCAPE "$FILE" \
    -z -e "$TRIM" &>/dev/null &&
    FILE=${TRIM}
    ;;
    esac

  5. @markusfisch markusfisch revised this gist Apr 24, 2014. 1 changed file with 18 additions and 8 deletions.
    26 changes: 18 additions & 8 deletions mkatlas
    Original file line number Diff line number Diff line change
    @@ -140,22 +140,32 @@ atlas_from_list()
    # @param ... - image files
    atlas_from_files()
    {
    local TRIMMED
    TRIMMED=`mktemp -d ${0##*/}.XXXXXXXXXX` || return 1
    local TRIMDIR
    TRIMDIR=`mktemp -d ${0##*/}.XXXXXXXXXX` || return 1

    # trim input files first
    local F
    for F in "$@"
    local FILE
    for FILE in "$@"
    do
    convert "$F" \
    local TRIM="$TRIMDIR/${FILE##*/}"

    case ${TRIM##*.} in
    svg)
    TRIM="${TRIM%.*}.png"
    ;;
    esac

    convert \
    -background none \
    "$FILE" \
    -strip \
    -trim \
    -bordercolor none -border $BORDER \
    "$TRIMMED/${F##*/}"
    "$TRIM"
    done

    identify -format '%w %h %d/%f\n' "$TRIMMED/*" | atlas_from_list
    rm -rf $TRIMMED
    identify -format '%w %h %d/%f\n' "$TRIMDIR/*" | atlas_from_list
    rm -rf $TRIMDIR
    }

    readonly BORDER=${BORDER:-0}
  6. @markusfisch markusfisch revised this gist Feb 4, 2014. 2 changed files with 10 additions and 10 deletions.
    8 changes: 4 additions & 4 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -57,10 +57,10 @@ Padding around sprites. Default is 0.
    #### ATLAS
    File name (and image format) of atlas image.

    #### PREFER_SMALLER
    Prefer smaller region for lay out if set. Sometimes this gives a smaller
    atlas. Just try.
    #### PREFER_LARGER_CELLS
    Prefer larger cells for lay out if set. Depending on your sprite set,
    that may make a smaller atlas. Just try.

    [1]: http://en.wikipedia.org/wiki/Bash_(Unix_shell)
    [2]: http://en.wikipedia.org/wiki/Texture_atlas
    [3]: http://www.imagemagick.org/
    [3]: http://www.imagemagick.org/
    12 changes: 6 additions & 6 deletions mkatlas
    Original file line number Diff line number Diff line change
    @@ -52,18 +52,18 @@ atlas_insert()

    if (( H > W ))
    then
    if (( PREFER_SMALLER ))
    if (( PREFER_LARGER_CELLS ))
    then
    atlas_cut_vertical $1 $2
    else
    atlas_cut_horizontal $1 $2
    else
    atlas_cut_vertical $1 $2
    fi
    else
    if (( PREFER_SMALLER ))
    if (( PREFER_LARGER_CELLS ))
    then
    atlas_cut_horizontal $1 $2
    else
    atlas_cut_vertical $1 $2
    else
    atlas_cut_horizontal $1 $2
    fi
    fi

  7. @markusfisch markusfisch revised this gist Jan 16, 2014. 1 changed file with 6 additions and 1 deletion.
    7 changes: 6 additions & 1 deletion mkatlas
    Original file line number Diff line number Diff line change
    @@ -67,7 +67,12 @@ atlas_insert()
    fi
    fi

    echo $X $Y $1 $2 $3 > $NODE/image
    echo \
    $(( X+BORDER )) \
    $(( Y+BORDER )) \
    $(( $1-BORDER*2 )) \
    $(( $2-BORDER*2 )) \
    $3 > $NODE/image

    return 0
    }
  8. @markusfisch markusfisch revised this gist Jan 9, 2014. 2 changed files with 3 additions and 5 deletions.
    6 changes: 2 additions & 4 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@ Switches
    There are a few variables for fine tuning.
    Just put them before invocation, e.g.:

    $ BORDER=0 ATLAS=atlas.jpg ./mkatlas img/*
    $ ATLAS=atlas.jpg ./mkatlas img/*

    #### WIDTH
    Maximum width of atlas. Default is 2048.
    @@ -52,9 +52,7 @@ Maximum width of atlas. Default is 2048.
    Maximum height of atlas. Default is 2048.

    #### BORDER
    Padding around sprites. If you intend to scale the atlas, it's wise to have
    a padding because sampling will make sprites "bleed" out of their frame.
    Default is 2.
    Padding around sprites. Default is 0.

    #### ATLAS
    File name (and image format) of atlas image.
    2 changes: 1 addition & 1 deletion mkatlas
    Original file line number Diff line number Diff line change
    @@ -153,6 +153,6 @@ atlas_from_files()
    rm -rf $TRIMMED
    }

    readonly BORDER=${BORDER:-2}
    readonly BORDER=${BORDER:-0}

    [ "$0" == "$BASH_SOURCE" ] && atlas_from_files "$@"
  9. @markusfisch markusfisch revised this gist Oct 2, 2013. 2 changed files with 2 additions and 2 deletions.
    2 changes: 1 addition & 1 deletion mkatlas
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    #!/bin/bash
    #!/usr/bin/env bash

    # Horizontal cut
    atlas_cut_horizontal()
    2 changes: 1 addition & 1 deletion patchatlas
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    #!/bin/bash
    #!/usr/bin/env bash

    # Patch given JavaScript files with JSON read from stdin
    #
  10. @markusfisch markusfisch revised this gist Sep 10, 2013. 1 changed file with 1 addition and 69 deletions.
    70 changes: 1 addition & 69 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,6 @@
    mkatlas
    =======

    [BASH][1] script to build a [texture atlas][2] for small/medium web
    sites/games. Requires [ImageMagickmkatlas
    =======

    [BASH][1] script to build a [texture atlas][2] for small/medium web
    sites/games. Requires [ImageMagick][3].

    @@ -69,68 +65,4 @@ atlas. Just try.

    [1]: http://en.wikipedia.org/wiki/Bash_(Unix_shell)
    [2]: http://en.wikipedia.org/wiki/Texture_atlas
    [3]: http://www.imagemagick.org/
    ][3].

    Usage
    -----

    ### Basic

    Just run

    $ ./mkatlas img/*

    which will create _atlas.png_ and outputs the corresponding sprite regions
    in JSON format:

    var atlas={
    first:{x:298,y:0,w:35,h:22},
    second:{x:254,y:0,w:44,h:33},
    ...
    }

    ### Advanced

    Alternatively you may use just markers in your JavaScript to insert the
    frame data in place. This way you wouldn't have to have a extra _atlas_
    object and wouldn't need to do any additional mapping. For example:

    var obj = {
    name: "Jim",
    frame: {/*first*/x:0,y:0,w:0,h:0},
    live: 100 };

    This file may be patched with _patchatlas_ like this:

    $ ./mkatlas img/* | ./patchatlas index.html

    Switches
    --------

    There are a few variables for fine tuning.
    Just put them before invocation, e.g.:

    $ BORDER=0 ATLAS=atlas.jpg ./mkatlas img/*

    WIDTH
    Maximum width of atlas. Default is 2048.

    HEIGHT
    Maximum height of atlas. Default is 2048.

    BORDER
    Padding around sprites. If you intend to scale the atlas, it's wise to have
    a padding because sampling will make sprites "bleed" out of their frame.
    Default is 2.

    ATLAS
    File name (and image format) of atlas image.

    PREFER_SMALLER
    Prefer smaller region for lay out if set. Sometimes this gives a smaller
    atlas. Just try.

    [1]: http://en.wikipedia.org/wiki/Bash_(Unix_shell)
    [2]: http://en.wikipedia.org/wiki/Texture_atlas
    [3]: http://www.imagemagick.org/
    [3]: http://www.imagemagick.org/
  11. @markusfisch markusfisch revised this gist Sep 9, 2013. 1 changed file with 68 additions and 0 deletions.
    68 changes: 68 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,10 @@
    mkatlas
    =======

    [BASH][1] script to build a [texture atlas][2] for small/medium web
    sites/games. Requires [ImageMagickmkatlas
    =======

    [BASH][1] script to build a [texture atlas][2] for small/medium web
    sites/games. Requires [ImageMagick][3].

    @@ -40,6 +44,70 @@ This file may be patched with _patchatlas_ like this:
    Switches
    --------

    There are a few variables for fine tuning.
    Just put them before invocation, e.g.:

    $ BORDER=0 ATLAS=atlas.jpg ./mkatlas img/*

    #### WIDTH
    Maximum width of atlas. Default is 2048.

    #### HEIGHT
    Maximum height of atlas. Default is 2048.

    #### BORDER
    Padding around sprites. If you intend to scale the atlas, it's wise to have
    a padding because sampling will make sprites "bleed" out of their frame.
    Default is 2.

    #### ATLAS
    File name (and image format) of atlas image.

    #### PREFER_SMALLER
    Prefer smaller region for lay out if set. Sometimes this gives a smaller
    atlas. Just try.

    [1]: http://en.wikipedia.org/wiki/Bash_(Unix_shell)
    [2]: http://en.wikipedia.org/wiki/Texture_atlas
    [3]: http://www.imagemagick.org/
    ][3].

    Usage
    -----

    ### Basic

    Just run

    $ ./mkatlas img/*

    which will create _atlas.png_ and outputs the corresponding sprite regions
    in JSON format:

    var atlas={
    first:{x:298,y:0,w:35,h:22},
    second:{x:254,y:0,w:44,h:33},
    ...
    }

    ### Advanced

    Alternatively you may use just markers in your JavaScript to insert the
    frame data in place. This way you wouldn't have to have a extra _atlas_
    object and wouldn't need to do any additional mapping. For example:

    var obj = {
    name: "Jim",
    frame: {/*first*/x:0,y:0,w:0,h:0},
    live: 100 };

    This file may be patched with _patchatlas_ like this:

    $ ./mkatlas img/* | ./patchatlas index.html

    Switches
    --------

    There are a few variables for fine tuning.
    Just put them before invocation, e.g.:

  12. @markusfisch markusfisch revised this gist Sep 9, 2013. 2 changed files with 30 additions and 2 deletions.
    26 changes: 26 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -37,6 +37,32 @@ This file may be patched with _patchatlas_ like this:

    $ ./mkatlas img/* | ./patchatlas index.html

    Switches
    --------

    There are a few variables for fine tuning.
    Just put them before invocation, e.g.:

    $ BORDER=0 ATLAS=atlas.jpg ./mkatlas img/*

    WIDTH
    Maximum width of atlas. Default is 2048.

    HEIGHT
    Maximum height of atlas. Default is 2048.

    BORDER
    Padding around sprites. If you intend to scale the atlas, it's wise to have
    a padding because sampling will make sprites "bleed" out of their frame.
    Default is 2.

    ATLAS
    File name (and image format) of atlas image.

    PREFER_SMALLER
    Prefer smaller region for lay out if set. Sometimes this gives a smaller
    atlas. Just try.

    [1]: http://en.wikipedia.org/wiki/Bash_(Unix_shell)
    [2]: http://en.wikipedia.org/wiki/Texture_atlas
    [3]: http://www.imagemagick.org/
    6 changes: 4 additions & 2 deletions mkatlas
    Original file line number Diff line number Diff line change
    @@ -124,7 +124,7 @@ atlas_from_list()
    # compose images into atlas
    convert -size "${WIDTH}x${HEIGHT}" xc:transparent \
    `< $CACHE/args` \
    -strip -trim -bordercolor none -border 2 \
    -strip -trim -bordercolor none -border $BORDER \
    "${ATLAS:-atlas.png}"

    rm -rf $CACHE
    @@ -145,12 +145,14 @@ atlas_from_files()
    convert "$F" \
    -strip \
    -trim \
    -bordercolor none -border 2 \
    -bordercolor none -border $BORDER \
    "$TRIMMED/${F##*/}"
    done

    identify -format '%w %h %d/%f\n' "$TRIMMED/*" | atlas_from_list
    rm -rf $TRIMMED
    }

    readonly BORDER=${BORDER:-2}

    [ "$0" == "$BASH_SOURCE" ] && atlas_from_files "$@"
  13. @markusfisch markusfisch revised this gist Sep 8, 2013. 1 changed file with 7 additions and 2 deletions.
    9 changes: 7 additions & 2 deletions mkatlas
    Original file line number Diff line number Diff line change
    @@ -124,7 +124,8 @@ atlas_from_list()
    # compose images into atlas
    convert -size "${WIDTH}x${HEIGHT}" xc:transparent \
    `< $CACHE/args` \
    -strip -trim "${ATLAS:-atlas.png}"
    -strip -trim -bordercolor none -border 2 \
    "${ATLAS:-atlas.png}"

    rm -rf $CACHE
    }
    @@ -141,7 +142,11 @@ atlas_from_files()
    local F
    for F in "$@"
    do
    convert "$F" -strip -trim "$TRIMMED/${F##*/}"
    convert "$F" \
    -strip \
    -trim \
    -bordercolor none -border 2 \
    "$TRIMMED/${F##*/}"
    done

    identify -format '%w %h %d/%f\n' "$TRIMMED/*" | atlas_from_list
  14. @markusfisch markusfisch revised this gist Sep 4, 2013. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -37,6 +37,6 @@ This file may be patched with _patchatlas_ like this:

    $ ./mkatlas img/* | ./patchatlas index.html

    1: http://en.wikipedia.org/wiki/Bash_(Unix_shell)
    2: http://en.wikipedia.org/wiki/Texture_atlas
    3: http://www.imagemagick.org/
    [1]: http://en.wikipedia.org/wiki/Bash_(Unix_shell)
    [2]: http://en.wikipedia.org/wiki/Texture_atlas
    [3]: http://www.imagemagick.org/
  15. @markusfisch markusfisch created this gist Sep 4, 2013.
    42 changes: 42 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    mkatlas
    =======

    [BASH][1] script to build a [texture atlas][2] for small/medium web
    sites/games. Requires [ImageMagick][3].

    Usage
    -----

    ### Basic

    Just run

    $ ./mkatlas img/*

    which will create _atlas.png_ and outputs the corresponding sprite regions
    in JSON format:

    var atlas={
    first:{x:298,y:0,w:35,h:22},
    second:{x:254,y:0,w:44,h:33},
    ...
    }

    ### Advanced

    Alternatively you may use just markers in your JavaScript to insert the
    frame data in place. This way you wouldn't have to have a extra _atlas_
    object and wouldn't need to do any additional mapping. For example:

    var obj = {
    name: "Jim",
    frame: {/*first*/x:0,y:0,w:0,h:0},
    live: 100 };

    This file may be patched with _patchatlas_ like this:

    $ ./mkatlas img/* | ./patchatlas index.html

    1: http://en.wikipedia.org/wiki/Bash_(Unix_shell)
    2: http://en.wikipedia.org/wiki/Texture_atlas
    3: http://www.imagemagick.org/
    151 changes: 151 additions & 0 deletions mkatlas
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,151 @@
    #!/bin/bash

    # Horizontal cut
    atlas_cut_horizontal()
    {
    echo $(( X+$1 )) $Y $W $2 > $NODE/child0/rect
    echo $X $(( Y+$2 )) $NW $H > $NODE/child1/rect
    }

    # Vertical cut
    atlas_cut_vertical()
    {
    echo $X $(( Y+$2 )) $1 $H > $NODE/child0/rect
    echo $(( X+$1 )) $Y $W $NH > $NODE/child1/rect
    }

    # Insert image, packing algorithm from
    # http://www.blackpawn.com/texts/lightmaps/default.html
    #
    # @param 1 - image width
    # @param 2 - image height
    # @param 3 - image file
    atlas_insert()
    {
    if [ -d "$NODE/child0" ]
    then
    local N=$NODE

    NODE=$N/child0
    atlas_insert $1 $2 $3 && return 0

    NODE=$N/child1
    atlas_insert $1 $2 $3 && return 0

    return 1
    fi

    [ -f $NODE/rect ] || return 1

    local X Y NW NH
    read X Y NW NH < $NODE/rect

    if (( $1 > NW )) || (( $2 > NH ))
    then
    return 1
    fi

    local W=$(( NW-$1 ))
    local H=$(( NH-$2 ))

    mkdir $NODE/child0 $NODE/child1

    if (( H > W ))
    then
    if (( PREFER_SMALLER ))
    then
    atlas_cut_vertical $1 $2
    else
    atlas_cut_horizontal $1 $2
    fi
    else
    if (( PREFER_SMALLER ))
    then
    atlas_cut_horizontal $1 $2
    else
    atlas_cut_vertical $1 $2
    fi
    fi

    echo $X $Y $1 $2 $3 > $NODE/image

    return 0
    }

    # Create texture atlas from a listing in the format "width height filename"
    atlas_from_list()
    {
    local CACHE
    CACHE=`mktemp -d ${0##*/}.XXXXXXXXXX` || return 1

    local WIDTH=${WIDTH:-2048}
    local HEIGHT=${HEIGHT:-2048}
    echo 0 0 $WIDTH $HEIGHT > $CACHE/rect

    # sort files and insert them into the atlas
    local MAX W H FILE
    while read W H FILE
    do
    [ "$FILE" ] || continue

    if (( W > H ))
    then
    MAX=$W
    else
    MAX=$H
    fi

    printf '%08d %d %d %s\n' $MAX $W $H $FILE
    done | sort -r | while read MAX W H FILE
    do
    local NODE=$CACHE
    atlas_insert $W $H $FILE || {
    echo 'error: canvas too small' >&2
    break
    }
    done

    # print JSON and build arguments for convert
    echo "var atlas={"

    find $CACHE -type f -name image | while read
    do
    local X Y W H FILE
    read X Y W H FILE < $REPLY

    echo "$FILE -geometry +$X+$Y -composite" >> $CACHE/args

    local NAME=${FILE##*/}
    echo "${NAME%.*}:{x:$X,y:$Y,w:$W,h:$H},"
    done

    echo "};"

    # compose images into atlas
    convert -size "${WIDTH}x${HEIGHT}" xc:transparent \
    `< $CACHE/args` \
    -strip -trim "${ATLAS:-atlas.png}"

    rm -rf $CACHE
    }

    # Create texture atlas
    #
    # @param ... - image files
    atlas_from_files()
    {
    local TRIMMED
    TRIMMED=`mktemp -d ${0##*/}.XXXXXXXXXX` || return 1

    # trim input files first
    local F
    for F in "$@"
    do
    convert "$F" -strip -trim "$TRIMMED/${F##*/}"
    done

    identify -format '%w %h %d/%f\n' "$TRIMMED/*" | atlas_from_list
    rm -rf $TRIMMED
    }

    [ "$0" == "$BASH_SOURCE" ] && atlas_from_files "$@"
    38 changes: 38 additions & 0 deletions patchatlas
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,38 @@
    #!/bin/bash

    # Patch given JavaScript files with JSON read from stdin
    #
    # @param ... - JavaScript files to patch
    atlas_patch()
    {
    (( $# < 1 )) && {
    echo "usage: ${0##*/} FILE..."
    return 1
    }

    while read
    do
    case $REPLY in
    *:{*)
    ;;
    *)
    continue
    ;;
    esac

    local NAME=${REPLY%%:\{*}

    [ "$NAME" ] || continue

    local FRAME=${REPLY#*\{}
    local PATCH="s^{/\*${NAME}\*/[\"xywh:0-9,]*}^{/*${NAME}*/${FRAME%,}^g"
    local TMP=".${0##*/}-$$.tmp"
    local SRC
    for SRC in "$@"
    do
    sed -e "$PATCH" < $SRC > $TMP && mv $TMP $SRC
    done
    done
    }

    [ "$0" == "$BASH_SOURCE" ] && atlas_patch "$@"