| 1 |
#include "stdafx.h" |
| 2 |
|
| 3 |
#include <assert.h> |
| 4 |
|
| 5 |
#include "dct.h" |
| 6 |
#include "Quantizer.h" |
| 7 |
|
| 8 |
#include <vector> |
| 9 |
#include <algorithm> |
| 10 |
#include <cmath> |
| 11 |
|
| 12 |
#include <boost/integer_traits.hpp> |
| 13 |
using namespace boost; |
| 14 |
#include <boost/cstdint.hpp> |
| 15 |
|
| 16 |
#include "misc.h" |
| 17 |
#include "decode.h" |
| 18 |
#include "encode.h" |
| 19 |
|
| 20 |
#include "ReadImage/ReadImage.h" |
| 21 |
#include "ReadImage/File.h" |
| 22 |
|
| 23 |
int _tmain(int argc, _TCHAR* argv[]) |
| 24 |
{ |
| 25 |
if (argc < 2) { |
| 26 |
_tprintf(_T("specify filename\n")); |
| 27 |
return 1; |
| 28 |
} |
| 29 |
|
| 30 |
FILE* f = _tfopen(argv[1], _T("rb")); |
| 31 |
if (!f) { |
| 32 |
_tprintf(_T("failed to open file : %s\n"), argv[1]); |
| 33 |
return 1; |
| 34 |
} |
| 35 |
File fo(f); |
| 36 |
ImageInfo imageInfo; |
| 37 |
ReadImageInfo(fo, imageInfo); |
| 38 |
|
| 39 |
size_t width = imageInfo.width; |
| 40 |
size_t height = imageInfo.height; |
| 41 |
assert(imageInfo.bitsPerSample == 8 && imageInfo.samplesPerPixel == 1); |
| 42 |
const size_t size = width * height; |
| 43 |
std::vector<unsigned char> in(size); |
| 44 |
std::vector<int> work(size); |
| 45 |
std::vector<int> work2(size); |
| 46 |
std::vector<unsigned char> out(size); |
| 47 |
|
| 48 |
unsigned char palettes[256 * 4]; |
| 49 |
ReadImageData(fo, &in[0], width, palettes); |
| 50 |
fclose(f); |
| 51 |
|
| 52 |
for (size_t i=0; i<size; ++i) { |
| 53 |
in[i] = palettes[4 * in[i]]; |
| 54 |
} |
| 55 |
|
| 56 |
const size_t hBlockCount = width / 8 + ((width % 8) ? 1 : 0); |
| 57 |
const size_t vBlockCount = height / 8 + ((height % 8) ? 1 : 0); |
| 58 |
const size_t totalBlockCount = hBlockCount * vBlockCount; |
| 59 |
|
| 60 |
size_t storageSize = work.size()*4*1.1+600; |
| 61 |
std::vector<unsigned char> work3(storageSize); |
| 62 |
std::vector<unsigned char> work4(storageSize); |
| 63 |
std::vector<unsigned char> encoded(storageSize); |
| 64 |
CompressInfo compressInfos[8] = {0}; |
| 65 |
|
| 66 |
Quantizer quantizer; |
| 67 |
quantizer.init(6*8+0, 0, 0, false); |
| 68 |
|
| 69 |
size_t totalLen = 0; |
| 70 |
|
| 71 |
// TODO: to design stream byte formats and various JYEIPEGYUU stream classes and implement serialize methods. |
| 72 |
|
| 73 |
// encode |
| 74 |
{ |
| 75 |
unsigned char* dest = &encoded[0]; |
| 76 |
unsigned char* initialDest = dest; |
| 77 |
|
| 78 |
// TODO: to record stream signature "jyeipegyuu\0" |
| 79 |
// TODO: to record streams |
| 80 |
|
| 81 |
int* pWork = &work[0]; |
| 82 |
int* pWork2 = &work2[0]; |
| 83 |
|
| 84 |
// TODO: to record quantizer parameter |
| 85 |
|
| 86 |
// TODO: to add encode options such as quantization table. |
| 87 |
encode(quantizer, hBlockCount, vBlockCount, &in[0], width, pWork, width*sizeof(int)); |
| 88 |
|
| 89 |
reorderByFrequency(hBlockCount, vBlockCount, pWork, pWork2); |
| 90 |
|
| 91 |
unsigned char enableDCPrediction = 1; |
| 92 |
*dest++ = enableDCPrediction; |
| 93 |
if (enableDCPrediction) { |
| 94 |
predictEncode(hBlockCount, vBlockCount, pWork2, pWork); |
| 95 |
} |
| 96 |
|
| 97 |
std::vector<unsigned char> signFlags(totalBlockCount*64); |
| 98 |
unsigned char* pSignFlags = &signFlags[0]; |
| 99 |
size_t signFlagCount = collectInfos(pWork2, totalBlockCount, pSignFlags, compressInfos); |
| 100 |
|
| 101 |
// AC�W����0��1�������������������Z�������k�����B�����g��������������01���������������������B�����������x�����������g���������������u���b�N�����������������B |
| 102 |
size_t zeroOneLimit = 2; |
| 103 |
std::vector<int> zeroOneInfos(totalBlockCount); |
| 104 |
std::vector<int> allZeroOneInfos(totalBlockCount * 8); |
| 105 |
int* pZeroOneInfos = &zeroOneInfos[0]; |
| 106 |
int* pAllZeroOneInfos = &allZeroOneInfos[0]; |
| 107 |
|
| 108 |
// quantizing zero one flags |
| 109 |
*dest++ = zeroOneLimit; |
| 110 |
if (zeroOneLimit != 0) { |
| 111 |
findZeroOneInfos(hBlockCount, vBlockCount, pWork2, pZeroOneInfos, pAllZeroOneInfos, zeroOneLimit); |
| 112 |
int encodedSize = totalBlockCount/4; |
| 113 |
Encode(pZeroOneInfos, totalBlockCount, 1, 0, &work3[0], encodedSize); |
| 114 |
*((uint32_t*)dest) = encodedSize; |
| 115 |
dest += 4; |
| 116 |
memcpy(dest, &work3[0], encodedSize); |
| 117 |
dest += encodedSize; |
| 118 |
|
| 119 |
//encodedSize = totalBlockCount; |
| 120 |
//Encode(pAllZeroOneInfos, totalBlockCount, (256>>zeroOneLimit)-1, 0, &work3[0], encodedSize); |
| 121 |
//*((uint32_t*)dest) = encodedSize; |
| 122 |
//dest += 4; |
| 123 |
//memcpy(dest, &work3[0], encodedSize); |
| 124 |
//dest += encodedSize; |
| 125 |
|
| 126 |
}else { |
| 127 |
pZeroOneInfos = 0; |
| 128 |
} |
| 129 |
dest += compress(hBlockCount, vBlockCount, pZeroOneInfos, zeroOneLimit, compressInfos, pWork2, (unsigned char*)pWork, &work3[0], &work4[0], dest, encoded.size()); |
| 130 |
|
| 131 |
// TODO: to record DCT coefficients sign predictor setting |
| 132 |
|
| 133 |
BitWriter writer(dest+4); |
| 134 |
for (size_t i=0; i<signFlagCount; ++i) { |
| 135 |
writer.putBit(signFlags[i] != 0); |
| 136 |
} |
| 137 |
*((uint32_t*)dest) = writer.nBytes(); |
| 138 |
dest += 4; |
| 139 |
dest += writer.nBytes(); |
| 140 |
|
| 141 |
totalLen = dest - initialDest; |
| 142 |
|
| 143 |
} |
| 144 |
|
| 145 |
size_t compressedLen = totalLen; |
| 146 |
|
| 147 |
std::fill(work.begin(), work.end(), 0); |
| 148 |
std::fill(work2.begin(), work2.end(), 0); |
| 149 |
std::vector<unsigned char> tmp(encoded.size()); |
| 150 |
|
| 151 |
// decode |
| 152 |
{ |
| 153 |
unsigned char* src = &encoded[0]; |
| 154 |
int* pWork = &work[0]; |
| 155 |
int* pWork2 = &work2[0]; |
| 156 |
size_t destLen = work2.size(); |
| 157 |
|
| 158 |
unsigned char enableDCPrediction = *src++; |
| 159 |
|
| 160 |
// zero one flags |
| 161 |
unsigned char zeroOneLimit = *src++; |
| 162 |
std::vector<int> zeroOneFlags(totalBlockCount*2); |
| 163 |
int* pZeroOneFlags = &zeroOneFlags[0]; |
| 164 |
if (zeroOneLimit != 0) { |
| 165 |
uint32_t zeroOneFlagBytes = *(uint32_t*)src; |
| 166 |
src += 4; |
| 167 |
{ |
| 168 |
int flagCount = totalBlockCount; |
| 169 |
Decode(src, zeroOneFlagBytes, pZeroOneFlags, flagCount); |
| 170 |
assert(flagCount == totalBlockCount); |
| 171 |
} |
| 172 |
src += zeroOneFlagBytes; |
| 173 |
}else { |
| 174 |
pZeroOneFlags = 0; |
| 175 |
} |
| 176 |
src += decompress(hBlockCount, vBlockCount, pZeroOneFlags, zeroOneLimit, src, compressedLen, &tmp[0], pWork, pWork2, destLen); |
| 177 |
|
| 178 |
// sign flags |
| 179 |
uint32_t signFlagBytes = *(uint32_t*)src; |
| 180 |
src += 4; |
| 181 |
std::vector<unsigned char> signFlags(signFlagBytes * 8); |
| 182 |
unsigned char* pSignFlags = &signFlags[0]; |
| 183 |
{ |
| 184 |
BitReader reader(src); |
| 185 |
for (size_t i=0; i<signFlagBytes*8; ++i) { |
| 186 |
pSignFlags[i] = reader.getBit(); |
| 187 |
} |
| 188 |
size_t pos = 0; |
| 189 |
for (size_t i=0; i<totalBlockCount*64; ++i) { |
| 190 |
int& val = pWork2[i]; |
| 191 |
if (val != 0) { |
| 192 |
val = pSignFlags[pos++] ? val : -val; |
| 193 |
} |
| 194 |
} |
| 195 |
} |
| 196 |
|
| 197 |
if (enableDCPrediction) { |
| 198 |
predictDecode(hBlockCount, vBlockCount, pWork2, pWork); |
| 199 |
} |
| 200 |
|
| 201 |
reorderByPosition(hBlockCount, vBlockCount, pWork2, pWork); |
| 202 |
|
| 203 |
decode(quantizer, hBlockCount, vBlockCount, pWork, width*sizeof(int), &out[0], width); |
| 204 |
} |
| 205 |
unsigned char* pOutput = &out[0]; |
| 206 |
|
| 207 |
//FILE* of = _tfopen(_T("out.raw"), _T("wb")); |
| 208 |
//fwrite(pOutput, 1, size, of); |
| 209 |
//fclose(of); |
| 210 |
|
| 211 |
_tprintf(_T("%f%% %d bytes"), (100.0 * compressedLen) / size, compressedLen); |
| 212 |
return 0; |
| 213 |
} |