21 using uint8_t =
unsigned char;
22 using uint16_t =
unsigned short;
23 using int16_t = short;
30 const uint8_t DefaultQuantLuminance[8*8] =
31 { 16, 11, 10, 16, 24, 40, 51, 61,
32 12, 12, 14, 19, 26, 58, 60, 55,
33 14, 13, 16, 24, 40, 57, 69, 56,
34 14, 17, 22, 29, 51, 87, 80, 62,
35 18, 22, 37, 56, 68,109,103, 77,
36 24, 35, 55, 64, 81,104,113, 92,
37 49, 64, 78, 87,103,121,120,101,
38 72, 92, 95, 98,112,100,103, 99 };
39 const uint8_t DefaultQuantChrominance[8*8] =
40 { 17, 18, 24, 47, 99, 99, 99, 99,
41 18, 21, 26, 66, 99, 99, 99, 99,
42 24, 26, 56, 99, 99, 99, 99, 99,
43 47, 66, 99, 99, 99, 99, 99, 99,
44 99, 99, 99, 99, 99, 99, 99, 99,
45 99, 99, 99, 99, 99, 99, 99, 99,
46 99, 99, 99, 99, 99, 99, 99, 99,
47 99, 99, 99, 99, 99, 99, 99, 99 };
52 const uint8_t ZigZagInv[8*8] =
53 { 0, 1, 8,16, 9, 2, 3,10,
54 17,24,32,25,18,11, 4, 5,
55 12,19,26,33,40,48,41,34,
56 27,20,13, 6, 7,14,21,28,
57 35,42,49,56,57,50,43,36,
58 29,22,15,23,30,37,44,51,
59 58,59,52,45,38,31,39,46,
60 53,60,61,54,47,55,62,63 };
69 const uint8_t DcLuminanceCodesPerBitsize[16] = { 0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 };
70 const uint8_t DcLuminanceValues [12] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
71 const uint8_t AcLuminanceCodesPerBitsize[16] = { 0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,125 };
72 const uint8_t AcLuminanceValues [162] =
73 { 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xA1,0x08,
74 0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,0x24,0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28,
75 0x29,0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
76 0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
77 0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,
78 0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2,
79 0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA };
81 const uint8_t DcChrominanceCodesPerBitsize[16] = { 0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };
82 const uint8_t DcChrominanceValues [12] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
83 const uint8_t AcChrominanceCodesPerBitsize[16] = { 0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,119 };
84 const uint8_t AcChrominanceValues [162] =
85 { 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
86 0xA1,0xB1,0xC1,0x09,0x23,0x33,0x52,0xF0,0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,0x1A,0x26,
87 0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,
88 0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85,0x86,0x87,
89 0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,
90 0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,
91 0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA };
92 const int16_t CodeWordLimit = 2048;
101 BitCode(uint16_t code_, uint8_t numBits_)
102 : code(code_), numBits(numBits_) {}
126 buffer.numBits +=
data.numBits;
127 buffer.data <<=
data.numBits;
128 buffer.data |=
data.code;
131 while (buffer.numBits >= 8)
135 auto oneByte = uint8_t(buffer.data >> buffer.numBits);
152 *
this << BitCode(0x7F, 7);
164 template <
typename T,
int Size>
167 for (
auto c : manyBytes)
173 void addMarker(uint8_t
id, uint16_t length)
175 output(0xFF); output(
id);
176 output(uint8_t(length >> 8));
177 output(uint8_t(length & 0xFF));
185 template <
typename Number>
186 Number minimum(Number
value, Number maximum)
192 template <
typename Number,
typename Limit>
193 Number clamp(Number
value, Limit minValue, Limit maxValue)
195 if (
value <= minValue)
return minValue;
196 if (
value >= maxValue)
return maxValue;
201 float rgb2y (
float r,
float g,
float b) {
return +0.299f * r +0.587f * g +0.114f * b; }
202 float rgb2cb(
float r,
float g,
float b) {
return -0.16874f * r -0.33126f * g +0.5f * b; }
203 float rgb2cr(
float r,
float g,
float b) {
return +0.5f * r -0.41869f * g -0.08131f * b; }
204 float rgb2y (
int r,
int g,
int b) {
return rgb2y ((
float)r, (
float)g, (
float)b); }
205 float rgb2cb(
int r,
int g,
int b) {
return rgb2cb((
float)r, (
float)g, (
float)b); }
206 float rgb2cr(
int r,
int g,
int b) {
return rgb2cr((
float)r, (
float)g, (
float)b); }
209 void DCT(
float block[8*8], uint8_t stride)
211 const auto SqrtHalfSqrt = 1.306562965f;
212 const auto InvSqrt = 0.707106781f;
213 const auto HalfSqrtSqrt = 0.382683432f;
214 const auto InvSqrtSqrt = 0.541196100f;
217 auto& block0 = block[0 ];
218 auto& block1 = block[1 * stride];
219 auto& block2 = block[2 * stride];
220 auto& block3 = block[3 * stride];
221 auto& block4 = block[4 * stride];
222 auto& block5 = block[5 * stride];
223 auto& block6 = block[6 * stride];
224 auto& block7 = block[7 * stride];
227 auto add07 = block0 + block7;
auto sub07 = block0 - block7;
228 auto add16 = block1 + block6;
auto sub16 = block1 - block6;
229 auto add25 = block2 + block5;
auto sub25 = block2 - block5;
230 auto add34 = block3 + block4;
auto sub34 = block3 - block4;
232 auto add0347 = add07 + add34;
auto sub07_34 = add07 - add34;
233 auto add1256 = add16 + add25;
auto sub16_25 = add16 - add25;
235 block0 = add0347 + add1256; block4 = add0347 - add1256;
237 auto z1 = (sub16_25 + sub07_34) * InvSqrt;
238 block2 = sub07_34 + z1; block6 = sub07_34 - z1;
240 auto sub23_45 = sub25 + sub34;
241 auto sub12_56 = sub16 + sub25;
242 auto sub01_67 = sub16 + sub07;
244 auto z5 = (sub23_45 - sub01_67) * HalfSqrtSqrt;
245 auto z2 = sub23_45 * InvSqrtSqrt + z5;
246 auto z3 = sub12_56 * InvSqrt;
247 auto z4 = sub01_67 * SqrtHalfSqrt + z5;
248 auto z6 = sub07 + z3;
249 auto z7 = sub07 - z3;
250 block1 = z6 + z4; block7 = z6 - z4;
251 block5 = z7 + z2; block3 = z7 - z2;
255 int16_t encodeBlock(BitWriter& writer,
float block[8][8],
const float scaled[8*8], int16_t lastDC,
256 const BitCode huffmanDC[256],
const BitCode huffmanAC[256],
const BitCode* codewords)
259 auto block64 = (
float*) block;
262 for (
auto offset = 0; offset < 8; offset++)
263 DCT(block64 + offset*8, 1);
265 for (
auto offset = 0; offset < 8; offset++)
266 DCT(block64 + offset*1, 8);
269 for (
auto i = 0; i < 8*8; i++)
270 block64[i] *= scaled[i];
273 auto DC = int(block64[0] + (block64[0] >= 0 ? +0.5f : -0.5f));
277 int16_t quantized[8*8];
278 for (
auto i = 1; i < 8*8; i++)
280 auto value = block64[ZigZagInv[i]];
282 quantized[i] = int(
value + (
value >= 0 ? +0.5f : -0.5f));
284 if (quantized[i] != 0)
289 auto diff = DC - lastDC;
291 writer << huffmanDC[0x00];
294 auto bits = codewords[diff];
295 writer << huffmanDC[bits.numBits] << bits;
300 for (
auto i = 1; i <= posNonZero; i++)
303 while (quantized[i] == 0)
309 writer << huffmanAC[0xF0];
315 auto encoded = codewords[quantized[i]];
317 writer << huffmanAC[offset + encoded.numBits] << encoded;
322 if (posNonZero < 8*8 - 1)
323 writer << huffmanAC[0x00];
330 void generateHuffmanTable(
const uint8_t numCodes[16],
const uint8_t* values, BitCode result[256])
333 auto huffmanCode = 0;
334 for (
auto numBits = 1; numBits <= 16; numBits++)
337 for (
auto i = 0; i < numCodes[numBits - 1]; i++)
338 result[*values++] = BitCode(huffmanCode++, numBits);
353 bool isRGB,
unsigned char quality_,
bool downsample,
const char* comment)
356 if (output ==
nullptr || pixels_ ==
nullptr)
359 if (width == 0 || height == 0)
363 const auto numComponents = isRGB ? 3 : 1;
373 BitWriter bitWriter(output);
377 const uint8_t HeaderJfif[2+2+16] =
386 bitWriter << HeaderJfif;
390 if (comment !=
nullptr)
394 while (comment[
length] != 0)
398 bitWriter.addMarker(0xFE, 2+
length);
400 for (
auto i = 0; i <
length; i++)
401 bitWriter << comment[i];
408 auto quality = clamp<uint16_t>(quality_, 1, 100);
410 quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
412 uint8_t quantLuminance [8*8];
413 uint8_t quantChrominance[8*8];
414 for (
auto i = 0; i < 8*8; i++)
416 int luminance = (DefaultQuantLuminance [ZigZagInv[i]] * quality + 50) / 100;
417 int chrominance = (DefaultQuantChrominance[ZigZagInv[i]] * quality + 50) / 100;
420 quantLuminance [i] = clamp(luminance, 1, 255);
421 quantChrominance[i] = clamp(chrominance, 1, 255);
425 bitWriter.addMarker(0xDB, 2 + (isRGB ? 2 : 1) * (1 + 8*8));
428 bitWriter << 0x00 << quantLuminance;
430 bitWriter << 0x01 << quantChrominance;
434 bitWriter.addMarker(0xC0, 2+6+3*numComponents);
439 << (height >> 8) << (height & 0xFF)
440 << (width >> 8) << (width & 0xFF);
443 bitWriter << numComponents;
444 for (
auto id = 1;
id <= numComponents;
id++)
447 << (
id == 1 && downsample ? 0x22 : 0x11)
448 << (
id == 1 ? 0 : 1);
453 bitWriter.addMarker(0xC4, isRGB ? (2+208+208) : (2+208));
462 << DcLuminanceCodesPerBitsize
463 << DcLuminanceValues;
465 << AcLuminanceCodesPerBitsize
466 << AcLuminanceValues;
469 BitCode huffmanLuminanceDC[256];
470 BitCode huffmanLuminanceAC[256];
471 generateHuffmanTable(DcLuminanceCodesPerBitsize, DcLuminanceValues, huffmanLuminanceDC);
472 generateHuffmanTable(AcLuminanceCodesPerBitsize, AcLuminanceValues, huffmanLuminanceAC);
475 BitCode huffmanChrominanceDC[256];
476 BitCode huffmanChrominanceAC[256];
481 << DcChrominanceCodesPerBitsize
482 << DcChrominanceValues;
484 << AcChrominanceCodesPerBitsize
485 << AcChrominanceValues;
488 generateHuffmanTable(DcChrominanceCodesPerBitsize, DcChrominanceValues, huffmanChrominanceDC);
489 generateHuffmanTable(AcChrominanceCodesPerBitsize, AcChrominanceValues, huffmanChrominanceAC);
494 bitWriter.addMarker(0xDA, 2+1+2*numComponents+3);
498 bitWriter << numComponents;
499 for (
auto id = 1;
id <= numComponents;
id++)
501 bitWriter <<
id << (
id == 1 ? 0x00 : 0x11);
504 static const uint8_t Spectral[3] = { 0, 63, 0 };
505 bitWriter << Spectral;
509 float scaledLuminance [8*8];
510 float scaledChrominance[8*8];
511 for (
auto i = 0; i < 8*8; i++)
513 auto row = ZigZagInv[i] / 8;
514 auto column = ZigZagInv[i] % 8;
517 static const float AanScaleFactors[8] = { 1, 1.387039845f, 1.306562965f, 1.175875602f, 1, 0.785694958f, 0.541196100f, 0.275899379f };
518 auto factor = 1 / (AanScaleFactors[row] * AanScaleFactors[column] * 8);
519 scaledLuminance [ZigZagInv[i]] = factor / quantLuminance [i];
520 scaledChrominance[ZigZagInv[i]] = factor / quantChrominance[i];
529 BitCode codewordsArray[2 * CodeWordLimit];
530 BitCode* codewords = &codewordsArray[CodeWordLimit];
533 for (int16_t value = 1; value < CodeWordLimit; value++)
540 mask = (mask << 1) | 1;
542 codewords[-value] = BitCode(mask - value, numBits);
543 codewords[+value] = BitCode( value, numBits);
547 auto pixels = (
const uint8_t*)pixels_;
550 const auto maxWidth = width - 1;
551 const auto maxHeight = height - 1;
554 const auto sampling = downsample ? 2 : 1;
555 const auto mcuSize = 8 * sampling;
558 int16_t lastYDC = 0, lastCbDC = 0, lastCrDC = 0;
560 float Y[8][8], Cb[8][8], Cr[8][8];
562 for (
auto mcuY = 0; mcuY < height; mcuY += mcuSize)
563 for (
auto mcuX = 0; mcuX < width; mcuX += mcuSize)
567 for (
auto blockY = 0; blockY < mcuSize; blockY += 8)
568 for (
auto blockX = 0; blockX < mcuSize; blockX += 8)
571 for (
auto deltaY = 0; deltaY < 8; deltaY++)
573 auto column = minimum(mcuX + blockX , maxWidth);
574 auto row = minimum(mcuY + blockY + deltaY, maxHeight);
575 for (
auto deltaX = 0; deltaX < 8; deltaX++)
578 auto pixelPos = row * int(width) + column;
579 if (column < maxWidth)
585 Y[deltaY][deltaX] = pixels[pixelPos] - 128.f;
590 auto r = pixels[3 * pixelPos ];
591 auto g = pixels[3 * pixelPos + 1];
592 auto b = pixels[3 * pixelPos + 2];
594 Y [deltaY][deltaX] = rgb2y (r, g, b) - 128;
598 Cb[deltaY][deltaX] = rgb2cb(r, g, b);
599 Cr[deltaY][deltaX] = rgb2cr(r, g, b);
605 lastYDC = encodeBlock(bitWriter, Y, scaledLuminance, lastYDC, huffmanLuminanceDC, huffmanLuminanceAC, codewords);
617 for (
short deltaY = 7; downsample && deltaY >= 0; deltaY--)
619 auto row = minimum(mcuY + 2*deltaY, maxHeight);
621 auto pixelPos = (row * int(width) + column) * 3;
624 auto rowStep = (row < maxHeight) ? 3 *
int(width) : 0;
625 auto columnStep = (column < maxWidth ) ? 3 : 0;
627 for (
short deltaX = 0; deltaX < 8; deltaX++)
630 auto right = pixelPos + columnStep;
631 auto down = pixelPos + rowStep;
632 auto downRight = pixelPos + columnStep + rowStep;
635 auto r = short(pixels[pixelPos ]) + pixels[right ] + pixels[down ] + pixels[downRight ];
636 auto g = short(pixels[pixelPos + 1]) + pixels[right + 1] + pixels[down + 1] + pixels[downRight + 1];
637 auto b = short(pixels[pixelPos + 2]) + pixels[right + 2] + pixels[down + 2] + pixels[downRight + 2];
640 Cb[deltaY][deltaX] = rgb2cb(r, g, b) / 4;
641 Cr[deltaY][deltaX] = rgb2cr(r, g, b) / 4;
648 if (column >= maxWidth)
651 pixelPos = ((row + 1) *
int(width) - 1) * 3;
657 lastCbDC = encodeBlock(bitWriter, Cb, scaledChrominance, lastCbDC, huffmanChrominanceDC, huffmanChrominanceAC, codewords);
658 lastCrDC = encodeBlock(bitWriter, Cr, scaledChrominance, lastCrDC, huffmanChrominanceDC, huffmanChrominanceAC, codewords);
665 bitWriter << 0xFF << 0xD9;