JSON-based controller descriptions
[lsnes.git] / src / library / png.cpp
blobc67eaf4f1ac1ac11003f2c4deccf00bad89b7ace
1 #include "png.hpp"
3 #include <fstream>
4 #include <iostream>
5 #include <cstdint>
6 #include <zlib.h>
7 #include <boost/iostreams/categories.hpp>
8 #include <boost/iostreams/copy.hpp>
9 #include <boost/iostreams/stream.hpp>
10 #include <boost/iostreams/stream_buffer.hpp>
11 #include <boost/iostreams/filter/symmetric.hpp>
12 #include <boost/iostreams/filter/zlib.hpp>
13 #include <boost/iostreams/filtering_stream.hpp>
14 #include <boost/iostreams/device/back_inserter.hpp>
16 namespace
18 void encode32(char* _buf, uint32_t val) throw()
20 unsigned char* buf = reinterpret_cast<unsigned char*>(_buf);
21 buf[0] = ((val >> 24) & 0xFF);
22 buf[1] = ((val >> 16) & 0xFF);
23 buf[2] = ((val >> 8) & 0xFF);
24 buf[3] = (val & 0xFF);
27 class png_hunk_output
29 public:
30 typedef char char_type;
31 struct category : boost::iostreams::closable_tag, boost::iostreams::sink_tag {};
32 png_hunk_output(std::ostream& _os, uint32_t _type)
33 : os(_os), type(_type)
37 void close()
39 uint32_t crc = crc32(0, NULL, 0);
40 char fixed[12];
41 encode32(fixed, stream.size());
42 encode32(fixed + 4, type);
43 crc = crc32(crc, reinterpret_cast<Bytef*>(fixed + 4), 4);
44 if(stream.size() > 0)
45 crc = crc32(crc, reinterpret_cast<Bytef*>(&stream[0]), stream.size());
46 encode32(fixed + 8, crc);
47 os.write(fixed, 8);
48 os.write(&stream[0], stream.size());
49 os.write(fixed + 8, 4);
52 std::streamsize write(const char* s, std::streamsize n)
54 size_t oldsize = stream.size();
55 stream.resize(oldsize + n);
56 memcpy(&stream[oldsize], s, n);
57 return n;
59 protected:
60 std::vector<char> stream;
61 std::ostream& os;
62 uint32_t type;
66 void save_png_data(const std::string& file, uint8_t* data24, uint32_t width, uint32_t height) throw(std::bad_alloc,
67 std::runtime_error)
69 char* data = reinterpret_cast<char*>(data24);
70 std::ofstream filp(file.c_str(), std::ios_base::binary);
71 if(!filp)
72 throw std::runtime_error("Can't open target PNG file");
73 char png_magic[] = {-119, 80, 78, 71, 13, 10, 26, 10};
74 filp.write(png_magic, sizeof(png_magic));
75 char ihdr[] = {25, 25, 25, 25, 25, 25, 25, 25, 8, 2, 0, 0, 0};
76 boost::iostreams::stream<png_hunk_output> ihdr_h(filp, 0x49484452);
77 encode32(ihdr, width);
78 encode32(ihdr + 4, height);
79 ihdr_h.write(ihdr, sizeof(ihdr));
80 ihdr_h.close();
82 boost::iostreams::filtering_ostream idat_h;
83 boost::iostreams::zlib_params params;
84 params.noheader = false;
85 idat_h.push(boost::iostreams::zlib_compressor(params));
86 idat_h.push(png_hunk_output(filp, 0x49444154));
87 for(uint32_t i = 0; i < height; i++) {
88 char identity_filter = 0;
89 idat_h.write(&identity_filter, 1);
90 idat_h.write(data + i * 3 * width, 3 * width);
92 idat_h.pop();
93 idat_h.pop();
95 boost::iostreams::stream<png_hunk_output> iend_h(filp, 0x49454E44);
96 iend_h.close();
97 if(!filp)
98 throw std::runtime_error("Can't write target PNG file");