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

每每看到好玩 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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容