电子邮件中的倒计时计时器图片 GIF

38

我最近收到了来自Onnit Labs的电子邮件,其中包含一个使用GIF图像的倒计时模块定时器。可以在此处查看该电子邮件:https://www.onnit.com/emails/lastchance-historic/

图片如下:

enter image description here

我研究了一下,似乎可以使用 gifsockets 将新帧发送到动画 GIF 中,因为在加载到浏览器中时,GIF 并未规定有多少帧。在这里可以找到它的github页面:http://github.com/videlalvaro/gifsockets

我认为这非常有趣,也是一种很酷的效果。是否有人对如何实现这个功能有其他见解?看起来Onnit正在使用的方法似乎会根据URL或图像末尾添加的日期更改倒计时。

onnit.com/emails/_modules/timer/?end=2012-12-27+00:00:00&dark=1

我正在尝试在电子邮件中实现相同的功能,但我有些困惑。


似乎应该可以正常工作 - 只需发送一个带有<img>标签的HTML电子邮件,其中'src'属性引用URL。只要电子邮件阅读器正确呈现HTML,无论URL是由邮件阅读器还是浏览器访问,都不应该有问题。 - GreyBeardedGeek
1
我下載了它生成的gif,只得到了60幀,這也許是他們所需要的全部? 郵件有多長? 你會花超過60秒的時間看完嗎? - SeanJA
我也在浏览器中打开了一段时间,似乎已经失去了时间轨迹(我重新加载后,时间减少了4分钟)。 - SeanJA
@GreyBeardedGeek 嗯,如果我使用他们的URL来托管图像,那么它会起作用,就像你说的那样,我只需将其包含在<img>标记中即可。我正在尝试使用自己的图像来完成这个操作。我该如何创建类似的东西? - alvaram
@SeanJA 这个gif是无限的,取决于在参数中添加到URL末尾的内容。 ?end=2012-12-27+00:00:00 对我来说,它似乎能够很好地跟踪时间。而且,我已经重新加载了它。 - alvaram
4个回答

37

虽然可能使用 gifsockets (我以前没有尝试过...)也可以,但是当我查看图片时,除了初始图像加载外,没有网络流量。 我还看到它从41跳到了42。重新加载将其降到39。

这似乎只是一个脚本,它生成60帧动画并将其发送给用户。 这可能可以用任何语言完成。

以下是php的实现方式:

http://seanja.com/secret/countdown/

输入图像描述


1
这很方便 ;)。不幸的是,您需要多次使用类似以下代码的imagettftext:https://gist.github.com/4165467 - SeanJA
这太棒了!然而,这个计时器上的分钟数也在来回跳动。 - Jeremiah Prummer
如果他们在半分钟内打开它,他们会这样做吗?如果你想的话,你可以在代码中配置它仅反向计算那么多秒。 - SeanJA
PHP代码似乎有一个错误。我在整点前几秒钟加载了倒计时页面,它从“0天16小时0分钟17秒”倒数到“0天16小时-1分钟17秒”或类似的时间。 - seanf
1
SeanJA,你的回答太棒了,这就是为什么我一段时间前就点赞了。我还进行了一些改进,你可能会喜欢:https://dev59.com/3mYr5IYBdhLWcg3wi6vd#58250565 我想知道你是否知道如何支持透明度?谢谢。 - Ryan
显示剩余3条评论

4

免费版本也没有品牌标识,这很好。 - James

0
您可以尝试使用http://makedreamprofits.com/pt/。与向GIF提供附加内容不同,此倒计时动画被分成单独的图像,并且在不增加太多流量的情况下可以持续计时长达20分钟。
附注:Gmail正在预加载图片,因此无法无限制地为其提供新帧。

是的,这个答案来自2012年,那时还没有gmail缓存图片,现在套接字可能是更好的答案了...我已经多年没关注过这个了。 - SeanJA

0

我非常感激Sean Ja的回答。(他应该得到更多的赞。)然后我想让代码更易读和可配置(并支持透明gif上的文本并自动居中文本):

use Carbon\Carbon;
class CountdownGifHelper {

    const DELAY = 100; /* Why was this labeled as 'milliseconds' when it seems like a value of 100 here causes 1 frame to be shown per second? */
    const MAX_FRAMES = 120;

    /**
     * 
     * @param string $bgImg
     * @param \DateInterval $interval
     * @param array $fontArr
     * @param array $frames
     * @param array $delays
     * @param string $format
     */
    public function addFrame($bgImg, $interval, $fontArr, &$frames, &$delays, $format) {
        $image = imagecreatefrompng($bgImg); //Each frame needs to start by creating a new image because otherwise the new numbers would draw on top of old ones. Here, it doesn't really matter what the PNG is (other than for size) because it's about to get filled with a new color.
        $text = $interval->format($format);
        ob_start();
        imageSaveAlpha($image, true);
        $backgroundColor = $fontArr['backgroundColor'];
        imagefill($image, 0, 0, $backgroundColor); //https://dev59.com/mXPYa4cB1Zd3GeqPfBxr#17016252 was a helpful hint
        imagecolortransparent($image, $backgroundColor);
        $this->insertCenteredText($image, $fontArr, $text);
        //imagettftext($image, $font['size'], $font['angle'], $font['x-offset'], $font['y-offset'], $font['color'], $font['file'], $text);//this was the old way
        imagegif($image); //The image format will be GIF87a unless the image has been made transparent with imagecolortransparent(), in which case the image format will be GIF89a.
        $frames[] = ob_get_contents();
        ob_end_clean();
        $delays[] = self::DELAY;
    }

    /**
     * 
     * @param resource $image
     * @param array $fontArray
     * @param string $text
     */
    public function insertCenteredText(&$image, $fontArray, $text) {
        $image_width = imagesx($image);
        $image_height = imagesy($image);
        $text_box = imagettfbbox($fontArray['size'], $fontArray['angle'], $fontArray['file'], $text); // Get Bounding Box Size
        $text_width = $text_box[2] - $text_box[0];
        $text_height = $text_box[7] - $text_box[1];
        // Calculate coordinates of the text https://dev59.com/9WUq5IYBdhLWcg3waPtC#14517450
        $x = ($image_width / 2) - ($text_width / 2);
        $y = ($image_height / 2) - ($text_height / 2);
        imagettftext($image, $fontArray['size'], $fontArray['angle'], $x, $y, $fontArray['color'], $fontArray['file'], $text);
    }

    /**
     * 
     * @param int $timestamp
     * @param string $bgImg
     * @param array $fontArray
     * @return string [can be used by Laravel response()->make($gifString, 200, $headers)]
     */
    public function getAnimatedGif($timestamp, $bgImg, $fontArray) {
        $future_date = Carbon::createFromTimestamp($timestamp);
        $time_now = time();
        $moment = new \DateTime(date('r', $time_now));
        $frames = [];
        $delays = [];
        for ($i = 0; $i <= self::MAX_FRAMES; $i++) {
            $interval = date_diff($future_date, $moment);
            if ($future_date < $moment) {
                $this->addFrame($bgImg, $interval, $fontArray, $frames, $delays, '00 : 00 : 00');
                $loops = 1; //stay stuck on this frame
                break;
            } else {
                $this->addFrame($bgImg, $interval, $fontArray, $frames, $delays, '%H : %I : %S');
                $loops = 0; //infinite loop
            }
            $moment->modify('+1 second');
        }
        $animatedGif = new \App\Helpers\AnimatedGif($frames, $delays, $loops, 0, 0, 0);
        return $animatedGif->getAnimation();
    }

    /**
     * ONEDAY allow config via params
     * @param resource $image
     * @return array
     */
    public function getFontArray($image) {
        $fontArr = [
            'file' => resource_path('assets/fonts/Kanit-Regular.ttf'),
            'size' => 30,
            //'x-offset' => 5,
            //'y-offset' => 30,
            'color' => imagecolorallocate($image, 90, 90, 90), //gray
            'backgroundColor' => imagecolorallocate($image, 0, 0, 0), //white. Must match the arguments provided to AnimatedGif (such as 0,0,0).
            'angle' => 0,
        ];
        return $fontArr;
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接