| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268 |
- #include "tiny_jpeg.h"
- #include <inttypes.h>
- #include <math.h> // floorf, ceilf
- #include <string.h> // memcpy
- #include "bsp_common.h"
- #include "core_debug.h"
- #define assert(x) ASSERT(x)
- #define tjei_min(a, b) ((a) < b) ? (a) : (b);
- #define tjei_max(a, b) ((a) < b) ? (b) : (a);
- #if defined(_MSC_VER)
- #define TJEI_FORCE_INLINE __forceinline
- // #define TJEI_FORCE_INLINE __declspec(noinline) // For profiling
- #else
- #define TJEI_FORCE_INLINE static // TODO: equivalent for gcc & clang
- #endif
- // Only use zero for debugging and/or inspection.
- #define TJE_USE_FAST_DCT 1
- // C std lib
- // ============================================================
- // Table definitions.
- //
- // The spec defines tjei_default reasonably good quantization matrices and huffman
- // specification tables.
- //
- //
- // Instead of hard-coding the final huffman table, we only hard-code the table
- // spec suggested by the specification, and then derive the full table from
- // there. This is only for didactic purposes but it might be useful if there
- // ever is the case that we need to swap huffman tables from various sources.
- // ============================================================
- // K.1 - suggested luminance QT
- static const uint8_t tjei_default_qt_luma_from_spec[] =
- {
- 16,11,10,16, 24, 40, 51, 61,
- 12,12,14,19, 26, 58, 60, 55,
- 14,13,16,24, 40, 57, 69, 56,
- 14,17,22,29, 51, 87, 80, 62,
- 18,22,37,56, 68,109,103, 77,
- 24,35,55,64, 81,104,113, 92,
- 49,64,78,87,103,121,120,101,
- 72,92,95,98,112,100,103, 99,
- };
- // Unused
- #if 0
- static const uint8_t tjei_default_qt_chroma_from_spec[] =
- {
- // K.1 - suggested chrominance QT
- 17,18,24,47,99,99,99,99,
- 18,21,26,66,99,99,99,99,
- 24,26,56,99,99,99,99,99,
- 47,66,99,99,99,99,99,99,
- 99,99,99,99,99,99,99,99,
- 99,99,99,99,99,99,99,99,
- 99,99,99,99,99,99,99,99,
- 99,99,99,99,99,99,99,99,
- };
- #endif
- static const uint8_t tjei_default_qt_chroma_from_paper[] =
- {
- // Example QT from JPEG paper
- 16, 12, 14, 14, 18, 24, 49, 72,
- 11, 10, 16, 24, 40, 51, 61, 12,
- 13, 17, 22, 35, 64, 92, 14, 16,
- 22, 37, 55, 78, 95, 19, 24, 29,
- 56, 64, 87, 98, 26, 40, 51, 68,
- 81, 103, 112, 58, 57, 87, 109, 104,
- 121,100, 60, 69, 80, 103, 113, 120,
- 103, 55, 56, 62, 77, 92, 101, 99,
- };
- // == Procedure to 'deflate' the huffman tree: JPEG spec, C.2
- // Number of 16 bit values for every code length. (K.3.3.1)
- static const uint8_t tjei_default_ht_luma_dc_len[16] =
- {
- 0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0
- };
- // values
- static const uint8_t tjei_default_ht_luma_dc[12] =
- {
- 0,1,2,3,4,5,6,7,8,9,10,11
- };
- // Number of 16 bit values for every code length. (K.3.3.1)
- static const uint8_t tjei_default_ht_chroma_dc_len[16] =
- {
- 0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0
- };
- // values
- static const uint8_t tjei_default_ht_chroma_dc[12] =
- {
- 0,1,2,3,4,5,6,7,8,9,10,11
- };
- // Same as above, but AC coefficients.
- static const uint8_t tjei_default_ht_luma_ac_len[16] =
- {
- 0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d
- };
- static const uint8_t tjei_default_ht_luma_ac[] =
- {
- 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
- 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,
- 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
- 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
- 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
- 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
- 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
- 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
- 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
- 0xF9, 0xFA
- };
- static const uint8_t tjei_default_ht_chroma_ac_len[16] =
- {
- 0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77
- };
- static const uint8_t tjei_default_ht_chroma_ac[] =
- {
- 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
- 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,
- 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,
- 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
- 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
- 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
- 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
- 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
- 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
- 0xF9, 0xFA
- };
- static float aan_scales[] = {
- 1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
- 1.0f, 0.785694958f, 0.541196100f, 0.275899379f
- };
- // ============================================================
- // Code
- // ============================================================
- // Zig-zag order:
- static const uint8_t tjei_zig_zag[64] =
- {
- 0, 1, 5, 6, 14, 15, 27, 28,
- 2, 4, 7, 13, 16, 26, 29, 42,
- 3, 8, 12, 17, 25, 30, 41, 43,
- 9, 11, 18, 24, 31, 40, 44, 53,
- 10, 19, 23, 32, 39, 45, 52, 54,
- 20, 22, 33, 38, 46, 51, 55, 60,
- 21, 34, 37, 47, 50, 56, 59, 61,
- 35, 36, 48, 49, 57, 58, 62, 63,
- };
- #define tjei_be_word BSP_Swap16
- // ============================================================
- // The following structs exist only for code clarity, debugability, and
- // readability. They are used when writing to disk, but it is useful to have
- // 1-packed-structs to document how the format works, and to inspect memory
- // while developing.
- // ============================================================
- static const uint8_t tjeik_jfif_id[] = "JFIF";
- static const uint8_t tjeik_com_str[] = "Created by JPEG Encoder";
- // TODO: Get rid of packed structs!
- #pragma pack(push)
- #pragma pack(1)
- typedef struct
- {
- uint16_t SOI;
- // JFIF header.
- uint16_t APP0;
- uint16_t jfif_len;
- uint8_t jfif_id[5];
- uint16_t version;
- uint8_t units;
- uint16_t x_density;
- uint16_t y_density;
- uint8_t x_thumb;
- uint8_t y_thumb;
- } TJEJPEGHeader;
- typedef struct
- {
- uint16_t com;
- uint16_t com_len;
- char com_str[sizeof(tjeik_com_str) - 1];
- } TJEJPEGComment;
- typedef struct
- {
- void* context;
- tje_write_func* func;
- } TJEWriteContext;
- typedef struct
- {
- // Huffman data.
- uint8_t ehuffsize[4][257];
- uint16_t ehuffcode[4][256];
- uint8_t const * ht_bits[4];
- uint8_t const * ht_vals[4];
- // Cuantization tables.
- uint8_t qt_luma[64];
- uint8_t qt_chroma[64];
- // fwrite by default. User-defined when using tje_encode_with_func.
- TJEWriteContext write_context;
- // Buffered output. Big performance win when using the usual stdlib implementations.
- size_t output_buffer_count;
- uint8_t output_buffer[TJEI_BUFFER_SIZE];
- } TJEState;
- // Helper struct for TJEFrameHeader (below).
- typedef struct
- {
- uint8_t component_id;
- uint8_t sampling_factors; // most significant 4 bits: horizontal. 4 LSB: vertical (A.1.1)
- uint8_t qt; // Quantization table selector.
- } TJEComponentSpec;
- typedef struct
- {
- uint16_t SOF;
- uint16_t len; // 8 + 3 * frame.num_components
- uint8_t precision; // Sample precision (bits per sample).
- uint16_t height;
- uint16_t width;
- uint8_t num_components; // For this implementation, will be equal to 3.
- TJEComponentSpec component_spec[3];
- } TJEFrameHeader;
- typedef struct
- {
- uint8_t component_id; // Just as with TJEComponentSpec
- uint8_t dc_ac; // (dc|ac)
- } TJEFrameComponentSpec;
- typedef struct
- {
- uint16_t SOS;
- uint16_t len;
- uint8_t num_components; // 3.
- TJEFrameComponentSpec component_spec[3];
- uint8_t first; // 0
- uint8_t last; // 63
- uint8_t ah_al; // o
- } TJEScanHeader;
- #pragma pack(pop)
- static void tjei_write(TJEState* state, const void* data, size_t num_bytes, size_t num_elements)
- {
- size_t to_write = num_bytes * num_elements;
- // Cap to the buffer available size and copy memory.
- size_t capped_count = tjei_min(to_write, TJEI_BUFFER_SIZE - 1 - state->output_buffer_count);
- memcpy(state->output_buffer + state->output_buffer_count, data, capped_count);
- state->output_buffer_count += capped_count;
- assert (state->output_buffer_count <= TJEI_BUFFER_SIZE - 1);
- // Flush the buffer.
- if ( state->output_buffer_count == TJEI_BUFFER_SIZE - 1 ) {
- state->write_context.func(state->write_context.context, state->output_buffer, (int)state->output_buffer_count);
- state->output_buffer_count = 0;
- }
- // Recursively calling ourselves with the rest of the buffer.
- if (capped_count < to_write) {
- tjei_write(state, (uint8_t*)data+capped_count, to_write - capped_count, 1);
- }
- }
- static void tjei_write_DQT(TJEState* state, const uint8_t* matrix, uint8_t id)
- {
- uint16_t DQT = tjei_be_word(0xffdb);
- tjei_write(state, &DQT, sizeof(uint16_t), 1);
- uint16_t len = tjei_be_word(0x0043); // 2(len) + 1(id) + 64(matrix) = 67 = 0x43
- tjei_write(state, &len, sizeof(uint16_t), 1);
- assert(id < 4);
- uint8_t precision_and_id = id; // 0x0000 8 bits | 0x00id
- tjei_write(state, &precision_and_id, sizeof(uint8_t), 1);
- // Write matrix
- tjei_write(state, matrix, 64*sizeof(uint8_t), 1);
- }
- typedef enum
- {
- TJEI_DC = 0,
- TJEI_AC = 1
- } TJEHuffmanTableClass;
- static void tjei_write_DHT(TJEState* state,
- uint8_t const * matrix_len,
- uint8_t const * matrix_val,
- TJEHuffmanTableClass ht_class,
- uint8_t id)
- {
- int num_values = 0;
- for ( int i = 0; i < 16; ++i ) {
- num_values += matrix_len[i];
- }
- assert(num_values <= 0xffff);
- uint16_t DHT = tjei_be_word(0xffc4);
- // 2(len) + 1(Tc|th) + 16 (num lengths) + ?? (num values)
- uint16_t len = tjei_be_word(2 + 1 + 16 + (uint16_t)num_values);
- assert(id < 4);
- uint8_t tc_th = (uint8_t)((((uint8_t)ht_class) << 4) | id);
- tjei_write(state, &DHT, sizeof(uint16_t), 1);
- tjei_write(state, &len, sizeof(uint16_t), 1);
- tjei_write(state, &tc_th, sizeof(uint8_t), 1);
- tjei_write(state, matrix_len, sizeof(uint8_t), 16);
- tjei_write(state, matrix_val, sizeof(uint8_t), (size_t)num_values);
- }
- // ============================================================
- // Huffman deflation code.
- // ============================================================
- // Returns all code sizes from the BITS specification (JPEG C.3)
- static uint8_t* tjei_huff_get_code_lengths(uint8_t huffsize[/*256*/], uint8_t const * bits)
- {
- int k = 0;
- for ( int i = 0; i < 16; ++i ) {
- for ( int j = 0; j < bits[i]; ++j ) {
- huffsize[k++] = (uint8_t)(i + 1);
- }
- huffsize[k] = 0;
- }
- return huffsize;
- }
- // Fills out the prefixes for each code.
- static uint16_t* tjei_huff_get_codes(uint16_t codes[], uint8_t* huffsize, int64_t count)
- {
- uint16_t code = 0;
- int k = 0;
- uint8_t sz = huffsize[0];
- for(;;) {
- do {
- assert(k < count);
- codes[k++] = code++;
- } while (huffsize[k] == sz);
- if (huffsize[k] == 0) {
- return codes;
- }
- do {
- code = (uint16_t)(code << 1);
- ++sz;
- } while( huffsize[k] != sz );
- }
- }
- static void tjei_huff_get_extended(uint8_t* out_ehuffsize,
- uint16_t* out_ehuffcode,
- uint8_t const * huffval,
- uint8_t* huffsize,
- uint16_t* huffcode, int64_t count)
- {
- int k = 0;
- do {
- uint8_t val = huffval[k];
- out_ehuffcode[val] = huffcode[k];
- out_ehuffsize[val] = huffsize[k];
- k++;
- } while ( k < count );
- }
- // ============================================================
- // Returns:
- // out[1] : number of bits
- // out[0] : bits
- TJEI_FORCE_INLINE void tjei_calculate_variable_length_int(int value, uint16_t out[2])
- {
- int abs_val = value;
- if ( value < 0 ) {
- abs_val = -abs_val;
- --value;
- }
- out[1] = 1;
- while( abs_val >>= 1 ) {
- ++out[1];
- }
- out[0] = (uint16_t)(value & ((1 << out[1]) - 1));
- }
- // Write bits to file.
- TJEI_FORCE_INLINE void tjei_write_bits(TJEState* state,
- uint32_t* bitbuffer, uint32_t* location,
- uint16_t num_bits, uint16_t bits)
- {
- // v-- location
- // [ ] <-- bit buffer
- // 32 0
- //
- // This call pushes to the bitbuffer and saves the location. Data is pushed
- // from most significant to less significant.
- // When we can write a full byte, we write a byte and shift.
- // Push the stack.
- uint32_t nloc = *location + num_bits;
- *bitbuffer |= (uint32_t)(bits << (32 - nloc));
- *location = nloc;
- while ( *location >= 8 ) {
- // Grab the most significant byte.
- uint8_t c = (uint8_t)((*bitbuffer) >> 24);
- // Write it to file.
- tjei_write(state, &c, 1, 1);
- if ( c == 0xff ) {
- // Special case: tell JPEG this is not a marker.
- char z = 0;
- tjei_write(state, &z, 1, 1);
- }
- // Pop the stack.
- *bitbuffer <<= 8;
- *location -= 8;
- }
- }
- // DCT implementation by Thomas G. Lane.
- // Obtained through NVIDIA
- // http://developer.download.nvidia.com/SDK/9.5/Samples/vidimaging_samples.html#gpgpu_dct
- //
- // QUOTE:
- // This implementation is based on Arai, Agui, and Nakajima's algorithm for
- // scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
- // Japanese, but the algorithm is described in the Pennebaker & Mitchell
- // JPEG textbook (see REFERENCES section in file README). The following code
- // is based directly on figure 4-8 in P&M.
- //
- static void tjei_fdct (float * data)
- {
- float tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- float tmp10, tmp11, tmp12, tmp13;
- float z1, z2, z3, z4, z5, z11, z13;
- float *dataptr;
- int ctr;
- /* Pass 1: process rows. */
- dataptr = data;
- for ( ctr = 7; ctr >= 0; ctr-- ) {
- tmp0 = dataptr[0] + dataptr[7];
- tmp7 = dataptr[0] - dataptr[7];
- tmp1 = dataptr[1] + dataptr[6];
- tmp6 = dataptr[1] - dataptr[6];
- tmp2 = dataptr[2] + dataptr[5];
- tmp5 = dataptr[2] - dataptr[5];
- tmp3 = dataptr[3] + dataptr[4];
- tmp4 = dataptr[3] - dataptr[4];
- /* Even part */
- tmp10 = tmp0 + tmp3; /* phase 2 */
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
- dataptr[0] = tmp10 + tmp11; /* phase 3 */
- dataptr[4] = tmp10 - tmp11;
- z1 = (tmp12 + tmp13) * ((float) 0.707106781); /* c4 */
- dataptr[2] = tmp13 + z1; /* phase 5 */
- dataptr[6] = tmp13 - z1;
- /* Odd part */
- tmp10 = tmp4 + tmp5; /* phase 2 */
- tmp11 = tmp5 + tmp6;
- tmp12 = tmp6 + tmp7;
- /* The rotator is modified from fig 4-8 to avoid extra negations. */
- z5 = (tmp10 - tmp12) * ((float) 0.382683433); /* c6 */
- z2 = ((float) 0.541196100) * tmp10 + z5; /* c2-c6 */
- z4 = ((float) 1.306562965) * tmp12 + z5; /* c2+c6 */
- z3 = tmp11 * ((float) 0.707106781); /* c4 */
- z11 = tmp7 + z3; /* phase 5 */
- z13 = tmp7 - z3;
- dataptr[5] = z13 + z2; /* phase 6 */
- dataptr[3] = z13 - z2;
- dataptr[1] = z11 + z4;
- dataptr[7] = z11 - z4;
- dataptr += 8; /* advance pointer to next row */
- }
- /* Pass 2: process columns. */
- dataptr = data;
- for ( ctr = 8-1; ctr >= 0; ctr-- ) {
- tmp0 = dataptr[8*0] + dataptr[8*7];
- tmp7 = dataptr[8*0] - dataptr[8*7];
- tmp1 = dataptr[8*1] + dataptr[8*6];
- tmp6 = dataptr[8*1] - dataptr[8*6];
- tmp2 = dataptr[8*2] + dataptr[8*5];
- tmp5 = dataptr[8*2] - dataptr[8*5];
- tmp3 = dataptr[8*3] + dataptr[8*4];
- tmp4 = dataptr[8*3] - dataptr[8*4];
- /* Even part */
- tmp10 = tmp0 + tmp3; /* phase 2 */
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
- dataptr[8*0] = tmp10 + tmp11; /* phase 3 */
- dataptr[8*4] = tmp10 - tmp11;
- z1 = (tmp12 + tmp13) * ((float) 0.707106781); /* c4 */
- dataptr[8*2] = tmp13 + z1; /* phase 5 */
- dataptr[8*6] = tmp13 - z1;
- /* Odd part */
- tmp10 = tmp4 + tmp5; /* phase 2 */
- tmp11 = tmp5 + tmp6;
- tmp12 = tmp6 + tmp7;
- /* The rotator is modified from fig 4-8 to avoid extra negations. */
- z5 = (tmp10 - tmp12) * ((float) 0.382683433); /* c6 */
- z2 = ((float) 0.541196100) * tmp10 + z5; /* c2-c6 */
- z4 = ((float) 1.306562965) * tmp12 + z5; /* c2+c6 */
- z3 = tmp11 * ((float) 0.707106781); /* c4 */
- z11 = tmp7 + z3; /* phase 5 */
- z13 = tmp7 - z3;
- dataptr[8*5] = z13 + z2; /* phase 6 */
- dataptr[8*3] = z13 - z2;
- dataptr[8*1] = z11 + z4;
- dataptr[8*7] = z11 - z4;
- dataptr++; /* advance pointer to next column */
- }
- }
- #if !TJE_USE_FAST_DCT
- static float slow_fdct(int u, int v, float* data)
- {
- #define kPI 3.14159265f
- float res = 0.0f;
- float cu = (u == 0) ? 0.70710678118654f : 1;
- float cv = (v == 0) ? 0.70710678118654f : 1;
- for ( int y = 0; y < 8; ++y ) {
- for ( int x = 0; x < 8; ++x ) {
- res += (data[y * 8 + x]) *
- cosf(((2.0f * x + 1.0f) * u * kPI) / 16.0f) *
- cosf(((2.0f * y + 1.0f) * v * kPI) / 16.0f);
- }
- }
- res *= 0.25f * cu * cv;
- return res;
- #undef kPI
- }
- #endif
- #define ABS(x) ((x) < 0 ? -(x) : (x))
- static void tjei_encode_and_write_MCU(TJEState* state,
- float* mcu,
- #if TJE_USE_FAST_DCT
- float* qt, // Pre-processed quantization matrix.
- #else
- uint8_t* qt,
- #endif
- uint8_t* huff_dc_len, uint16_t* huff_dc_code, // Huffman tables
- uint8_t* huff_ac_len, uint16_t* huff_ac_code,
- int* pred, // Previous DC coefficient
- uint32_t* bitbuffer, // Bitstack.
- uint32_t* location)
- {
- int du[64]; // Data unit in zig-zag order
- float dct_mcu[64];
- memcpy(dct_mcu, mcu, 64 * sizeof(float));
- #if TJE_USE_FAST_DCT
- tjei_fdct(dct_mcu);
- for ( int i = 0; i < 64; ++i ) {
- float fval = dct_mcu[i];
- fval *= qt[i];
- #if 0
- fval = (fval > 0) ? floorf(fval + 0.5f) : ceilf(fval - 0.5f);
- #else
- fval = floorf(fval + 1024 + 0.5f);
- fval -= 1024;
- #endif
- int val = (int)fval;
- du[tjei_zig_zag[i]] = val;
- }
- #else
- for ( int v = 0; v < 8; ++v ) {
- for ( int u = 0; u < 8; ++u ) {
- dct_mcu[v * 8 + u] = slow_fdct(u, v, mcu);
- }
- }
- for ( int i = 0; i < 64; ++i ) {
- float fval = dct_mcu[i] / (qt[i]);
- int val = (int)((fval > 0) ? floorf(fval + 0.5f) : ceilf(fval - 0.5f));
- du[tjei_zig_zag[i]] = val;
- }
- #endif
- uint16_t vli[2];
- // Encode DC coefficient.
- int diff = du[0] - *pred;
- *pred = du[0];
- if ( diff != 0 ) {
- tjei_calculate_variable_length_int(diff, vli);
- // Write number of bits with Huffman coding
- tjei_write_bits(state, bitbuffer, location, huff_dc_len[vli[1]], huff_dc_code[vli[1]]);
- // Write the bits.
- tjei_write_bits(state, bitbuffer, location, vli[1], vli[0]);
- } else {
- tjei_write_bits(state, bitbuffer, location, huff_dc_len[0], huff_dc_code[0]);
- }
- // ==== Encode AC coefficients ====
- int last_non_zero_i = 0;
- // Find the last non-zero element.
- for ( int i = 63; i > 0; --i ) {
- if (du[i] != 0) {
- last_non_zero_i = i;
- break;
- }
- }
- for ( int i = 1; i <= last_non_zero_i; ++i ) {
- // If zero, increase count. If >=15, encode (FF,00)
- int zero_count = 0;
- while ( du[i] == 0 ) {
- ++zero_count;
- ++i;
- if (zero_count == 16) {
- // encode (ff,00) == 0xf0
- tjei_write_bits(state, bitbuffer, location, huff_ac_len[0xf0], huff_ac_code[0xf0]);
- zero_count = 0;
- }
- }
- tjei_calculate_variable_length_int(du[i], vli);
- assert(zero_count < 0x10);
- assert(vli[1] <= 10);
- uint16_t sym1 = (uint16_t)((uint16_t)zero_count << 4) | vli[1];
- assert(huff_ac_len[sym1] != 0);
- // Write symbol 1 --- (RUNLENGTH, SIZE)
- tjei_write_bits(state, bitbuffer, location, huff_ac_len[sym1], huff_ac_code[sym1]);
- // Write symbol 2 --- (AMPLITUDE)
- tjei_write_bits(state, bitbuffer, location, vli[1], vli[0]);
- }
- if (last_non_zero_i != 63) {
- // write EOB HUFF(00,00)
- tjei_write_bits(state, bitbuffer, location, huff_ac_len[0], huff_ac_code[0]);
- }
- return;
- }
- enum {
- TJEI_LUMA_DC,
- TJEI_LUMA_AC,
- TJEI_CHROMA_DC,
- TJEI_CHROMA_AC,
- };
- #if TJE_USE_FAST_DCT
- struct TJEProcessedQT
- {
- float chroma[64];
- float luma[64];
- };
- #endif
- // Set up huffman tables in state.
- static void tjei_huff_expand(TJEState* state)
- {
- assert(state);
- state->ht_bits[TJEI_LUMA_DC] = tjei_default_ht_luma_dc_len;
- state->ht_bits[TJEI_LUMA_AC] = tjei_default_ht_luma_ac_len;
- state->ht_bits[TJEI_CHROMA_DC] = tjei_default_ht_chroma_dc_len;
- state->ht_bits[TJEI_CHROMA_AC] = tjei_default_ht_chroma_ac_len;
- state->ht_vals[TJEI_LUMA_DC] = tjei_default_ht_luma_dc;
- state->ht_vals[TJEI_LUMA_AC] = tjei_default_ht_luma_ac;
- state->ht_vals[TJEI_CHROMA_DC] = tjei_default_ht_chroma_dc;
- state->ht_vals[TJEI_CHROMA_AC] = tjei_default_ht_chroma_ac;
- // How many codes in total for each of LUMA_(DC|AC) and CHROMA_(DC|AC)
- int32_t spec_tables_len[4] = { 0 };
- for ( int i = 0; i < 4; ++i ) {
- for ( int k = 0; k < 16; ++k ) {
- spec_tables_len[i] += state->ht_bits[i][k];
- }
- }
- // Fill out the extended tables..
- uint8_t huffsize[4][257];
- uint16_t huffcode[4][256];
- for ( int i = 0; i < 4; ++i ) {
- assert (256 >= spec_tables_len[i]);
- tjei_huff_get_code_lengths(huffsize[i], state->ht_bits[i]);
- tjei_huff_get_codes(huffcode[i], huffsize[i], spec_tables_len[i]);
- }
- for ( int i = 0; i < 4; ++i ) {
- int64_t count = spec_tables_len[i];
- tjei_huff_get_extended(state->ehuffsize[i],
- state->ehuffcode[i],
- state->ht_vals[i],
- &huffsize[i][0],
- &huffcode[i][0], count);
- }
- }
- //static int tjei_encode_main(TJEState* state,
- // const unsigned char* src_data,
- // const int width,
- // const int height,
- // const int src_num_components)
- //{
- // if (src_num_components != 3 && src_num_components != 4) {
- // return 0;
- // }
- //
- // if (width > 0xffff || height > 0xffff) {
- // return 0;
- // }
- //
- //#if TJE_USE_FAST_DCT
- // struct TJEProcessedQT pqt;
- // // Again, taken from classic japanese implementation.
- // //
- // /* For float AA&N IDCT method, divisors are equal to quantization
- // * coefficients scaled by scalefactor[row]*scalefactor[col], where
- // * scalefactor[0] = 1
- // * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
- // * We apply a further scale factor of 8.
- // * What's actually stored is 1/divisor so that the inner loop can
- // * use a multiplication rather than a division.
- // */
- //
- //
- // // build (de)quantization tables
- // for(int y=0; y<8; y++) {
- // for(int x=0; x<8; x++) {
- // int i = y*8 + x;
- // pqt.luma[y*8+x] = 1.0f / (8 * aan_scales[x] * aan_scales[y] * state->qt_luma[tjei_zig_zag[i]]);
- // pqt.chroma[y*8+x] = 1.0f / (8 * aan_scales[x] * aan_scales[y] * state->qt_chroma[tjei_zig_zag[i]]);
- // }
- // }
- //#endif
- //
- // { // Write header
- // TJEJPEGHeader header;
- // // JFIF header.
- // header.SOI = tjei_be_word(0xffd8); // Sequential DCT
- // header.APP0 = tjei_be_word(0xffe0);
- //
- // uint16_t jfif_len = sizeof(TJEJPEGHeader) - 4 /*SOI & APP0 markers*/;
- // header.jfif_len = tjei_be_word(jfif_len);
- // memcpy(header.jfif_id, (void*)tjeik_jfif_id, 5);
- // header.version = tjei_be_word(0x0102);
- // header.units = 0x01; // Dots-per-inch
- // header.x_density = tjei_be_word(0x0060); // 96 DPI
- // header.y_density = tjei_be_word(0x0060); // 96 DPI
- // header.x_thumb = 0;
- // header.y_thumb = 0;
- // tjei_write(state, &header, sizeof(TJEJPEGHeader), 1);
- // }
- // { // Write comment
- // TJEJPEGComment com;
- // uint16_t com_len = 2 + sizeof(tjeik_com_str) - 1;
- // // Comment
- // com.com = tjei_be_word(0xfffe);
- // com.com_len = tjei_be_word(com_len);
- // memcpy(com.com_str, (void*)tjeik_com_str, sizeof(tjeik_com_str)-1);
- // tjei_write(state, &com, sizeof(TJEJPEGComment), 1);
- // }
- //
- // // Write quantization tables.
- // tjei_write_DQT(state, state->qt_luma, 0x00);
- // tjei_write_DQT(state, state->qt_chroma, 0x01);
- //
- // { // Write the frame marker.
- // TJEFrameHeader header;
- // header.SOF = tjei_be_word(0xffc0);
- // header.len = tjei_be_word(8 + 3 * 3);
- // header.precision = 8;
- // assert(width <= 0xffff);
- // assert(height <= 0xffff);
- // header.width = tjei_be_word((uint16_t)width);
- // header.height = tjei_be_word((uint16_t)height);
- // header.num_components = 3;
- // uint8_t tables[3] = {
- // 0, // Luma component gets luma table (see tjei_write_DQT call above.)
- // 1, // Chroma component gets chroma table
- // 1, // Chroma component gets chroma table
- // };
- // for (int i = 0; i < 3; ++i) {
- // TJEComponentSpec spec;
- // spec.component_id = (uint8_t)(i + 1); // No particular reason. Just 1, 2, 3.
- // spec.sampling_factors = (uint8_t)0x11;
- // spec.qt = tables[i];
- //
- // header.component_spec[i] = spec;
- // }
- // // Write to file.
- // tjei_write(state, &header, sizeof(TJEFrameHeader), 1);
- // }
- //
- // tjei_write_DHT(state, state->ht_bits[TJEI_LUMA_DC], state->ht_vals[TJEI_LUMA_DC], TJEI_DC, 0);
- // tjei_write_DHT(state, state->ht_bits[TJEI_LUMA_AC], state->ht_vals[TJEI_LUMA_AC], TJEI_AC, 0);
- // tjei_write_DHT(state, state->ht_bits[TJEI_CHROMA_DC], state->ht_vals[TJEI_CHROMA_DC], TJEI_DC, 1);
- // tjei_write_DHT(state, state->ht_bits[TJEI_CHROMA_AC], state->ht_vals[TJEI_CHROMA_AC], TJEI_AC, 1);
- //
- // // Write start of scan
- // {
- // TJEScanHeader header;
- // header.SOS = tjei_be_word(0xffda);
- // header.len = tjei_be_word((uint16_t)(6 + (sizeof(TJEFrameComponentSpec) * 3)));
- // header.num_components = 3;
- //
- // uint8_t tables[3] = {
- // 0x00,
- // 0x11,
- // 0x11,
- // };
- // for (int i = 0; i < 3; ++i) {
- // TJEFrameComponentSpec cs;
- // // Must be equal to component_id from frame header above.
- // cs.component_id = (uint8_t)(i + 1);
- // cs.dc_ac = (uint8_t)tables[i];
- //
- // header.component_spec[i] = cs;
- // }
- // header.first = 0;
- // header.last = 63;
- // header.ah_al = 0;
- // tjei_write(state, &header, sizeof(TJEScanHeader), 1);
- //
- // }
- // // Write compressed data.
- //
- // float du_y[64];
- // float du_b[64];
- // float du_r[64];
- //
- // // Set diff to 0.
- // int pred_y = 0;
- // int pred_b = 0;
- // int pred_r = 0;
- //
- // // Bit stack
- // uint32_t bitbuffer = 0;
- // uint32_t location = 0;
- //
- //
- // for ( int y = 0; y < height; y += 8 ) {
- // for ( int x = 0; x < width; x += 8 ) {
- // // Block loop: ====
- // for ( int off_y = 0; off_y < 8; ++off_y ) {
- // for ( int off_x = 0; off_x < 8; ++off_x ) {
- // int block_index = (off_y * 8 + off_x);
- //
- // int src_index = (((y + off_y) * width) + (x + off_x)) * src_num_components;
- //
- // int col = x + off_x;
- // int row = y + off_y;
- //
- // if(row >= height) {
- // src_index -= (width * (row - height + 1)) * src_num_components;
- // }
- // if(col >= width) {
- // src_index -= (col - width + 1) * src_num_components;
- // }
- // assert(src_index < width * height * src_num_components);
- //
- // uint8_t r = src_data[src_index + 0];
- // uint8_t g = src_data[src_index + 1];
- // uint8_t b = src_data[src_index + 2];
- //
- // float luma = 0.299f * r + 0.587f * g + 0.114f * b - 128;
- // float cb = -0.1687f * r - 0.3313f * g + 0.5f * b;
- // float cr = 0.5f * r - 0.4187f * g - 0.0813f * b;
- //
- // du_y[block_index] = luma;
- // du_b[block_index] = cb;
- // du_r[block_index] = cr;
- // }
- // }
- //
- // tjei_encode_and_write_MCU(state, du_y,
- //#if TJE_USE_FAST_DCT
- // pqt.luma,
- //#else
- // state->qt_luma,
- //#endif
- // state->ehuffsize[TJEI_LUMA_DC], state->ehuffcode[TJEI_LUMA_DC],
- // state->ehuffsize[TJEI_LUMA_AC], state->ehuffcode[TJEI_LUMA_AC],
- // &pred_y, &bitbuffer, &location);
- // tjei_encode_and_write_MCU(state, du_b,
- //#if TJE_USE_FAST_DCT
- // pqt.chroma,
- //#else
- // state->qt_chroma,
- //#endif
- // state->ehuffsize[TJEI_CHROMA_DC], state->ehuffcode[TJEI_CHROMA_DC],
- // state->ehuffsize[TJEI_CHROMA_AC], state->ehuffcode[TJEI_CHROMA_AC],
- // &pred_b, &bitbuffer, &location);
- // tjei_encode_and_write_MCU(state, du_r,
- //#if TJE_USE_FAST_DCT
- // pqt.chroma,
- //#else
- // state->qt_chroma,
- //#endif
- // state->ehuffsize[TJEI_CHROMA_DC], state->ehuffcode[TJEI_CHROMA_DC],
- // state->ehuffsize[TJEI_CHROMA_AC], state->ehuffcode[TJEI_CHROMA_AC],
- // &pred_r, &bitbuffer, &location);
- //
- //
- // }
- // }
- //
- // // Finish the image.
- // { // Flush
- // if (location > 0 && location < 8) {
- // tjei_write_bits(state, &bitbuffer, &location, (uint16_t)(8 - location), 0);
- // }
- // }
- // uint16_t EOI = tjei_be_word(0xffd9);
- // tjei_write(state, &EOI, sizeof(uint16_t), 1);
- //
- // if (state->output_buffer_count) {
- // state->write_context.func(state->write_context.context, state->output_buffer, (int)state->output_buffer_count);
- // state->output_buffer_count = 0;
- // }
- //
- // return 1;
- //}
- //int tje_encode_with_func(tje_write_func* func,
- // void* context,
- // const int quality,
- // const int width,
- // const int height,
- // const int num_components,
- // const unsigned char* src_data)
- //{
- // if (quality < 1 || quality > 3) {
- // tje_log("[ERROR] -- Valid 'quality' values are 1 (lowest), 2, or 3 (highest)");
- // return 0;
- // }
- //
- // TJEState state = { 0 };
- //
- //
- //
- // TJEWriteContext wc = { 0 };
- //
- // wc.context = context;
- // wc.func = func;
- //
- // state.write_context = wc;
- //
- //
- // tjei_huff_expand(&state);
- //
- // int result = tjei_encode_main(&state, src_data, width, height, num_components);
- //
- // return result;
- //}
- // ============================================================
- typedef struct
- {
- TJEState encode_state;
- #if TJE_USE_FAST_DCT
- struct TJEProcessedQT pqt;
- #endif
- uint32_t width;
- uint32_t height;
- uint32_t num_components;
- uint32_t cur_height;
- // Set diff to 0.
- int pred_y;
- int pred_b;
- int pred_r;
- // Bit stack
- uint32_t bitbuffer;
- uint32_t location;
- }TJE_ContextStruct;
- void *jpeg_encode_init(tje_write_func* func, void* context, uint8_t quality, uint32_t width, uint32_t height, uint8_t src_num_components)
- {
- if (quality < 1 || quality > 3) {
- tje_log("Valid 'quality' %d values are 1 (lowest), 2, or 3 (highest)", quality);
- return NULL;
- }
- if (src_num_components != 3 && src_num_components != 4) {
- return NULL;
- }
- if (width > 0xffff || height > 0xffff) {
- return NULL;
- }
- TJE_ContextStruct *ctx = zalloc(sizeof(TJE_ContextStruct));
- uint8_t qt_factor = 1;
- switch(quality) {
- case 3:
- for ( int i = 0; i < 64; ++i ) {
- ctx->encode_state.qt_luma[i] = 1;
- ctx->encode_state.qt_chroma[i] = 1;
- }
- break;
- case 2:
- qt_factor = 10;
- // don't break. fall through.
- case 1:
- for ( int i = 0; i < 64; ++i ) {
- ctx->encode_state.qt_luma[i] = tjei_default_qt_luma_from_spec[i] / qt_factor;
- if (ctx->encode_state.qt_luma[i] == 0) {
- ctx->encode_state.qt_luma[i] = 1;
- }
- ctx->encode_state.qt_chroma[i] = tjei_default_qt_chroma_from_paper[i] / qt_factor;
- if (ctx->encode_state.qt_chroma[i] == 0) {
- ctx->encode_state.qt_chroma[i] = 1;
- }
- }
- break;
- default:
- assert(!"invalid code path");
- break;
- }
- ctx->encode_state.write_context.func = func;
- ctx->encode_state.write_context.context = context;
- ctx->width = width;
- ctx->height = height;
- ctx->num_components = src_num_components;
- tjei_huff_expand(&ctx->encode_state);
- TJEState* state = &ctx->encode_state;
- #if TJE_USE_FAST_DCT
- // Again, taken from classic japanese implementation.
- //
- /* For float AA&N IDCT method, divisors are equal to quantization
- * coefficients scaled by scalefactor[row]*scalefactor[col], where
- * scalefactor[0] = 1
- * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
- * We apply a further scale factor of 8.
- * What's actually stored is 1/divisor so that the inner loop can
- * use a multiplication rather than a division.
- */
- // build (de)quantization tables
- for(int y=0; y<8; y++) {
- for(int x=0; x<8; x++) {
- int i = y*8 + x;
- ctx->pqt.luma[y*8+x] = 1.0f / (8 * aan_scales[x] * aan_scales[y] * state->qt_luma[tjei_zig_zag[i]]);
- ctx->pqt.chroma[y*8+x] = 1.0f / (8 * aan_scales[x] * aan_scales[y] * state->qt_chroma[tjei_zig_zag[i]]);
- }
- }
- #endif
- { // Write header
- TJEJPEGHeader header;
- // JFIF header.
- header.SOI = tjei_be_word(0xffd8); // Sequential DCT
- header.APP0 = tjei_be_word(0xffe0);
- uint16_t jfif_len = sizeof(TJEJPEGHeader) - 4 /*SOI & APP0 markers*/;
- header.jfif_len = tjei_be_word(jfif_len);
- memcpy(header.jfif_id, (void*)tjeik_jfif_id, 5);
- header.version = tjei_be_word(0x0102);
- header.units = 0x01; // Dots-per-inch
- header.x_density = tjei_be_word(0x0060); // 96 DPI
- header.y_density = tjei_be_word(0x0060); // 96 DPI
- header.x_thumb = 0;
- header.y_thumb = 0;
- tjei_write(state, &header, sizeof(TJEJPEGHeader), 1);
- }
- { // Write comment
- TJEJPEGComment com;
- uint16_t com_len = 2 + sizeof(tjeik_com_str) - 1;
- // Comment
- com.com = tjei_be_word(0xfffe);
- com.com_len = tjei_be_word(com_len);
- memcpy(com.com_str, (void*)tjeik_com_str, sizeof(tjeik_com_str)-1);
- tjei_write(state, &com, sizeof(TJEJPEGComment), 1);
- }
- // Write quantization tables.
- tjei_write_DQT(state, state->qt_luma, 0x00);
- tjei_write_DQT(state, state->qt_chroma, 0x01);
- { // Write the frame marker.
- TJEFrameHeader header;
- header.SOF = tjei_be_word(0xffc0);
- header.len = tjei_be_word(8 + 3 * 3);
- header.precision = 8;
- assert(width <= 0xffff);
- assert(height <= 0xffff);
- header.width = tjei_be_word((uint16_t)width);
- header.height = tjei_be_word((uint16_t)height);
- header.num_components = 3;
- uint8_t tables[3] = {
- 0, // Luma component gets luma table (see tjei_write_DQT call above.)
- 1, // Chroma component gets chroma table
- 1, // Chroma component gets chroma table
- };
- for (int i = 0; i < 3; ++i) {
- TJEComponentSpec spec;
- spec.component_id = (uint8_t)(i + 1); // No particular reason. Just 1, 2, 3.
- spec.sampling_factors = (uint8_t)0x11;
- spec.qt = tables[i];
- header.component_spec[i] = spec;
- }
- // Write to file.
- tjei_write(state, &header, sizeof(TJEFrameHeader), 1);
- }
- tjei_write_DHT(state, state->ht_bits[TJEI_LUMA_DC], state->ht_vals[TJEI_LUMA_DC], TJEI_DC, 0);
- tjei_write_DHT(state, state->ht_bits[TJEI_LUMA_AC], state->ht_vals[TJEI_LUMA_AC], TJEI_AC, 0);
- tjei_write_DHT(state, state->ht_bits[TJEI_CHROMA_DC], state->ht_vals[TJEI_CHROMA_DC], TJEI_DC, 1);
- tjei_write_DHT(state, state->ht_bits[TJEI_CHROMA_AC], state->ht_vals[TJEI_CHROMA_AC], TJEI_AC, 1);
- // Write start of scan
- {
- TJEScanHeader header;
- header.SOS = tjei_be_word(0xffda);
- header.len = tjei_be_word((uint16_t)(6 + (sizeof(TJEFrameComponentSpec) * 3)));
- header.num_components = 3;
- uint8_t tables[3] = {
- 0x00,
- 0x11,
- 0x11,
- };
- for (int i = 0; i < 3; ++i) {
- TJEFrameComponentSpec cs;
- // Must be equal to component_id from frame header above.
- cs.component_id = (uint8_t)(i + 1);
- cs.dc_ac = (uint8_t)tables[i];
- header.component_spec[i] = cs;
- }
- header.first = 0;
- header.last = 63;
- header.ah_al = 0;
- tjei_write(state, &header, sizeof(TJEScanHeader), 1);
- }
- return ctx;
- }
- void jpeg_encode_run(void *ctx, uint8_t *src_data, uint8_t is_rgb)
- {
- float du_y[64];
- float du_b[64];
- float du_r[64];
- TJE_ContextStruct *handle = (TJE_ContextStruct *)ctx;
- TJEState* state = &handle->encode_state;
- uint32_t width = handle->width;
- uint32_t height = handle->height;
- uint32_t src_num_components = handle->num_components;
- uint32_t block_index, src_index, col, row;
- uint8_t r,g,b;
- for ( uint32_t x = 0; x < width; x += 8 ) {
- // Block loop: ====
- for ( uint32_t off_y = 0; off_y < 8; ++off_y ) {
- for ( uint32_t off_x = 0; off_x < 8; ++off_x ) {
- block_index = (off_y * 8 + off_x);
- src_index = (((0 + off_y) * width) + (x + off_x)) * src_num_components;
- if (is_rgb)
- {
- r = src_data[src_index + 0];
- g = src_data[src_index + 1];
- b = src_data[src_index + 2];
- du_y[block_index] = 0.299f * r + 0.587f * g + 0.114f * b - 128;
- du_b[block_index] = -0.1687f * r - 0.3313f * g + 0.5f * b;
- du_r[block_index] = 0.5f * r - 0.4187f * g - 0.0813f * b;
- }
- else
- {
- du_y[block_index] = src_data[src_index + 0];
- du_b[block_index] = src_data[src_index + 1];
- du_r[block_index] = src_data[src_index + 2];
- du_y[block_index] -= 128;
- du_b[block_index] -= 128;
- du_r[block_index] -= 128;
- }
- }
- }
- tjei_encode_and_write_MCU(state, du_y,
- #if TJE_USE_FAST_DCT
- handle->pqt.luma,
- #else
- state->qt_luma,
- #endif
- state->ehuffsize[TJEI_LUMA_DC], state->ehuffcode[TJEI_LUMA_DC],
- state->ehuffsize[TJEI_LUMA_AC], state->ehuffcode[TJEI_LUMA_AC],
- &handle->pred_y, &handle->bitbuffer, &handle->location);
- tjei_encode_and_write_MCU(state, du_b,
- #if TJE_USE_FAST_DCT
- handle->pqt.chroma,
- #else
- state->qt_chroma,
- #endif
- state->ehuffsize[TJEI_CHROMA_DC], state->ehuffcode[TJEI_CHROMA_DC],
- state->ehuffsize[TJEI_CHROMA_AC], state->ehuffcode[TJEI_CHROMA_AC],
- &handle->pred_b, &handle->bitbuffer, &handle->location);
- tjei_encode_and_write_MCU(state, du_r,
- #if TJE_USE_FAST_DCT
- handle->pqt.chroma,
- #else
- state->qt_chroma,
- #endif
- state->ehuffsize[TJEI_CHROMA_DC], state->ehuffcode[TJEI_CHROMA_DC],
- state->ehuffsize[TJEI_CHROMA_AC], state->ehuffcode[TJEI_CHROMA_AC],
- &handle->pred_r, &handle->bitbuffer, &handle->location);
- }
- handle->cur_height += 8;
- }
- void jpeg_encode_end(void *ctx)
- {
- uint16_t EOI = tjei_be_word(0xffd9);
- TJE_ContextStruct *handle = (TJE_ContextStruct *)ctx;
- TJEState* state = &handle->encode_state;
- tjei_write(state, &EOI, sizeof(uint16_t), 1);
- if (state->output_buffer_count) {
- state->write_context.func(state->write_context.context, state->output_buffer, (int)state->output_buffer_count);
- state->output_buffer_count = 0;
- }
- }
|