Sun-Valley-ttk-theme icon indicating copy to clipboard operation
Sun-Valley-ttk-theme copied to clipboard

Merge control images into a single sprite sheet?

Open TransparentLC opened this issue 2 years ago • 6 comments

This theme is really helpful to make a GUI application with modern style. I have already used it in my personal projects!

The theme's controls are made up of hundreds of png images, and I think that lots of tiny files might be a little unfriendly to hard drive and compression. So I tried to merge these images into a single sprite sheet (the following image) and it works great. This is a small enhancement and may be useful for distributing the theme with GUI applications since the users generally don't need to modify these images.

sprites

(I put the light and dark theme together)

merged.zip

The zip archive contains the following files:

  • sprites.png The merged sprite sheet image. It can be created with TexturePacker (non-free) or Free texture packer (free and open-source).
  • sprites.json The sprite sheet image's metadata in "JSON (array)" format.
  • extract.py Reads the metadata and generates tcl code to load separate files from the sprite sheet. The code replaces load_images.
  • sun-valley.tcl Modified tcl code.

TransparentLC avatar May 05 '22 16:05 TransparentLC

Looks really cool! thanks!

I'll look more into it, when I have more time.

rdbende avatar May 13 '22 19:05 rdbende

Just tried it out. WOW!

rdbende avatar May 13 '22 19:05 rdbende

Free texture packer uses Max Rects Packer written in JS to get the images' position (x, y, w, h) in packed sprite sheet. So the sprite sheet and tcl code can be generated programmatically.

I suggest using GitHub Actions to generate the sprite sheet and modified tcl code automatically then upload them as artifacts and I'm glad to make a pull request if you need. The problem is how can I replace the load_images in a cleaner way than keyword/regex substitution?

TransparentLC avatar May 14 '22 01:05 TransparentLC

will you be updating the pypi package sv_ttk with this change?

onyx-and-iris avatar May 27 '22 14:05 onyx-and-iris

I need to investigate this a bit more, but then yes.

rdbende avatar May 27 '22 15:05 rdbende

My Node.js script to generate the sprite sheet (then compress with TinyPNG) and tcl code that replaces load_images:

package.json
{
    "type": "module",
    "dependencies": {
        "maxrects-packer": "^2.7.3",
        "sharp": "^0.30.5"
    }
}
pack.js
import fs from 'fs';
import path from 'path';
import sharp from 'sharp';
import { MaxRectsPacker } from 'maxrects-packer';

for (const theme of ['dark', 'light']) {
    const packer = new MaxRectsPacker(Infinity, Infinity, 0, {
        pot: false,
        square: true,
    });
    packer.addArray(await Promise.all(fs.readdirSync(theme).map(async f => {
        const p = path.join(theme, f);
        const { width, height } = await sharp(p).metadata();
        const imagePath = path.join(theme, f);
        return {
            width,
            height,
            imagePath,
        };
    })));

    const packedBin = packer.bins[0];

    const packedImage = await sharp({
        create: {
            width: packedBin.width,
            height: packedBin.height,
            channels: 4,
            background: 'transparent',
        },
    })
        .composite(packedBin.rects.map(e => ({
            input: e.imagePath,
            left: e.x,
            top: e.y,
        })))
        .png({
            compressionLevel: 9,
        })
        .toBuffer();

    try {
        const shrinked = (await fetch('https://tinypng.com/web/shrink', {
            method: 'post',
            body: packedImage,
            headers: {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko',
                'X-Forwarded-For': Array(4).fill().map(() => Math.floor(Math.random() * 256)).join('.'),
            },
        }).then(r => r.json())).output.url;
        fs.writeFileSync(`${theme}.png`, Buffer.from((await fetch(shrinked).then(r => r.arrayBuffer()))));
    } catch (err) {
        console.log('Failed to minify with TinyPNG.', err);
        fs.writeFileSync(`${theme}.png`, packedImage);
    }

    fs.writeFileSync(`${theme}.packed.tcl`, [
        'variable images',
        `variable s [image create photo -file [file join [file dirname [info script]] ${theme}.png] -format png]`,
        `foreach {k x y w h} [list ${packedBin.rects.map(e => `${path.parse(e.imagePath).name} ${e.x} ${e.y} ${e.width} ${e.height}`).join(' ')}] {`,
        '    set images($k) [image create photo -width $w -height $h]',
        '    $images($k) copy $sprites -from $x $y [expr {$x+$w}] [expr {$y+$h}]',
        '}',
        'unset s',
    ].join('\n'));
}

Generated tcl code example:

variable images
variable s [image create photo -file [file join [file dirname [info script]] light.png] -format png]
foreach {k x y w h} [list card 0 0 50 50 notebook-border 50 0 40 40 ...] {
    set images($k) [image create photo -width $w -height $h]
    $images($k) copy $sprites -from $x $y [expr {$x+$w}] [expr {$y+$h}]
}
unset s

TransparentLC avatar May 28 '22 09:05 TransparentLC

@TransparentLC Just wanna let you know that this is almost finished together with some bugfixes, I just need to do some cleanup in the theme files, and then I'll make a new release. Probably I'll use this in my Azure and Forest theme as well.

rdbende avatar Sep 04 '22 08:09 rdbende

This will be an awesome update! Thanks both of you.

onyx-and-iris avatar Sep 06 '22 13:09 onyx-and-iris

@TransparentLC Just wanna let you know that this is almost finished together with some bugfixes, I just need to do some cleanup in the theme files, and then I'll make a new release. Probably I'll use this in my Azure and Forest theme as well.

Shit, I lost all my edits somewhere on my computer. I remember, it was in some totally random folder, and I didn't commit my changes, and now I can't find it. I'm so angry 🤬🤬🤬

rdbende avatar Sep 10 '22 20:09 rdbende

Never mind, after 45 minutes of searching I found them inside the trash, deleted from ~/Themes/ttk_themes/Theme/sv_theme. Sheesh... 😌

rdbende avatar Sep 10 '22 20:09 rdbende

@TransparentLC Huge thanks for all this! 👏🎉

Version 2 is now out: #47

rdbende avatar Sep 11 '22 11:09 rdbende