Example #1
0
        public static void tjei_write_DQT(TJEState state, byte *matrix, byte id)
        {
            ushort DQT = (ushort)(tjei_be_word((ushort)(0xffdb)));

            tjei_write(state, &DQT, (ulong)(sizeof(ushort)), (ulong)(1));
            ushort len = (ushort)(tjei_be_word((ushort)(0x0043)));

            tjei_write(state, &len, (ulong)(sizeof(ushort)), (ulong)(1));
            byte precision_and_id = (byte)(id);

            tjei_write(state, &precision_and_id, (ulong)(sizeof(byte)), (ulong)(1));
            tjei_write(state, matrix, (ulong)(64 * sizeof(byte)), (ulong)(1));
        }
Example #2
0
        public static void tjei_write_DHT(TJEState state, byte *matrix_len, byte *matrix_val, int ht_class, byte id)
        {
            int num_values = (int)(0);

            for (int i = (int)(0); (i) < (16); ++i)
            {
                num_values += (int)(matrix_len[i]);
            }
            ushort DHT   = (ushort)(tjei_be_word((ushort)(0xffc4)));
            ushort len   = (ushort)(tjei_be_word((ushort)(2 + 1 + 16 + (ushort)(num_values))));
            byte   tc_th = (byte)((((byte)(ht_class)) << 4) | id);

            tjei_write(state, &DHT, (ulong)(sizeof(ushort)), (ulong)(1));
            tjei_write(state, &len, (ulong)(sizeof(ushort)), (ulong)(1));
            tjei_write(state, &tc_th, (ulong)(sizeof(byte)), (ulong)(1));
            tjei_write(state, matrix_len, (ulong)(sizeof(byte)), (ulong)(16));
            tjei_write(state, matrix_val, (ulong)(sizeof(byte)), (ulong)(num_values));
        }
Example #3
0
        public static void tjei_write_bits(TJEState state, uint *bitbuffer, uint *location, ushort num_bits, ushort bits)
        {
            uint nloc = (uint)(*location + num_bits);

            *bitbuffer |= ((uint)(bits << (int)(32 - nloc)));
            *location   = (uint)(nloc);
            while ((*location) >= (8))
            {
                byte c = (byte)((*bitbuffer) >> 24);
                tjei_write(state, &c, (ulong)(1), (ulong)(1));
                if ((c) == (0xff))
                {
                    sbyte z = (sbyte)(0);
                    tjei_write(state, &z, (ulong)(1), (ulong)(1));
                }
                *bitbuffer <<= 8;
                *location   -= (uint)(8);
            }
        }
Example #4
0
        public static unsafe void tjei_huff_expand(TJEState 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;
            var spec_tables_len = stackalloc int[4];

            for (var i = 0; i < 4; ++i)
            {
                spec_tables_len[i] = 0;
                for (var k = 0; k < 16; ++k)
                {
                    spec_tables_len[i] += state.ht_bits[i][k];
                }
            }
            var huffsize = stackalloc byte[4 * 257];
            var huffcode = stackalloc ushort[4 * 256];

            for (var i = 0; i < 4; ++i)
            {
                tjei_huff_get_code_lengths(huffsize + i * 257, state.ht_bits[i]);
                tjei_huff_get_codes(huffcode + i * 256, huffsize + i * 257,
                                    spec_tables_len[i]);
            }

            for (var i = 0; i < 4; ++i)
            {
                var count = spec_tables_len[i];
                tjei_huff_get_extended((byte *)state.ehuffsize + i * 257,
                                       (ushort *)state.ehuffcode + i * 256,
                                       state.ht_vals[i],
                                       huffsize + i * 257,
                                       huffcode + i * 256,
                                       count);
            }
        }
Example #5
0
        public static void tjei_write(TJEState state, void *data, ulong num_bytes, ulong num_elements)
        {
            ulong to_write     = (ulong)(num_bytes * num_elements);
            ulong capped_count =
                (ulong)
                (((to_write) < (1024 - 1 - state.output_buffer_count))
                        ? (to_write)
                        : (1024 - 1 - state.output_buffer_count));

            memcpy((byte *)state.output_buffer + state.output_buffer_count, data, (ulong)(capped_count));
            state.output_buffer_count += (ulong)(capped_count);
            if ((state.output_buffer_count) == (1024 - 1))
            {
                state.write_context.func(state.write_context.context, state.output_buffer,
                                         (int)(state.output_buffer_count));
                state.output_buffer_count = (ulong)(0);
            }

            if ((capped_count) < (to_write))
            {
                tjei_write(state, (byte *)(data) + capped_count, (ulong)(to_write - capped_count), (ulong)(1));
            }
        }
Example #6
0
        public static int tjei_encode_main(TJEState state, byte *src_data, int width, int height, int src_num_components)
        {
            if ((src_num_components != 3) && (src_num_components != 4))
            {
                return((int)(0));
            }

            if (((width) > (0xffff)) || ((height) > (0xffff)))
            {
                return((int)(0));
            }

            TJEProcessedQT pqt        = new TJEProcessedQT();
            float *        aan_scales = stackalloc float[8];

            aan_scales[0] = (float)(1.0f);
            aan_scales[1] = (float)(1.387039845f);
            aan_scales[2] = (float)(1.306562965f);
            aan_scales[3] = (float)(1.175875602f);
            aan_scales[4] = (float)(1.0f);
            aan_scales[5] = (float)(0.785694958f);
            aan_scales[6] = (float)(0.541196100f);
            aan_scales[7] = (float)(0.275899379f);

            for (int y = (int)(0); (y) < (8); y++)
            {
                for (int x = (int)(0); (x) < (8); x++)
                {
                    int i = (int)(y * 8 + x);
                    pqt.luma[y * 8 + x]   = (float)(1.0f / (8 * aan_scales[x] * aan_scales[y] * state.qt_luma[tjei_zig_zag[i]]));
                    pqt.chroma[y * 8 + x] =
                        (float)(1.0f / (8 * aan_scales[x] * aan_scales[y] * state.qt_chroma[tjei_zig_zag[i]]));
                }
            }
            {
                TJEJPEGHeader header = new TJEJPEGHeader();
                header.SOI  = (ushort)(tjei_be_word((ushort)(0xffd8)));
                header.APP0 = (ushort)(tjei_be_word((ushort)(0xffe0)));
                ushort jfif_len = (ushort)(20 - 4);
                header.jfif_len = (ushort)(tjei_be_word((ushort)(jfif_len)));
                memcpy(header.jfif_id, (void *)(tjeik_jfif_id), (ulong)(5));
                header.version   = (ushort)(tjei_be_word((ushort)(0x0102)));
                header.units     = (byte)(0x01);
                header.x_density = (ushort)(tjei_be_word((ushort)(0x0060)));
                header.y_density = (ushort)(tjei_be_word((ushort)(0x0060)));
                header.x_thumb   = (byte)(0);
                header.y_thumb   = (byte)(0);
                tjei_write(state, &header, (ulong)sizeof(TJEJPEGHeader), (ulong)(1));
            }

            {
                TJEJPEGComment com     = new TJEJPEGComment();
                ushort         com_len = (ushort)(2 + tjeik_com_str.Count);
                com.com     = (ushort)(tjei_be_word((ushort)(0xfffe)));
                com.com_len = (ushort)(tjei_be_word((ushort)(com_len)));
                memcpy(com.com_str, (void *)(tjeik_com_str), (ulong)(tjeik_com_str.Count));
                tjei_write(state, &com, (ulong)sizeof(TJEJPEGComment), 1);
            }

            tjei_write_DQT(state, state.qt_luma, (byte)(0x00));
            tjei_write_DQT(state, state.qt_chroma, (byte)(0x01));
            {
                TJEFrameHeader header = new TJEFrameHeader();
                header.SOF            = (ushort)(tjei_be_word((ushort)(0xffc0)));
                header.len            = (ushort)(tjei_be_word((ushort)(8 + 3 * 3)));
                header.precision      = (byte)(8);
                header.width          = (ushort)(tjei_be_word((ushort)(width)));
                header.height         = (ushort)(tjei_be_word((ushort)(height)));
                header.num_components = (byte)(3);
                byte *tables = stackalloc byte[3];
                tables[0] = (byte)(0);
                tables[1] = (byte)(1);
                tables[2] = (byte)(1);
                TJEComponentSpec spec = new TJEComponentSpec();
                spec.component_id     = ((byte)(0 + 1));
                spec.sampling_factors = ((byte)(0x11));
                spec.qt = (byte)(tables[0]);
                header.component_spec0 = (TJEComponentSpec)(spec);
                spec.component_id      = ((byte)(1 + 1));
                spec.qt = (byte)(tables[1]);
                header.component_spec1 = (TJEComponentSpec)(spec);
                spec.component_id      = ((byte)(2 + 1));
                spec.qt = (byte)(tables[2]);
                header.component_spec2 = (TJEComponentSpec)(spec);
                tjei_write(state, &header, (ulong)sizeof(TJEFrameHeader), 1);
            }

            tjei_write_DHT(state, state.ht_bits[TJEI_LUMA_DC], state.ht_vals[TJEI_LUMA_DC], (int)(TJEI_DC), (byte)(0));
            tjei_write_DHT(state, state.ht_bits[TJEI_LUMA_AC], state.ht_vals[TJEI_LUMA_AC], (int)(TJEI_AC), (byte)(0));
            tjei_write_DHT(state, state.ht_bits[TJEI_CHROMA_DC], state.ht_vals[TJEI_CHROMA_DC], (int)(TJEI_DC),
                           (byte)(1));
            tjei_write_DHT(state, state.ht_bits[TJEI_CHROMA_AC], state.ht_vals[TJEI_CHROMA_AC], (int)(TJEI_AC),
                           (byte)(1));
            {
                TJEScanHeader header = new TJEScanHeader();
                header.SOS            = (ushort)(tjei_be_word((ushort)(0xffda)));
                header.len            = (ushort)(tjei_be_word((ushort)(6 + (sizeof(TJEFrameComponentSpec) * 3))));
                header.num_components = (byte)(3);
                byte *tables = stackalloc byte[3];
                tables[0] = (byte)(0x00);
                tables[1] = (byte)(0x11);
                tables[2] = (byte)(0x11);
                TJEFrameComponentSpec cs = new TJEFrameComponentSpec();
                cs.component_id        = ((byte)(0 + 1));
                cs.dc_ac               = (byte)(tables[0]);
                header.component_spec0 = (TJEFrameComponentSpec)(cs);
                cs.component_id        = ((byte)(1 + 1));
                cs.dc_ac               = (byte)(tables[1]);
                header.component_spec1 = (TJEFrameComponentSpec)(cs);
                cs.component_id        = ((byte)(2 + 1));
                cs.dc_ac               = (byte)(tables[2]);
                header.component_spec2 = (TJEFrameComponentSpec)(cs);
                header.first           = (byte)(0);
                header.last            = (byte)(63);
                header.ah_al           = (byte)(0);
                tjei_write(state, &header, (ulong)sizeof(TJEScanHeader), 1);
            }

            float *du_y      = stackalloc float[64];
            float *du_b      = stackalloc float[64];
            float *du_r      = stackalloc float[64];
            int    pred_y    = (int)(0);
            int    pred_b    = (int)(0);
            int    pred_r    = (int)(0);
            uint   bitbuffer = (uint)(0);
            uint   location  = (uint)(0);

            for (int y = (int)(0); (y) < (height); y += (int)(8))
            {
                for (int x = (int)(0); (x) < (width); x += (int)(8))
                {
                    for (int off_y = (int)(0); (off_y) < (8); ++off_y)
                    {
                        for (int off_x = (int)(0); (off_x) < (8); ++off_x)
                        {
                            int block_index = (int)(off_y * 8 + off_x);
                            int src_index   = (int)((((y + off_y) * width) + (x + off_x)) * src_num_components);
                            int col         = (int)(x + off_x);
                            int row         = (int)(y + off_y);
                            if ((row) >= (height))
                            {
                                src_index -= (int)((width * (row - height + 1)) * src_num_components);
                            }
                            if ((col) >= (width))
                            {
                                src_index -= (int)((col - width + 1) * src_num_components);
                            }
                            byte  r    = (byte)(src_data[src_index + 0]);
                            byte  g    = (byte)(src_data[src_index + 1]);
                            byte  b    = (byte)(src_data[src_index + 2]);
                            float luma = (float)(0.299f * r + 0.587f * g + 0.114f * b - 128);
                            float cb   = (float)(-0.1687f * r - 0.3313f * g + 0.5f * b);
                            float cr   = (float)(0.5f * r - 0.4187f * g - 0.0813f * b);
                            du_y[block_index] = (float)(luma);
                            du_b[block_index] = (float)(cb);
                            du_r[block_index] = (float)(cr);
                        }
                    }
                    tjei_encode_and_write_MCU(state, du_y, pqt.luma,
                                              ((byte *)state.ehuffsize + TJEI_LUMA_DC * 257), ((ushort *)state.ehuffcode + TJEI_LUMA_DC * 256),
                                              ((byte *)state.ehuffsize + TJEI_LUMA_AC * 257), ((ushort *)state.ehuffcode + TJEI_LUMA_AC * 256),
                                              &pred_y, &bitbuffer, &location);
                    tjei_encode_and_write_MCU(state, du_b, pqt.chroma,
                                              ((byte *)state.ehuffsize + TJEI_CHROMA_DC * 257),
                                              ((ushort *)state.ehuffcode + TJEI_CHROMA_DC * 256),
                                              ((byte *)state.ehuffsize + TJEI_CHROMA_AC * 257),
                                              ((ushort *)state.ehuffcode + TJEI_CHROMA_AC * 256), &pred_b,
                                              &bitbuffer, &location);
                    tjei_encode_and_write_MCU(state, du_r, pqt.chroma,
                                              ((byte *)state.ehuffsize + TJEI_CHROMA_DC * 257),
                                              ((ushort *)state.ehuffcode + TJEI_CHROMA_DC * 256),
                                              ((byte *)state.ehuffsize + TJEI_CHROMA_AC * 257),
                                              ((ushort *)state.ehuffcode + TJEI_CHROMA_AC * 256), &pred_r,
                                              &bitbuffer, &location);
                }
            }
            {
                if (((location) > (0)) && ((location) < (8)))
                {
                    tjei_write_bits(state, &bitbuffer, &location, (ushort)(8 - location), (ushort)(0));
                }
            }

            ushort EOI = (ushort)(tjei_be_word((ushort)(0xffd9)));

            tjei_write(state, &EOI, (ulong)(sizeof(ushort)), (ulong)(1));
            if ((state.output_buffer_count) != 0)
            {
                state.write_context.func(state.write_context.context, state.output_buffer,
                                         (int)(state.output_buffer_count));
                state.output_buffer_count = (ulong)(0);
            }

            return((int)(1));
        }
Example #7
0
        public static void tjei_encode_and_write_MCU(TJEState state, float *mcu, float *qt, byte *huff_dc_len,
                                                     ushort *huff_dc_code, byte *huff_ac_len, ushort *huff_ac_code, int *pred, uint *bitbuffer, uint *location)
        {
            int *  du      = stackalloc int[64];
            float *dct_mcu = stackalloc float[64];

            memcpy(dct_mcu, mcu, (ulong)(64 * sizeof(float)));
            tjei_fdct(dct_mcu);
            for (int i = (int)(0); (i) < (64); ++i)
            {
                state.fval  = (float)(dct_mcu[i]);
                state.fval *= (float)(qt[i]);
                state.fval  = (float)(floorf((float)(state.fval + 1024 + 0.5f)));
                state.fval -= (float)(1024);
                int val = (int)(state.fval);
                du[tjei_zig_zag[i]] = (int)(val);
            }
            ushort *vli  = stackalloc ushort[2];
            int     diff = (int)(du[0] - *pred);

            *pred = (int)(du[0]);
            if (diff != 0)
            {
                tjei_calculate_variable_length_int((int)(diff), vli);
                tjei_write_bits(state, bitbuffer, location, (ushort)(huff_dc_len[vli[1]]),
                                (ushort)(huff_dc_code[vli[1]]));
                tjei_write_bits(state, bitbuffer, location, (ushort)(vli[1]), (ushort)(vli[0]));
            }
            else
            {
                tjei_write_bits(state, bitbuffer, location, (ushort)(huff_dc_len[0]), (ushort)(huff_dc_code[0]));
            }

            int last_non_zero_i = (int)(0);

            for (int i = (int)(63); (i) > (0); --i)
            {
                if (du[i] != 0)
                {
                    last_non_zero_i = (int)(i);
                    break;
                }
            }
            for (int i = (int)(1); i <= last_non_zero_i; ++i)
            {
                int zero_count = (int)(0);
                while ((du[i]) == (0))
                {
                    ++zero_count;
                    ++i;
                    if ((zero_count) == (16))
                    {
                        tjei_write_bits(state, bitbuffer, location, (ushort)(huff_ac_len[0xf0]),
                                        (ushort)(huff_ac_code[0xf0]));
                        zero_count = (int)(0);
                    }
                }
                tjei_calculate_variable_length_int((int)(du[i]), vli);
                ushort sym1 = (ushort)((ushort)(((ushort)(zero_count) << 4) | vli[1]));
                tjei_write_bits(state, bitbuffer, location, (ushort)(huff_ac_len[sym1]), (ushort)(huff_ac_code[sym1]));
                tjei_write_bits(state, bitbuffer, location, (ushort)(vli[1]), (ushort)(vli[0]));
            }
            if (last_non_zero_i != 63)
            {
                tjei_write_bits(state, bitbuffer, location, (ushort)(huff_ac_len[0]), (ushort)(huff_ac_code[0]));
            }

            return;
        }
Example #8
0
        public static unsafe int tje_encode_with_func(WriteCallback2 func,
                                                      void *context,
                                                      int quality,
                                                      int width,
                                                      int height,
                                                      int num_components,
                                                      byte *src_data)
        {
            if (quality < 1 || quality > 3)
            {
                throw new Exception("[ERROR] -- Valid 'quality' values are 1 (lowest), 2, or 3 (highest)");
            }

            var state = new TJEState();

            byte qt_factor = 1;

            switch (quality)
            {
            case 3:
                for (int i = 0; i < 64; ++i)
                {
                    state.qt_luma[i]   = 1;
                    state.qt_chroma[i] = 1;
                }
                break;

            case 1:
            case 2:
                if (quality == 2)
                {
                    qt_factor = 10;
                }
                // don't break. fall through.
                for (int i = 0; i < 64; ++i)
                {
                    state.qt_luma[i] = (byte)(tjei_default_qt_luma_from_spec[i] / qt_factor);
                    if (state.qt_luma[i] == 0)
                    {
                        state.qt_luma[i] = 1;
                    }
                    state.qt_chroma[i] = (byte)(tjei_default_qt_chroma_from_paper[i] / qt_factor);
                    if (state.qt_chroma[i] == 0)
                    {
                        state.qt_chroma[i] = 1;
                    }
                }
                break;

            default:
                throw new Exception("invalid code path");
            }

            var wc = new TJEWriteContext
            {
                context = context,
                func    = func
            };

            state.write_context = wc;
            tjei_huff_expand(state);

            var result = tjei_encode_main(state, src_data, width, height, num_components);

            return(result);
        }