Пишу, по большей части, про историю, свою жизнь и немного про программирование.

Часы без JavaScript: фильм о фильме

Как уже догадались все, кому это было хоть каплю интересно, часы без JavaScript сделаны анимированным GIF. Сделал я всё очень просто: скачал найденный где-то на FTP шрифт «clock.ttf», внутри которого вместо букв нарисованы стрелки в разных положениях и сгенерировал с его помощью 720 картинок.

Шрифт clock (27.08КиБ)

Оказалось, что проще всего сгенерировать картинки при помощи Go. В Пайтоне на «Маке» у меня нет PIL и я его плохо знаю, во встроенном PHP нет поддержки TTF, так что Go:

package main

import "gd"
import "os"
import "fmt"

func main() {
    im := gd.CreateTrueColor(21, 21)
    white := im.ColorAllocate(255, 255, 255)
    black := im.ColorAllocate(0, 0, 0)
    
    // стрелки: 64 → 123 (m) и 192 → 251 (h)

    defer im.Destroy()
        
    for i := 0; i < 720; i++ {
        im.FilledRectangle(0, 0, 20, 20, white)
        
        min  := i % 60
        hour := (i / 60) * 5 + min / 12
        
        im.StringFT(black, "./clock.ttf", 10, 0, 0, 16, "1")
        im.StringFT(black, "./clock.ttf", 10, 0, 0, 16, string(hour + 192))
        im.StringFT(black, "./clock.ttf", 10, 0, 0, 16, string(min + 64))

        name := fmt.Sprintf("gifs/%02d%02d.gif", i/60, i%60)
        im.Gif(name)
        
    }
    
}

После запуска получилось 720 картинок с ноль часов ноль минут до 11:59 (я не зря выбрал часы со стрелками, это позволило сократить размер анимированных часов вдвое).

Когда на сервер приходит запрос, я проверяю сколько сейчас времени и, если файл с часами для текущей минуты уже существует, то делаю редирект на существующую картинку. Если нет, то генерирую из 720 картинок новый «мультик», кладу его на диск и делаю редирект на него (остальные картинки удаляю):

<?
    include "clock.inc.php";
    
    list($h, $m) = explode(':', date('H:i'));
    if ($h > 12) $h -= 12;
    $name = sprintf("%02d%02d.gif", $h, $m);
    
    if (!file_exists($name)) {	
        @array_map('unlink', glob('*.gif'));
    
        $frames_tail = $frames = $framed = array();
        $frames_name = 'frames_tail';
    
        for ($H = 0; $H<12; $H++) {
            for ($M = 0; $M<60; $M++) {
                if ($h == $H && $m == $M) {
                    $frames_name = 'frames';
                }
            
                ${$frames_name}[] = sprintf("gifs/%02d%02d.gif", $H, $M);
                $framed[] = 100;
            }
        }
    
        $frames = array_merge($frames, $frames_tail);
    
        $gif = new GIFAnimator($frames, $framed, 0, 2, -1, -1, -1, 'url');
    
        fwrite(fopen($name, 'wb'), $gif->GetAnimation());
    }
    
    header("Location: $name");

Для генерации анимированных GIF применяется какой-то первый попавшийся в интернете класс, предназначенный для этого. Работает шустро.

8 комментариев
playpauseandstop (playpausenstop.livejournal.com) 2011

В Пайтоне на «Маке» у меня нет PIL

$ sudo easy_install pip
$ sudo pip install PIL

:) про аргумент, «я его плохо знаю» читал, но подумал может на будущее пригодиться

зы. chromium-14.0.792.0-2.1.i586, ctrl+enter не работает :(

Евгений Степанищев (bolknote.ru) 2011

Комментарий для playpausenstop.livejournal.com:

pip у меня нету, а easy_install есть. Но я его всё равно плохо знаю, а учить ради такой ерунды не хотелось :)

ninjacolumbo (ninjacolumbo.ya.ru) 2011

Вот ты псих, а!

Евгений Степанищев (bolknote.ru) 2011

Комментарий для ninjacolumbo.ya.ru:

:-D

profiles.google.com/gaius.julius 2011

Остаётся нераскрытым вопрос «Есть ли жизнь за пределом экрана». Точнее так: «крутятся ли анимированные гифки за пределами вьюпорта»?

В последний раз я проверял лет пять назад, и это сильно зависило от браузера.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для http://profiles.google.com/gaius.julius:

Надо попробовать. Сделать какой-нибудь гигантский GIF и попробовать.

profiles.google.com/gaius.julius 2011

Можно прямо на часах в этом посте пробовать (-:

Евгений Степанищев (bolknote.ru) 2011

Комментарий для http://profiles.google.com/gaius.julius:

Они у меня как-то не очень «Оперу» грузят, даже когда их видно.