每每看到好玩 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;
}
网友评论