diff options
| author | Simon Robertshaw <simon@hardwired.org.uk> | 2012-11-17 19:44:09 (GMT) |
|---|---|---|
| committer | Simon Robertshaw <simon@hardwired.org.uk> | 2012-11-17 19:44:09 (GMT) |
| commit | 058a2edd75debbd0297f92572316daa704bd379f (patch) | |
| tree | ad303f091f9a08b209b91eb34a9fcad996a3de69 /src/Format.cpp | |
| parent | e3594aba9e05c6865d396418c028049cda92c2f3 (diff) | |
| parent | 7a21ae192fe19868539956f3fe28e62b2c7c4429 (diff) | |
| download | powder-058a2edd75debbd0297f92572316daa704bd379f.zip powder-058a2edd75debbd0297f92572316daa704bd379f.tar.gz | |
Merge branch 'master' of github.com:FacialTurd/PowderToypp
Diffstat (limited to 'src/Format.cpp')
| -rw-r--r-- | src/Format.cpp | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/src/Format.cpp b/src/Format.cpp new file mode 100644 index 0000000..5f9741d --- /dev/null +++ b/src/Format.cpp @@ -0,0 +1,369 @@ + +#include <ctime> +#include <string> +#include <stdexcept> +#include <iostream> +#include <iterator> +#include <zlib.h> +#include <stdio.h> +#include "Format.h" +#include "graphics/Graphics.h" + +std::string format::URLEncode(std::string source) +{ + char * src = (char *)source.c_str(); + char * dst = new char[(source.length()*3)+2]; + std::fill(dst, dst+(source.length()*3)+2, 0); + + char *d; + unsigned char *s; + + for (d=dst; *d; d++) ; + + for (s=(unsigned char *)src; *s; s++) + { + if ((*s>='0' && *s<='9') || + (*s>='a' && *s<='z') || + (*s>='A' && *s<='Z')) + *(d++) = *s; + else + { + *(d++) = '%'; + *(d++) = hex[*s>>4]; + *(d++) = hex[*s&15]; + } + } + *d = 0; + + std::string finalString(dst); + delete[] dst; + return finalString; +} + +std::string format::UnixtimeToDate(time_t unixtime, std::string dateFormat) +{ + struct tm * timeData; + char buffer[128]; + + timeData = localtime(&unixtime); + + strftime(buffer, 128, dateFormat.c_str(), timeData); + return std::string(buffer); +} + +std::string format::UnixtimeToDateMini(time_t unixtime) +{ + time_t currentTime = time(NULL); + struct tm currentTimeData = *localtime(¤tTime); + struct tm timeData = *localtime(&unixtime); + + if(currentTimeData.tm_year != timeData.tm_year) + { + return UnixtimeToDate(unixtime, "%b %Y"); + } + else if(currentTimeData.tm_mon != timeData.tm_mon || currentTimeData.tm_mday != timeData.tm_mday) + { + return UnixtimeToDate(unixtime, "%d %B"); + } + else + { + return UnixtimeToDate(unixtime, "%H:%M:%S"); + } +} + +std::vector<char> format::VideoBufferToPTI(const VideoBuffer & vidBuf) +{ + std::vector<char> data; + int dataSize = 0; + char * buffer = (char*)Graphics::ptif_pack(vidBuf.Buffer, vidBuf.Width, vidBuf.Height, &dataSize); + + if(buffer) + { + data.insert(data.end(), buffer, buffer+dataSize); + free(buffer); + } + + return data; +} + +std::vector<char> format::VideoBufferToPPM(const VideoBuffer & vidBuf) +{ + std::vector<char> data; + char buffer[256]; + sprintf(buffer, "P6\n%d %d\n255\n", vidBuf.Width, vidBuf.Height); + data.insert(data.end(), buffer, buffer+strlen(buffer)); + + unsigned char * currentRow = new unsigned char[vidBuf.Width*3]; + for(int y = 0; y < vidBuf.Height; y++) + { + int rowPos = 0; + for(int x = 0; x < vidBuf.Width; x++) + { + currentRow[rowPos++] = PIXR(vidBuf.Buffer[(y*vidBuf.Width)+x]); + currentRow[rowPos++] = PIXG(vidBuf.Buffer[(y*vidBuf.Width)+x]); + currentRow[rowPos++] = PIXB(vidBuf.Buffer[(y*vidBuf.Width)+x]); + } + data.insert(data.end(), currentRow, currentRow+(vidBuf.Width*3)); + } + delete currentRow; + + return data; +} + +struct PNGChunk +{ + int Length; + char Name[4]; + char * Data; + + //char[4] CRC(); + + PNGChunk(int length, std::string name) + { + if(name.length()!=4) + throw std::runtime_error("Invalid chunk name"); + std::copy(name.begin(), name.begin()+4, Name); + Length = length; + if(length) + { + Data = new char[length]; + std::fill(Data, Data+length, 0); + } + else + { + Data = NULL; + } + } + unsigned long CRC() + { + if(!Data) + { + return format::CalculateCRC((unsigned char*)Name, 4); + } + else + { + unsigned char * temp = new unsigned char[4+Length]; + std::copy(Name, Name+4, temp); + std::copy(Data, Data+Length, temp+4); + unsigned long tempRet = format::CalculateCRC(temp, 4+Length); + delete[] temp; + return tempRet; + } + } + ~PNGChunk() + { + if(Data) + delete[] Data; + } +}; + +std::vector<char> format::VideoBufferToPNG(const VideoBuffer & vidBuf) +{ + std::vector<PNGChunk*> chunks; + + //Begin IHDR (Image header) chunk (Image size and depth) + PNGChunk IHDRChunk = PNGChunk(13, "IHDR"); + + //Image Width + IHDRChunk.Data[0] = (vidBuf.Width>>24)&0xFF; + IHDRChunk.Data[1] = (vidBuf.Width>>16)&0xFF; + IHDRChunk.Data[2] = (vidBuf.Width>>8)&0xFF; + IHDRChunk.Data[3] = (vidBuf.Width)&0xFF; + + //Image Height + IHDRChunk.Data[4] = (vidBuf.Height>>24)&0xFF; + IHDRChunk.Data[5] = (vidBuf.Height>>16)&0xFF; + IHDRChunk.Data[6] = (vidBuf.Height>>8)&0xFF; + IHDRChunk.Data[7] = (vidBuf.Height)&0xFF; + + //Bit depth + IHDRChunk.Data[8] = 8; //8bits per channel or 24bpp + + //Colour type + IHDRChunk.Data[9] = 2; //RGB triple + + //Everything else is default + chunks.push_back(&IHDRChunk); + + //Begin image data, format is 8bit RGB (24bit pixel) + int dataPos = 0; + unsigned char * uncompressedData = new unsigned char[(vidBuf.Width*vidBuf.Height*3)+vidBuf.Height]; + + //Byte ordering and filtering + unsigned char * previousRow = new unsigned char[vidBuf.Width*3]; + std::fill(previousRow, previousRow+(vidBuf.Width*3), 0); + unsigned char * currentRow = new unsigned char[vidBuf.Width*3]; + for(int y = 0; y < vidBuf.Height; y++) + { + int rowPos = 0; + for(int x = 0; x < vidBuf.Width; x++) + { + currentRow[rowPos++] = PIXR(vidBuf.Buffer[(y*vidBuf.Width)+x]); + currentRow[rowPos++] = PIXG(vidBuf.Buffer[(y*vidBuf.Width)+x]); + currentRow[rowPos++] = PIXB(vidBuf.Buffer[(y*vidBuf.Width)+x]); + } + + uncompressedData[dataPos++] = 2; //Up Sub(x) filter + for(int b = 0; b < rowPos; b++) + { + int filteredByte = (currentRow[b]-previousRow[b])&0xFF; + uncompressedData[dataPos++] = filteredByte; + } + + unsigned char * tempRow = previousRow; + previousRow = currentRow; + currentRow = tempRow; + } + delete[] currentRow; + delete[] previousRow; + + //Compression + int compressedBufferSize = (vidBuf.Width*vidBuf.Height*3)*2; + unsigned char * compressedData = new unsigned char[compressedBufferSize]; + + int result; + z_stream zipStream; + zipStream.zalloc = Z_NULL; + zipStream.zfree = Z_NULL; + zipStream.opaque = Z_NULL; + + result = deflateInit2(&zipStream, + 9, // level + Z_DEFLATED, // method + 10, // windowBits + 1, // memLevel + Z_DEFAULT_STRATEGY // strategy + ); + + if (result != Z_OK) exit(result); + + zipStream.next_in = uncompressedData; + zipStream.avail_in = dataPos; + + zipStream.next_out = compressedData; + zipStream.avail_out = compressedBufferSize; + + + result = deflate(&zipStream, Z_FINISH); + if (result != Z_STREAM_END) exit(result); + + int compressedSize = compressedBufferSize-zipStream.avail_out; + PNGChunk IDATChunk = PNGChunk(compressedSize, "IDAT"); + std::copy(compressedData, compressedData+compressedSize, IDATChunk.Data); + chunks.push_back(&IDATChunk); + + deflateEnd(&zipStream); + + delete[] compressedData; + delete[] uncompressedData; + + PNGChunk IENDChunk = PNGChunk(0, "IEND"); + chunks.push_back(&IENDChunk); + + //Write chunks to output buffer + int finalDataSize = 8; + for(std::vector<PNGChunk*>::iterator iter = chunks.begin(), end = chunks.end(); iter != end; ++iter) + { + PNGChunk * cChunk = *iter; + finalDataSize += 4 + 4 + 4; + finalDataSize += cChunk->Length; + } + unsigned char * finalData = new unsigned char[finalDataSize]; + int finalDataPos = 0; + + //PNG File header + finalData[finalDataPos++] = 0x89; + finalData[finalDataPos++] = 0x50; + finalData[finalDataPos++] = 0x4E; + finalData[finalDataPos++] = 0x47; + finalData[finalDataPos++] = 0x0D; + finalData[finalDataPos++] = 0x0A; + finalData[finalDataPos++] = 0x1A; + finalData[finalDataPos++] = 0x0A; + + for(std::vector<PNGChunk*>::iterator iter = chunks.begin(), end = chunks.end(); iter != end; ++iter) + { + PNGChunk * cChunk = *iter; + + //Chunk length + finalData[finalDataPos++] = (cChunk->Length>>24)&0xFF; + finalData[finalDataPos++] = (cChunk->Length>>16)&0xFF; + finalData[finalDataPos++] = (cChunk->Length>>8)&0xFF; + finalData[finalDataPos++] = (cChunk->Length)&0xFF; + + //Chunk name + std::copy(cChunk->Name, cChunk->Name+4, finalData+finalDataPos); + finalDataPos += 4; + + //Chunk data + if(cChunk->Data) + { + std::copy(cChunk->Data, cChunk->Data+cChunk->Length, finalData+finalDataPos); + finalDataPos += cChunk->Length; + } + + //Chunk CRC + unsigned long tempCRC = cChunk->CRC(); + finalData[finalDataPos++] = (tempCRC>>24)&0xFF; + finalData[finalDataPos++] = (tempCRC>>16)&0xFF; + finalData[finalDataPos++] = (tempCRC>>8)&0xFF; + finalData[finalDataPos++] = (tempCRC)&0xFF; + } + + std::vector<char> outputData(finalData, finalData+finalDataPos); + + delete[] finalData; + + return outputData; +} + +//CRC functions, copypasta from W3 PNG spec. + +/* Table of CRCs of all 8-bit messages. */ +unsigned long crc_table[256]; + +/* Flag: has the table been computed? Initially false. */ +int crc_table_computed = 0; + +/* Make the table for a fast CRC. */ +void make_crc_table(void) +{ + unsigned long c; + int n, k; + + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) + c = 0xedb88320L ^ (c >> 1); + else + c = c >> 1; + } + crc_table[n] = c; + } + crc_table_computed = 1; +} + +/* Update a running CRC with the bytes buf[0..len-1]--the CRC + should be initialized to all 1's, and the transmitted value + is the 1's complement of the final running CRC (see the + crc() routine below)). */ + +unsigned long update_crc(unsigned long crc, unsigned char *buf, int len) +{ + unsigned long c = crc; + int n; + + if (!crc_table_computed) + make_crc_table(); + for (n = 0; n < len; n++) + { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c; +} + +unsigned long format::CalculateCRC(unsigned char * data, int len) +{ + return update_crc(0xffffffffL, data, len) ^ 0xffffffffL; +}
\ No newline at end of file |
