Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <vector>
- #include <cstdio>
- // PNGencoder: A minimal PNG encoder for demonstration purposes.
- class PNGencoder
- {
- std::vector<unsigned char> output;
- private:
- static void PutWord(unsigned char* target, unsigned dword, bool msb_first)
- {
- for(int p=0; p<4; ++p) target[p] = dword >> (msb_first ? 24-p*8 : p*8);
- }
- static unsigned adler32(const unsigned char* data, unsigned size, unsigned res=1)
- {
- for(unsigned s1,a=0; a<size; ++a)
- s1 = ((res & 0xFFFF) + (data[a] & 0xFF)) % 65521,
- res = s1 + ((((res>>16) + s1) % 65521) << 16);
- return res;
- }
- static unsigned crc32(const unsigned char* data, unsigned size, unsigned res=0)
- {
- for(unsigned tmp,n,a=0; a<size; ++a, res = ~((~res>>8) ^ tmp))
- for(tmp = (~res ^ data[a]) & 0xFF, n=0; n<8; ++n)
- tmp = (tmp>>1) ^ ((tmp&1) ? 0xEDB88320u : 0);
- return res;
- }
- void Deflate(const unsigned char* source, unsigned srcsize)
- {
- /* A bare-bones deflate-compressor (as in gzip) */
- int algo=8, windowbits=8 /* 8 to 15 allowed */, flevel=0 /* 0 to 3 */;
- /* Put RFC1950 header: */
- unsigned h0 = algo + (windowbits-8)*16, h1 = flevel*64 + 31-((256*h0)%31);
- output.push_back(h0);
- output.push_back(h1); /* checksum and compression level */
- /* Compress data using a lossless algorithm (RFC1951): */
- for(unsigned begin=0; ; )
- {
- unsigned eat = std::min(65535u, srcsize-begin);
- std::size_t o = output.size(); output.resize(o+5);
- output[o+0] = (begin+eat) >= srcsize; /* bfinal bit and btype: 0=uncompressed */
- PutWord(&output[o+1], eat|(~eat<<16), false);
- output.insert(output.end(), source+begin, source+begin+eat);
- begin += eat;
- if(begin >= srcsize) break;
- }
- /* After compressed data, put the checksum (adler-32): */
- std::size_t o = output.size(); output.resize(o+4);
- PutWord(&output[o], adler32(source, srcsize), true);
- }
- public:
- void EncodeImage(unsigned width,unsigned height, const unsigned char* rgbdata)
- {
- std::size_t o;
- #define BeginChunk(n_reserve_extra) o = output.size(); output.resize(o+8+n_reserve_extra)
- #define EndChunk(type) do { \
- unsigned ncopy=output.size()-(o+8); \
- static const char t[4+1] = type; \
- output.resize(o+8+ncopy+4); \
- PutWord(&output[o+0], ncopy, true); /* chunk length */ \
- std::copy(t+0, t+4, &output[o+4]); /* chunk type */ \
- /* in the chunk, put crc32 of the type and data (below) */ \
- PutWord(&output[o+8+ncopy], crc32(&output[o+4], 4+ncopy), true); \
- } while(0)
- /* Put PNG header (always const) */
- static const char header[8+1] = "\x89PNG\15\12\x1A\12";
- output.insert(output.end(), header, header+8);
- /* Put IHDR chunk */
- BeginChunk(13);
- PutWord(&output[o+8+0], width, true); /* Put image width */
- PutWord(&output[o+8+4], height, true); /* and height in IHDR */
- PutWord(&output[o+8+8], 0x08020000, true);
- /* Meaning of above: 8-bit,rgb-triple,deflate,std filters,no interlacing */
- EndChunk("IHDR");
- /* Put IDAT chunk */
- BeginChunk(0);
- std::vector<unsigned char> idat;
- for(unsigned y=0; y<height; ++y)
- {
- idat.push_back(0x00); // filter type for this scanline
- idat.insert(idat.end(), rgbdata+y*width*3, rgbdata+y*width*3+width*3);
- }
- Deflate(&idat[0], idat.size());
- EndChunk("IDAT");
- /* Put IEND chunk */
- BeginChunk(0);
- EndChunk("IEND");
- #undef BeginChunk
- #undef EndChunk
- }
- void SaveTo(const char* fn)
- {
- std::FILE* fp = std::fopen(fn, "wb");
- if(!fp) { std::perror(fn); return; }
- std::fwrite(&output[0], 1, output.size(), fp);
- std::fclose(fp);
- }
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement