为啥微信添加个动态表情这么难?

每每看到好玩 gif 想要跟基友分享,结果发过去就成了死图。搜了半天才知道,要添加到微信表情才可以,照着添加了,结果又提示 “所选图片太大”!!!
What the f**?我只是单纯的想分享一张 gif 动图,咋还生出这么多幺蛾子。

拿 Graphics-Magic 练练手,程序中会多次尝试缩放直到结果 1M以下。

#include <cassert>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>

#include <boost/format.hpp>
#include <gflags/gflags.h>
#include <Magick++.h> 

DEFINE_int32(max_size, 1024, "output file size in Kb");
DEFINE_string(in, "", "input image filename");
DEFINE_string(out, "", "output image filename");
DEFINE_int32(retry, 3, "max retry times");
//DEFINE_int32(depth, 8, "output image depth");
//DEFINE_int32(quality, 75, "output image quality");

int read_image_vec(const std::string& filename, std::vector<Magick::Image>& image_vec) {
    assert(image_vec.empty());
    try {
        Magick::readImages(&image_vec, filename);
    } catch (Magick::Warning &warning) {
        std::cerr << warning.what() << std::endl;
    } catch (Magick::Error &error) {
        std::cerr << error.what() << std::endl;
    }

    return !image_vec.empty() && image_vec.front().isValid() ? 0 : 1;
}

Magick::Geometry image_vec_page(const std::vector<Magick::Image>& image_vec) {
    assert(!image_vec.empty());
    Magick::Geometry max_page(0, 0);
    for (const auto& image : image_vec) {
        auto page = image.page();
        if (page.width() > max_page.width()) {
            max_page.width(page.width());
        }
        if (page.height() > max_page.height()) {
            max_page.height(page.height());
        }
    }
    return max_page;
}

Magick::Geometry image_vec_size(const std::vector<Magick::Image>& image_vec) {
    assert(!image_vec.empty());
    Magick::Geometry max_size(0, 0);
    for (const auto& image : image_vec) {
        auto size = image.size();
        if (size.width() > max_size.width()) {
            max_size.width(size.width());
        }
        if (size.height() > max_size.height()) {
            max_size.height(size.height());
        }
    }
    return max_size;
}

double guess_resize_ratio(const off_t src_file_size,
                          const off_t max_file_size) {
    static double FILE_SIZE_RATIO = 1.0;
    FILE_SIZE_RATIO = std::max(0.5, FILE_SIZE_RATIO - 0.1);
    return sqrt(max_file_size * FILE_SIZE_RATIO / src_file_size);
}

void image_vec_resize(std::vector<Magick::Image>& image_vec, const double ratio) {
    assert(!image_vec.empty());
    assert(ratio > 0);

    for (auto& image : image_vec) {
        auto page = image.page();

        auto size = image.size();
        size.width(size.width() * ratio);
        size.height(size.height() * ratio);
        image.thumbnail(size);

        page.width(page.width() * ratio);
        page.height(page.height() * ratio);
        page.xOff(page.xOff() * ratio);
        page.yOff(page.yOff() * ratio);
        image.page(page);
    }
}

size_t image_vec_encode(std::vector<Magick::Image>& image_vec, Magick::Blob& blob) {
    assert(!image_vec.empty());

    /*
    for (auto& image : image_vec) {
        if (image.depth() > FLAGS_depth) {
            image.depth(FLAGS_depth);
        }

        if (image.quality() > FLAGS_quality) {
            image.quality(FLAGS_quality);
        }

        //image.type(Magick::OptimizeType);
    }
    */

    writeImages(image_vec.begin(), image_vec.end(), &blob);
    return blob.length();
}

int main(int argc, char** argv) {
    google::SetVersionString("1.0.0.0");
    google::ParseCommandLineFlags(&argc, &argv, true);

    Magick::InitializeMagick("./");

    std::vector<Magick::Image> image_vec;
    if (0 != read_image_vec(FLAGS_in, image_vec)) {
        std::cerr << "read input error" << std::endl;
        return -1;
    }

    std::cout << boost::format("frame: %1%") % image_vec.size() << std::endl;

    auto src_page = image_vec_page(image_vec);
    if (!src_page.isValid()) {
        std::cerr << boost::format("invalid page: %1%x%2%") % src_page.width() % src_page.height()
                  << std::endl;
        return -1;
    }
    std::cout << boost::format("page: %1%x%2%") % src_page.width() % src_page.height()
              << std::endl;

    auto src_file_size = image_vec.front().fileSize();
    std::cout << boost::format("fileSize: %1%") % src_file_size << std::endl;

    off_t max_file_size = FLAGS_max_size * 1024;
    if (src_file_size <= max_file_size) {
        std::cout << "max_size no more than source file size, no need to resize" << std::endl;
        return 0;
    }

    // strip
    for_each(image_vec.begin(), image_vec.end(), Magick::stripImage());

    for (auto i = 0; i < FLAGS_retry; ++i) {
        std::cout << boost::format("try the %1% time") % (i + 1) << std::endl;
        std::cout << boost::format("    src page: %1%x%2%  fileSize: %3%")
                                   % src_page.width() % src_page.height()
                                   % src_file_size
                  << std::endl;
        auto ratio = guess_resize_ratio(src_file_size, max_file_size);
        image_vec_resize(image_vec, ratio);
        Magick::Blob blob;
        auto dst_file_size = image_vec_encode(image_vec, blob);
        auto dst_page = image_vec_page(image_vec);
        std::cout << boost::format("    dst page: %1%x%2%  fileSize: %3%")
                                   % dst_page.width() % dst_page.height()
                                   % dst_file_size
                  << std::endl;
        if (dst_file_size <= max_file_size) {
            std::ofstream ofs(FLAGS_out, std::ostream::out);
            ofs.write(static_cast<const char*>(blob.data()), blob.length());
            return 0;
        } else {
            src_file_size = dst_file_size;
            src_page = dst_page;
        }
    }

    std::cerr << "convert faild" << std::endl;
    return -1;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容