cv2converter.zip/main.cpp
#define _SCL_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include <algorithm>
#include <array>
#include <string>
#include <png.h>
#include <zlib.h>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>
#include <boost/range.hpp>
#include <boost/range/irange.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <Windows.h>
struct Color {
public:
Color() {
}
Color(unsigned char r, unsigned char g, unsigned char b, unsigned char alpha) :
r(r), g(g), b(b), alpha(alpha)
{
}
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char alpha;
};
class UCharVectorO : boost::noncopyable {
private:
std::vector<unsigned char> &result;
public:
UCharVectorO(std::vector<unsigned char> &result) : result(result) {}
static void Write(png_struct *png, png_byte *data, png_size_t size) {
UCharVectorO * const out = reinterpret_cast<UCharVectorO *>(::png_get_io_ptr(png));
BOOST_ASSERT(out != NULL);
const unsigned int cur = out->result.size();
out->result.resize(cur + size);
std::copy(&data[0], &data[size], &out->result[cur]);
}
static void Flush(png_struct *png) {
}
};
class UCharVectorI : boost::noncopyable {
private:
const std::vector<unsigned char> &result;
unsigned int readIndex;
public:
UCharVectorI(const std::vector<unsigned char> &result) : result(result), readIndex(0) {}
static void Read(png_struct * const png, png_byte * const data, png_size_t size) {
UCharVectorI * const out = reinterpret_cast<UCharVectorI *>(::png_get_io_ptr(png));
if (out->readIndex + size > out->result.size()) {
size = out->result.size() - out->readIndex;
}
std::copy(out->result.begin() + out->readIndex, out->result.begin() + out->readIndex + size, data);
out->readIndex += size;
}
};
void png_write_struct_free(png_struct *png) {
::png_destroy_write_struct(&png, NULL);
}
void png_info_free(png_struct * const png, png_info *info) {
::png_destroy_info_struct(png, &info);
}
void png_read_struct_free(png_struct *png) {
::png_destroy_read_struct(&png, NULL, NULL);
}
bool toPng(unsigned int width, unsigned int height, const std::vector<Color> &data, std::vector<unsigned char> &result) {
const boost::shared_ptr<png_struct> png(::png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL), png_write_struct_free);
if (!png) {
return false;
}
const boost::shared_ptr<png_info> info(::png_create_info_struct(png.get()), boost::bind(png_info_free, png.get(), _1));
if (!info) {
return false;
}
result.clear();
UCharVectorO io(result);
::png_set_write_fn(png.get(), &io, UCharVectorO::Write, UCharVectorO::Flush);
::png_set_IHDR(png.get(), info.get(), width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE);
::png_write_info(png.get(), info.get());
std::vector<const png_byte *> rows(height);
for (unsigned int i = 0; i < height; i++) {
rows[i] = reinterpret_cast<const png_byte *>(&data[i * width]);
}
::png_write_image(png.get(), const_cast<png_byte **>(&rows.front()));
::png_write_end(png.get(), info.get());
return true;
}
bool fromPng(const std::vector<unsigned char> &data, std::vector<Color> &pixels, unsigned int &width, unsigned int &height) {
const std::unique_ptr<png_struct, void(*)(png_struct *)> png(::png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL), png_read_struct_free);
const std::unique_ptr<png_info, boost::function<void(png_info *)> > info(::png_create_info_struct(png.get()), boost::bind(png_info_free, png.get(), _1));
const std::unique_ptr<png_info, boost::function<void(png_info *)> > end(::png_create_info_struct(png.get()), boost::bind(png_info_free, png.get(), _1));
UCharVectorI io(data);
::png_set_read_fn(png.get(), &io, UCharVectorI::Read);
unsigned char signature[8];
UCharVectorI::Read(png.get(), signature, 8);
if (::png_sig_cmp(signature, 0, 8) != 0) {
return false;
}
::png_set_sig_bytes(png.get(), 8);
::png_read_png(png.get(), info.get(), PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_16, NULL);
width = ::png_get_image_width(png.get(), info.get());
height = ::png_get_image_height(png.get(), info.get());
const Color * const * const rows = reinterpret_cast<const Color * const *>(::png_get_rows(png.get(), info.get()));
pixels.resize(width * height);
for (unsigned int h : boost::irange(0U, height)) {
for (unsigned int w : boost::irange(0U, width)) {
pixels[h * width + w] = rows[h][w];
}
}
return true;
}
bool cv2ToPng(const std::vector<unsigned char> &data, std::vector<unsigned char> &result) {
const unsigned char cn = data[0];
const unsigned int w2 = *reinterpret_cast<const unsigned int *>(&data[1]);
const unsigned int h = *reinterpret_cast<const unsigned int *>(&data[5]);
const unsigned int w = *reinterpret_cast<const unsigned int *>(&data[9]);
if (h == 0 || w2 == 0) {
std::vector<Color> pixels(w2 * h);
return toPng(w2, h, pixels, result);
}
if (cn == 24 || cn == 32) {
std::vector<Color> pixels(w2 * h);
const unsigned char *p = &data[17];
for (unsigned int i = 0; i < w2 * h; i++) {
pixels[i].b = p[0];
pixels[i].g = p[1];
pixels[i].r = p[2];
pixels[i].alpha = p[3];
p += 4;
if (((i + 1) % w2) == 0) {
p += 4 * (w - w2);
}
}
return toPng(w2, h, pixels, result);
}
if (cn == 8) {
std::wcout << boost::wformat(L"palette型cv2は未対応です、空の画像で出力されます。\n");
std::vector<Color> palette;
// loadPalette(palette); TODO
std::vector<Color> pixels(h * w2);
const unsigned char *p = &data[17];
for (unsigned int i = 0; i < h*w2; i += w2, p+= w) {
for (unsigned int j : boost::irange(0U, w2)) {
pixels[i * w2 + j] = palette[*p];
}
}
return toPng(w2, h, pixels, result);
}
std::wcout << boost::wformat(L"未知の色数です、出力されません。\n");
return false;
}
bool pngToCv2(const std::vector<unsigned char> &data, std::vector<unsigned char> &result) {
std::vector<Color> pixels;
unsigned int width;
unsigned int height;
if (!fromPng(data, pixels, width, height)) {
return false;
}
result.resize(1 + 4 + 4 + 4 + 4 + (4 * pixels.size()));
result[0] = 32;
*reinterpret_cast<unsigned int *>(&result[1]) = width;
*reinterpret_cast<unsigned int *>(&result[5]) = height;
*reinterpret_cast<unsigned int *>(&result[9]) = width;
*reinterpret_cast<unsigned int *>(&result[13]) = 0;
std::vector<unsigned char>::iterator it = result.begin() + 17;
for (const Color &color : pixels) {
*it = color.b; it++;
*it = color.g; it++;
*it = color.r; it++;
*it = color.alpha; it++;
}
return true;
}
int main() {
std::locale loc = std::locale("japanese").combine<std::numpunct<char> >(std::locale::classic()).combine<std::numpunct<wchar_t> >(std::locale::classic());
std::locale::global(loc);
std::wcout.imbue(loc);
std::cout.imbue(loc);
int argc;
const wchar_t * const * const argv = ::CommandLineToArgvW(GetCommandLineW(), &argc);
for (const unsigned int i : boost::irange(1U, static_cast<unsigned int>(argc))) {
const boost::filesystem::path path = argv[i];
if (!boost::filesystem::is_regular_file(path)) {
std::wcout << boost::wformat(L"%sはファイルではありません。\n") % path;
continue;
}
const unsigned long long int fileSize = boost::filesystem::file_size(path);
boost::filesystem::ifstream ifs(path, boost::filesystem::ifstream::binary);
if (!ifs.is_open()) {
std::wcout << boost::wformat(L"%sを開けませんでした。\n") % path;
continue;
}
std::vector<unsigned char> in(fileSize);
ifs.read(reinterpret_cast<char *>(&in.front()), in.size());
ifs.close();
bool result = false;
std::vector<unsigned char> out;
boost::filesystem::path outPath = path;
if (path.extension() == L".cv2") {
result = cv2ToPng(in, out);
outPath.replace_extension(".png");
} else if (path.extension() == L".png") {
result = pngToCv2(in, out);
outPath.replace_extension(".cv2");
}
if (!result) {
std::wcout << boost::wformat(L"%sの変換に失敗しました。\n") % path;
continue;
}
boost::filesystem::ofstream ofs(outPath, boost::filesystem::ofstream::binary);
ofs.write(reinterpret_cast<const char *>(&out.front()), out.size());
ofs.close();
}
std::wcout << boost::wformat(L"全ての処理が終了しました。\n");
std::wcin.get();
return 0;
}