Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Для dxdy, 10 апреля 2018 г.
- // Файл "jpg_coder_fp.c"
- // Положить 24-битный BMP-файл "in.bmp" и запустить программу без аргументов.
- // Или указать как аргумент имя какого-нибудь 24-битного BMP-файла. После
- // работы программы должны получиться JPEG-файлы "out.jpg" и "opt_out.jpg".
- // Вторым аргументом можно указать качество рисунка от 1 до 5.
- //
- // К программе подключен файл оптимизатора "jpg_opt.c", который по ссылке
- // https://pastebin.com/J2aHcGFr
- // В нем нужно отключить тестовую обёртку макросом в строке 920.
- // gcc jpg_coder_fp.c -o jpg_coder_fp.cgi -Wall -Werror -O3
- // ./jpg_coder_fp.cgi
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <limits.h>
- /*****************************************
- * JPEG-кодер содержит 4-е функции кодирования и одну функцию распечатки ошибок.
- * Функции отличаются тем, что одни помещают JPEG-файл в предоставленный извне
- * буфер buf, а другие сразу пишут JPEG-файл в файл fp.
- * Функции отличаются еще наличием аргумента q (quality) -качаство рисунка.
- *
- * int jpg_coder(char *buf, int Sbuf, const char *in, int w, int h, int *err)
- *
- * int jpg_coder_q(char *buf, int Sbuf, const char *in, int w, int h, int *err,
- * int q)
- *
- * int jpg_coder_q_fp(FILE *fp, const char *in, int w, int h, int *err, int q)
- *
- * int jpg_coder_fp(FILE *fp, const char *in, int w, int h, int *err)
- *
- * buf -выходной буфер для JPEG-файла;
- * Sbuf -длина выходного буфера, должна быть достаточна для JPEG-файла;
- * fp -выходной JPEG-файл;
- * in -входной RGB-буфер;
- * w, h -ширина и высота рисунка;
- * err -возвращает ошибку (можно NULL);
- * q -качество рисунка от 1 до 5 (5 -наилучшее качество, но плохое сжатие).
- *
- * Типичное значение q=3, подходит для большинства случаев. Функции, в которых
- * нет этого аргумента, внутри себя устанавливают q=3.
- *
- * Возврат: длина JPEG-файла или -1.
- * Для распечатки ошибок есть функция
- * const char *jpc_strerror(int err);
- *******************************************/
- // макросы ошибок JPEG-кодера
- #define JPC_ERR_WR_FILE 61
- #define JPC_ERR_MEMORY 62
- #define JPC_ERR_INVAL 64
- #define JPC_ERR_CODE 65
- /*
- Схема движения данных.
- |Входной RGB-буфер|
- |
- |<- Преобразование RGB ==> YCbCr
- |
- |s->comp[comp].mblok -буфер на один макроблок|
- |
- |<- Прореживние макроблока
- |
- |s->comp[comp].matr -буфер на один макроблок|
- |
- |<- Дискретно-косинусное преобразование
- |
- |s->comp[comp].dctmatr -буфер на один макроблок|
- |
- |<- Квантование и зигзаг
- |
- |s->comp[comp].matr -буфер на один макроблок|
- |
- |<- Кодирование Хаффмана
- |
- |Выходной поток|
- */
- //--- структура алфавита Хаффмана ---
- struct jpc_alf{
- int cod; // код
- int bits; // длина кода
- };
- //--- обобщенная структура ---
- struct jpc {
- char *pf0; // начало выходного буфера
- char *pf1; // текущая позиция выходного буфера
- char *pf2; // за край выходного буфера
- int w; // ширина
- int h; // высота
- int xblok; // x -размер макроблока
- int yblok; // y -размер макроблока
- char qmatr[64*4]; // матрицы квантования
- int quality; // качество рисунка, от 1 до 5, самое лучшее 5.
- int err;
- int bit_count; // счетчик битов
- unsigned int ch; // буфер битов
- int sizefile; // длина выходного файла
- FILE *fp; // выходной файл
- // указатели на функции записи
- int (*jpc_fputc)(int ch, struct jpc *s);
- int (*jpc_fwrite)(const char *buf, int Selem, int n, struct jpc *s);
- //--- структура компонентов Y Cb Cr ---
- struct{
- int n; // число матриц 8x8 на макроблок
- int mdc; // хранит последний dc-коэффициент
- int matr[64*4]; // матрицы коэффициентов
- int dctmatr[64*4]; // матрицы коэффициентов после DCT
- int mblok[256]; // матрица макроблока
- } comp[3];
- //--- структуры алфавита Хаффмана ---
- struct jpc_alf alf[4*256];
- char buf_hfm[16+16+16+16+12+12+162+162]; // буфер длин кодов символов и
- // самих символов
- const char *hfmtab[4]; // указатели на строку длин кодов в buf_hfm
- int dla[4]; // длины алфавитов
- };
- //------------- jpc_putc_buf -----------
- int jpc_putc_buf(int ch, struct jpc *s)
- {
- if(s->pf1 >= s->pf2){ s->err = JPC_ERR_WR_FILE; return(-1);}
- *s->pf1++ = ch;
- return(ch);
- }
- //----------------- jpc_fwrite_buf ------------
- int jpc_fwrite_buf(const char *buf, int Selem, int n, struct jpc *s)
- {
- int len;
- if(Selem<0 || n<0) return(0);
- if(Selem==0 || n==0) return(n);
- len = Selem * n;
- if(len > (s->pf2 - s->pf1)){
- s->err = JPC_ERR_WR_FILE;
- return(-1);
- }
- memmove(s->pf1, buf, len);
- s->pf1 += len;
- return(n);
- }
- //------------- jpc_putc_fp -----------
- int jpc_putc_fp(int ch, struct jpc *s)
- {
- int k;
- k = fputc(ch, s->fp);
- if(k < 0){ s->err = JPC_ERR_WR_FILE; return(-1);}
- s->sizefile++;
- return(k);
- }
- //----------------- jpc_fwrite_fp ------------
- int jpc_fwrite_fp(const char *buf, int Selem, int n, struct jpc *s)
- {
- int k;
- k = fwrite(buf, Selem, n, s->fp);
- if(k != n){ s->err = JPC_ERR_WR_FILE; return(-1);}
- s->sizefile += (Selem * n);
- return(n);
- }
- //------------- jpc_put_n_bits -------------
- // положить в выходной поток bits бит.
- int jpc_put_n_bits(int cod, int bits, struct jpc *s)
- {
- int val;
- s->ch = (s->ch << bits) + (((1 << bits) - 1) & cod);
- s->bit_count += bits;
- while(s->bit_count >= 8){
- s->bit_count -= 8;
- val=(s->ch >> s->bit_count) & 255;
- if(s->jpc_fputc(val, s) < 0) return(-1);
- if(val==0xFF){
- if(s->jpc_fputc(0, s) < 0) return(-1);
- }
- }
- return(0);
- }
- //------------- jpc_flush_bits --------------
- // сбросить в выходной поток оставшиеся биты
- int jpc_flush_bits(struct jpc *s)
- {
- int val, bits;
- bits = s->bit_count;
- if(bits > 0){
- val = ((s->ch << (8-bits)) | ((1 << (8-bits)) - 1)) & 255;
- if(s->jpc_fputc(val, s) < 0) return(-1);
- if(val==0xFF){
- if(s->jpc_fputc(0, s) < 0) return(-1);
- }
- }
- s->bit_count = s->ch = 0;
- return(0);
- }
- //----------------- jpc_dct --------------
- // прямое DCT (дискретное косинусное преобразование)
- void jpc_dct(int *s, int *d)
- {
- const int arr[64]={ // компенсация DCT преобразователя
- // 4096 * 1/(2*sqrt(2)) * 1/(2*sqrt(2))
- // 4096 * (1.0/(4.0*(cos(PI*y/16.0)))) * (1.0/(4.0*(cos(PI*x/16.0))))
- 512, 369, 392, 435, 512, 651, 945, 1849,
- 369, 266, 282, 314, 369, 469, 681, 1333,
- 392, 282, 300, 333, 392, 498, 723, 1415,
- 435, 314, 333, 370, 435, 554, 803, 1572,
- 512, 369, 392, 435, 512, 651, 944, 1849,
- 651, 469, 498, 554, 651, 828, 1201, 2352,
- 945, 681, 723, 803, 944, 1201, 1743, 3412,
- 1849, 1333, 1415, 1572, 1849, 2352, 3412, 6679,
- };
- int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- int tmp10, tmp11, tmp12, tmp13;
- int z1, z2, z3, z4, z5, z11, z13;
- const int *ps;
- int *pd;
- int i;
- const int A1 = 181; // 256 * cos(4*Pi/16)
- const int A2 = 139; // 256 * (cos(2*Pi/16) - cos(6*Pi/16))
- const int A3 = 181; // 256 * cos(4*Pi/16)
- const int A4 = 334; // 256 * (cos(2*Pi/16) + cos(6*Pi/16))
- const int A5 = 98; // 256 * cos(6*Pi/16)
- pd = d;
- for(i=0; i<64; i+=8){
- ps = s + i;
- tmp0 = ps[0] + ps[7];
- tmp7 = ps[0] - ps[7];
- tmp1 = ps[1] + ps[6];
- tmp6 = ps[1] - ps[6];
- tmp2 = ps[2] + ps[5];
- tmp5 = ps[2] - ps[5];
- tmp3 = ps[3] + ps[4];
- tmp4 = ps[3] - ps[4];
- tmp10 = tmp0 + tmp3;
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
- pd[0] = tmp10 + tmp11;
- pd[4] = tmp10 - tmp11;
- z1 = ((tmp12 + tmp13) * A1)>>8;
- pd[2] = tmp13 + z1;
- pd[6] = tmp13 - z1;
- tmp10 = tmp4 + tmp5;
- tmp11 = tmp5 + tmp6;
- tmp12 = tmp6 + tmp7;
- z5 = ((tmp10 - tmp12) * A5)>>8;
- z2 = ((tmp10 * A2)>>8) +z5;
- z4 = ((tmp12 * A4)>>8) +z5;
- z3 = (tmp11 * A3)>>8;
- z11 = tmp7 + z3;
- z13 = tmp7 - z3;
- pd[5] = z13 + z2;
- pd[3] = z13 - z2;
- pd[1] = z11 + z4;
- pd[7] = z11 - z4;
- pd += 8;
- }
- pd = d;
- for(i=0; i<8; i++){
- tmp0 = pd[8*0] + pd[8*7];
- tmp7 = pd[8*0] - pd[8*7];
- tmp1 = pd[8*1] + pd[8*6];
- tmp6 = pd[8*1] - pd[8*6];
- tmp2 = pd[8*2] + pd[8*5];
- tmp5 = pd[8*2] - pd[8*5];
- tmp3 = pd[8*3] + pd[8*4];
- tmp4 = pd[8*3] - pd[8*4];
- tmp10 = tmp0 + tmp3;
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
- pd[8*0] = tmp10 + tmp11;
- pd[8*4] = tmp10 - tmp11;
- z1 = ((tmp12 + tmp13) * A1)>>8;
- pd[8*2] = tmp13 + z1;
- pd[8*6] = tmp13 - z1;
- tmp10 = tmp4 + tmp5;
- tmp11 = tmp5 + tmp6;
- tmp12 = tmp6 + tmp7;
- z5 = ((tmp10 - tmp12) * A5)>>8;
- z2 = ((tmp10 * A2)>>8) +z5;
- z4 = ((tmp12 * A4)>>8) +z5;
- z3 = (tmp11 * A3)>>8;
- z11 = tmp7 + z3;
- z13 = tmp7 - z3;
- pd[8*5] = z13 + z2;
- pd[8*3] = z13 - z2;
- pd[8*1] = z11 + z4;
- pd[8*7] = z11 - z4;
- pd++;
- }
- for(i=0; i<64; i++) d[i] = (d[i] * arr[i] + 2048) >> 12;
- return;
- }
- //------------- jpc_dct_blok ----------------
- // DCT на один макроблок
- void jpc_dct_blok(struct jpc *s)
- {
- int comp, n;
- for(comp=0; comp<3; comp++){
- for(n=0; n < s->comp[comp].n; n++){
- jpc_dct(s->comp[comp].matr + n*64,
- s->comp[comp].dctmatr + n*64);
- }
- }
- return;
- }
- //----------- jpc_get_hfm_cod -------------
- // инициализация структуры, коды Хаффмана
- void jpc_get_hfm_cod(struct jpc *s)
- {
- // http://www.impulseadventure.com/photo/optimized-jpeg.html
- // Standard
- char *p1;
- //--- длины ---
- const unsigned char DClenY[]={ // 12 (00) яркость
- 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
- };
- const unsigned char DClenCh[]={ // 12 (01) цвет
- 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
- };
- const unsigned char AClenY[]={ // 162 (10) яркость
- 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125
- };
- const unsigned char AClenCh[]={ // 162 (11) цвет
- 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119
- };
- //--- символы ---
- const unsigned char DCsymY[]={ // 12 (00) яркость
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
- };
- const unsigned char DCsymCh[]={ // 12 (01) цвет
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
- };
- const unsigned char ACsymY[]={ // 162 (10) яркость
- 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
- };
- const unsigned char ACsymCh[]={ // 162 (11) цвет
- 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
- };
- p1 = s->buf_hfm;
- s->hfmtab[0] = p1; s->dla[0] = 12;
- memcpy(p1, DClenY, 16); p1 += 16;
- memcpy(p1, DCsymY, 12); p1 += 12;
- s->hfmtab[1] = p1; s->dla[1] = 12;
- memcpy(p1, DClenCh, 16); p1 += 16;
- memcpy(p1, DCsymCh, 12); p1 += 12;
- s->hfmtab[2] = p1; s->dla[2] = 162;
- memcpy(p1, AClenY, 16); p1 += 16;
- memcpy(p1, ACsymY, 162); p1 += 162;
- s->hfmtab[3] = p1; s->dla[3] = 162;
- memcpy(p1, AClenCh, 16); p1 += 16;
- memcpy(p1, ACsymCh, 162); p1 += 162;
- return;
- }
- //----------- jpc_make_h_tree ----------------
- // Таблицы Хаффмана. Заряжаем массив алфавита.
- int jpc_make_h_tree(struct jpc *s, int id)
- {
- int i, j, k, n, len, cod, dla;
- const char *sym, *hfmtab;
- struct jpc_alf *alf;
- alf = s->alf + id*256;
- hfmtab = s->hfmtab[id];
- dla = s->dla[id];
- for(i=0, n=0; i<16; i++) n=n+(hfmtab[i]&255); // подсчет символов
- if(n==0 || n>dla || n>256){ s->err = JPC_ERR_CODE; return(-1);}
- sym = hfmtab + 16;
- for(len=1, cod=0, i=0; len<=16; len++){
- k = hfmtab[len-1] & 255; // число кодов текущей длины
- if(k > 0){
- for(; k>0; k--, i++){
- j = sym[i] & 255;
- alf[j].cod = cod++;
- alf[j].bits = len; // j равно символу алфавита
- }
- if(cod > ((1 << len) - 1)){ s->err = JPC_ERR_CODE; return(-1);}
- }
- cod <<= 1;
- }
- return(n);
- }
- //--------------- jpc_set_hfm ----------------
- // инициализация таблиц Хаффмана для кодирования
- int jpc_set_hfm(struct jpc *s)
- {
- int i;
- jpc_get_hfm_cod(s); // таблицы длин и символов Хаффмана
- for(i=0; i<4; i++){
- if(jpc_make_h_tree(s, i) < 0) return(-1);
- }
- return(0);
- }
- //------------ jpc_get_qmatr ---------------
- // инициирует таблицы квантования
- void jpc_get_qmatr(struct jpc *s)
- {
- const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
- 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
- 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,
- 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; // зигзаг
- int i;
- const unsigned char *q0, *q1;
- // 5
- const unsigned char q0_5[]={
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1
- };
- const unsigned char q1_5[]={
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1
- };
- // 4
- const unsigned char q0_4[]={
- 2, 1, 2, 3, 3, 4, 5, 6,
- 1, 2, 3, 3, 4, 5, 6, 7,
- 2, 3, 3, 4, 5, 6, 7, 8,
- 3, 3, 4, 5, 6, 7, 8, 9,
- 3, 4, 5, 6, 7, 8, 9, 10,
- 4, 5, 6, 7, 8, 9, 10, 11,
- 5, 6, 7, 8, 9, 10, 11, 12,
- 6, 7, 8, 9, 10, 11, 12, 12
- };
- const unsigned char q1_4[]={
- 1, 2, 3, 4, 6, 8, 12, 12,
- 2, 3, 4, 6, 8, 12, 12, 12,
- 3, 4, 6, 8, 12, 12, 12, 12,
- 4, 6, 8, 12, 12, 12, 12, 12,
- 6, 8, 12, 12, 12, 12, 12, 12,
- 8, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12
- };
- // 3 Лучшее квантование
- const unsigned char q0_3[]={
- 2, 2, 3, 4, 6, 8, 12, 16,
- 2, 3, 4, 6, 8, 12, 16, 20,
- 3, 4, 6, 8, 12, 16, 20, 24,
- 4, 6, 8, 12, 16, 20, 24, 28,
- 6, 8, 12, 16, 20, 24, 28, 32,
- 8, 12, 16, 20, 24, 28, 32, 36,
- 12, 16, 20, 24, 28, 32, 36, 36,
- 16, 20, 24, 28, 32, 36, 36, 36
- };
- const unsigned char q1_3[]={
- 16, 12, 14, 16, 18, 24, 32, 60,
- 12, 14, 16, 18, 24, 32, 60, 80,
- 14, 16, 18, 24, 32, 60, 80, 100,
- 16, 18, 24, 32, 60, 80, 100, 120,
- 18, 24, 32, 60, 80, 100, 120, 140,
- 24, 32, 60, 80, 100, 120, 140, 160,
- 32, 60, 80, 100, 120, 140, 160, 180,
- 60, 80, 100, 120, 140, 160, 180, 200
- };
- // 2
- const unsigned char q0_2[]={
- 12, 12, 14, 16, 18, 24, 32, 60,
- 12, 14, 16, 18, 24, 32, 60, 80,
- 14, 16, 18, 24, 32, 60, 80, 100,
- 16, 18, 24, 32, 60, 80, 100, 120,
- 18, 24, 32, 60, 80, 100, 120, 140,
- 24, 32, 60, 80, 100, 120, 140, 160,
- 32, 60, 80, 100, 120, 140, 160, 180,
- 60, 80, 100, 120, 140, 160, 180, 200
- };
- const unsigned char q1_2[]={
- 12, 12, 14, 16, 18, 24, 32, 60,
- 12, 14, 16, 18, 24, 32, 60, 80,
- 14, 16, 18, 24, 32, 60, 80, 100,
- 16, 18, 24, 32, 60, 80, 100, 120,
- 18, 24, 32, 60, 80, 100, 120, 140,
- 24, 32, 60, 80, 100, 120, 140, 160,
- 32, 60, 80, 100, 120, 140, 160, 180,
- 60, 80, 100, 120, 140, 160, 180, 200
- };
- // 1
- const unsigned char q0_1[]={
- 30, 30, 50, 80, 100, 200, 200, 200,
- 30, 50, 80, 100, 200, 200, 200, 200,
- 50, 80, 100, 200, 200, 200, 200, 200,
- 80, 100, 200, 200, 200, 200, 200, 200,
- 100, 200, 200, 200, 200, 200, 200, 200,
- 200, 200, 200, 200, 200, 200, 200, 200,
- 200, 200, 200, 200, 200, 200, 200, 200,
- 200, 200, 200, 200, 200, 200, 200, 200
- };
- const unsigned char q1_1[]={
- 50, 50, 50, 100, 200, 200, 200, 200,
- 50, 50, 100, 200, 200, 200, 200, 200,
- 50, 100, 200, 200, 200, 200, 200, 200,
- 100, 200, 200, 200, 200, 200, 200, 200,
- 200, 200, 200, 200, 200, 200, 200, 200,
- 200, 200, 200, 200, 200, 200, 200, 200,
- 200, 200, 200, 200, 200, 200, 200, 200,
- 200, 200, 200, 200, 200, 200, 200, 200
- };
- q0=q0_3; q1=q1_3;
- if(s->quality <= 1){ q0=q0_1; q1=q1_1;}
- if(s->quality == 2){ q0=q0_2; q1=q1_2;}
- if(s->quality == 3){ q0=q0_3; q1=q1_3;}
- if(s->quality == 4){ q0=q0_4; q1=q1_4;}
- if(s->quality >= 5){ q0=q0_5; q1=q1_5;}
- for(i=0; i<64; i++) s->qmatr[i] = q0[(int)(njZZ[i])];
- for(i=0; i<64; i++) s->qmatr[i+64] = q1[(int)(njZZ[i])];
- return;
- }
- //-------------------- jpc_get_blok ---------------------
- // RGB ==> jpc->comp[comp].mblok 16х16 пикселей Y Cb Cr
- // in -показывает место верхнего левого пикселя текущего макроблока
- // во входном RGB буфере
- void jpc_get_blok(struct jpc *s, int xblok, int yblok, const char *in)
- {
- int *p, i, k, n;
- int kr, kg, kb;
- int *pY, *pB, *pR;
- int x, y, xm, ym;
- const char *pin;
- if(s->xblok > xblok) xm=xblok; else xm=s->xblok;
- if(s->yblok > yblok) ym=yblok; else ym=s->yblok;
- pY = s->comp[0].mblok;
- pB = s->comp[1].mblok;
- pR = s->comp[2].mblok;
- for(y=0; y < ym; y++){
- pin=in +(s->w * 3 * y);
- for(x=0; x < xm; x++){
- kr = (*pin++)&255;
- kg = (*pin++)&255;
- kb = (*pin++)&255;
- *pY++ = (( 77*kr + 150*kg + 29*kb + 128)>>8)-128;
- *pB++ = ((-43*kr - 85*kg + 128*kb + 128)>>8);
- *pR++ = ((128*kr - 107*kg - 21*kb + 128)>>8);
- }
- if(x < s->xblok){
- n = s->xblok - x;
- for(k = *(pY-1), i=0; i<n; i++) *pY++ = k;
- for(k = *(pB-1), i=0; i<n; i++) *pB++ = k;
- for(k = *(pR-1), i=0; i<n; i++) *pR++ = k;
- }
- }
- if(y < s->yblok){
- n = (s->yblok - y) * 16;
- for(p=pY-16, i=0; i<n; i++) *pY++ = *p++;
- for(p=pB-16, i=0; i<n; i++) *pB++ = *p++;
- for(p=pR-16, i=0; i<n; i++) *pR++ = *p++;
- }
- return;
- }
- //----------------- jpc_red_blok ----------------
- // прореживает массив jpc->comp[comp].mblok 16х16 и распределяет
- // по матрицам jpc->comp[comp].matr 8х8
- void jpc_red_blok(struct jpc *s)
- {
- int *pin, *p0, *p1, *p2, y, i;
- // создаем четыре Y-матрицы
- pin = s->comp[0].mblok;
- p1 = s->comp[0].matr;
- p0=p1;
- for(y=0; y<16; y++){
- if(y!=8) p1=p0;
- for(p2=p1+8; p1<p2;) *p1++ = *pin++;
- p0=p1;
- p1 += 56;
- for(p2=p1+8; p1<p2;) *p1++ = *pin++;
- }
- // создаем по одной Cb и Cr матрице
- for(i=1; i<=2; i++){
- pin = s->comp[i].mblok;
- p1 = s->comp[i].matr;
- for(y=0; y<8; y++){
- for(p2=p1+8; p1<p2;){
- *p1++ = (*pin + *(pin+1) + *(pin+16) + *(pin+17) + 2)>>2;
- pin += 2;
- }
- pin += 16;
- }
- }
- return;
- }
- //------------- jpc_quant ------------
- // деление (a / q) с округлением
- int jpc_quant(int a, int q)
- {
- int k;
- q &=255;
- k = q >> 1;
- if(a<0) return((a - k) / q);
- return((a + k) / q);
- }
- //----------------- jpc_qnt_blok ----------------
- // квантует и зигзажит матрицы jpc->comp[comp].dctmatr 8х8
- // результат в матрицах jpc->comp[comp].matr (на один макроблок)
- void jpc_qnt_blok(struct jpc *s)
- {
- const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
- 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
- 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,
- 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; // зигзаг
- int *p1;
- int comp, i, k, n;
- char *pq;
- int *pin;
- for(comp=0; comp<3; comp++){
- p1 = s->comp[comp].matr;
- if(comp==0) pq = s->qmatr;
- else pq = s->qmatr + 64;
- for(n=0; n < s->comp[comp].n; n++){
- pin = s->comp[comp].dctmatr + n*64;
- k = jpc_quant(pin[0], pq[0]);
- *p1++ = k - s->comp[comp].mdc;
- s->comp[comp].mdc = k;
- for(i=1; i<64; i++){
- *p1++ = jpc_quant(pin[(int)njZZ[i]], pq[i]);
- };
- }
- }
- return;
- }
- //--------- conv_kf -----------------
- // преобразование коэффициента в дополнительный код и ограничение
- int conv_kf(int val, int *bits, int limit)
- {
- int k, bits0=0;
- if(val < 0){
- if(val < -limit) val = -limit;
- for(k = -val; k != 0; k >>= 1) bits0++;
- val = val - 1 - ((-1) << bits0);
- }
- else{
- if(val > limit) val = limit;
- for(k = val; k != 0; k >>= 1) bits0++;
- }
- *bits = bits0;
- return(val);
- }
- //------------- jpc_put_kf ----------------
- // положить в файл один коэффициент (код Хаффмана и EXTRA-биты)
- int jpc_put_kf(struct jpc *s, struct jpc_alf *alf, int hcod, int val, int bits)
- {
- if(alf[hcod].bits <=0){ s->err = JPC_ERR_CODE; return(-1);}
- if(jpc_put_n_bits(alf[hcod].cod, alf[hcod].bits, s) < 0) return(-1);
- if(bits > 0){
- if(jpc_put_n_bits(val, bits, s) < 0) return(-1);
- }
- return(0);
- }
- //------------------- jpc_coding_matr ----------------
- // кодирует и пишет в файл матрицу 8х8, на которую показывает p0
- int jpc_coding_matr(struct jpc *s, int *p0, int comp)
- {
- struct jpc_alf *pDC, *pAC;
- int zn, hcod, bits, val;
- int *p1, *p2;
- if(comp==0){ // выбираем подходящий алфавит Хаффмана
- pDC = s->alf;
- pAC = s->alf + 512;
- }
- else{
- pDC = s->alf + 256;
- pAC = s->alf + 768;
- }
- // обработка DC коэффициента
- if(*p0 == 0){ // DC=0 кодируется нулевым кодом Хаффмана
- if(jpc_put_kf(s, pDC, 0, 0, 0) < 0) return(-1);
- }
- else{
- val = conv_kf(*p0, &bits, 2047);
- hcod = bits;
- if(jpc_put_kf(s, pDC, hcod, val, bits) < 0) return(-1);
- }
- // обработка AC коэффициентов
- for(zn=0, p1=p0+1, p2=p0+64; p1<p2; p1++){
- if(*p1 != 0){
- val = conv_kf(*p1, &bits, 1023);
- while(zn >= 16){
- if(jpc_put_kf(s, pAC, 0xF0, 0, 0) < 0) return(-1);
- zn -= 16;
- }
- hcod = (zn << 4) | bits;
- if(jpc_put_kf(s, pAC, hcod, val, bits) < 0) return(-1);
- zn = 0;
- }
- else zn++;
- }
- if(zn != 0){
- if(jpc_put_kf(s, pAC, 0, 0, 0) < 0) return(-1);
- }
- return(0);
- }
- //------------------- jpc_coding_blok ----------------
- // кодирует и пишет в файл один макроблок
- int jpc_coding_blok(struct jpc *s)
- {
- int i;
- for(i=0; i<4; i++){
- if(jpc_coding_matr(s, s->comp[0].matr + i*64, 0) < 0) return(-1);
- }
- if(jpc_coding_matr(s, s->comp[1].matr, 1) < 0) return(-1);
- if(jpc_coding_matr(s, s->comp[2].matr, 2) < 0) return(-1);
- return(0);
- }
- //----------------- jpc_scan ------------
- int jpc_scan(struct jpc *s, const char *in)
- {
- const char *pin; // pin -показывает место верхнего левого пикселя
- // текущего макроблока во входном буфере
- const char *pin0; // начало текущей полосы макроблоков
- int x, y; // счетчики макроблоков по горизонтали и по вертикали
- int xss, yss; // размер рабочей части текущего макроблока
- int xm; // ширина рисунка в макроблоках
- int ym; // высота рисунка в макроблоках
- int xs; // рабочий кусок правых макроблоков
- int ys; // рабочий кусок нижних макроблоков
- xm = (s->w + s->xblok - 1)/s->xblok;
- ym = (s->h + s->yblok - 1)/s->yblok;
- xs = s->xblok - (xm * s->xblok - s->w);
- ys = s->yblok - (ym * s->yblok - s->h);
- yss = s->yblok;
- pin = pin0 = in;
- for(y=0; y<ym; y++){
- if(y>0) pin = pin0 = pin0 + 3 * s->w * s->yblok;
- if(y>=(ym-1)) yss = ys;
- xss = s->xblok;
- for(x=0; x<xm; x++){
- if(x>0) pin += s->xblok * 3;
- if(x>=(xm-1)) xss = xs;
- jpc_get_blok(s, xss, yss, pin);
- jpc_red_blok(s);
- jpc_dct_blok(s);
- jpc_qnt_blok(s);
- if(jpc_coding_blok(s) < 0) return(-1);
- }
- }
- return(0);
- }
- //----------------------- jpc_hdr_jpg -----------------------
- // заголовок JPEG-файла
- int jpc_hdr_jpg(struct jpc *s)
- {
- char buf[2];
- unsigned char aC0[]={ // общая часть (C0)
- // | высота | ширина |
- 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01
- };
- const unsigned char aDA[]={ // скан (DA)
- 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02,
- 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00
- };
- const unsigned char aD8[]={0xFF, 0xD8};
- const unsigned char aDB[]={0xFF, 0xDB, 0x00, 0x43};
- const unsigned char aC4[]={0xFF, 0xC4};
- int i, dl;
- if(s->jpc_fwrite((char*)aD8, 2, 1, s) < 0) return(-1); // (D8)
- for(i=0; i < 2; i++){ // таблицы квантования (DB)
- if(s->jpc_fwrite((char*)aDB, 4, 1, s) < 0) return(-1);
- buf[0]=i;
- if(s->jpc_fwrite(buf, 1, 1, s) < 0) return(-1);
- if(s->jpc_fwrite(s->qmatr + 64*i, 64, 1, s) < 0) return(-1);
- }
- aC0[5] = s->h >> 8; aC0[6] = s->h & 255;
- aC0[7] = s->w >> 8; aC0[8] = s->w & 255;
- if(s->jpc_fwrite((char*)aC0, sizeof(aC0), 1, s) < 0) return(-1); //(C0)
- for(i=0; i < 4; i++){ // таблицы Хаффмана (C4)
- if(s->jpc_fwrite((char*)aC4, 2, 1, s) < 0) return(-1);
- dl = 3 + 16 + s->dla[i]; // длина блока
- buf[0]= dl>>8;
- buf[1]= dl&255;
- if(s->jpc_fwrite(buf, 2, 1, s) < 0) return(-1);
- buf[0] = ((i<<3) & 16) + (i & 1); //класс и идентификатор
- if(s->jpc_fwrite(buf, 1, 1, s) < 0) return(-1);
- // длины и символы
- if(s->jpc_fwrite(s->hfmtab[i], dl-3, 1, s) < 0) return(-1);
- }
- if(s->jpc_fwrite((char*)aDA, sizeof(aDA), 1, s) < 0) return(-1); //(DA)
- return(0);
- }
- //------------------- jpc_fun_coder ------------------------
- int jpc_fun_coder(struct jpc *s, const char *in)
- {
- const unsigned char aD9[]={0xFF, 0xD9};
- jpc_get_qmatr(s); // таблицы квантования
- if(jpc_set_hfm(s) < 0) return(-1); // таблицы Хаффмана
- if(jpc_hdr_jpg(s) < 0) return(-1);
- if(jpc_scan(s, in) < 0) return(-1);
- if(jpc_flush_bits(s) < 0) return(-1);
- if(s->jpc_fwrite((char*)aD9, 2, 1, s) < 0) return(-1);
- return(0);
- }
- //-------------- jpc_init_jpc ------------------
- void jpc_init_jpc(struct jpc *s, int w, int h, int q)
- {
- memset(s, 0, sizeof(struct jpc));
- s->w = w;
- s->h = h;
- s->xblok = 16; // пикселей на макроблок по горизонтали
- s->yblok = 16; // пикселей на макроблок по вертикали
- s->comp[0].n = 4; // матриц на макроблок для Y
- s->comp[1].n = 1; // матриц на макроблок для Cb
- s->comp[2].n = 1; // матриц на макроблок для Cr
- s->quality = q; //
- return;
- }
- //------------------ jpg_coder_q --------------------------
- // q -качество рисунка, от 1 до 5. Самое лучшее 5. Типичное 3.
- int jpg_coder_q(char *buf, int Sbuf, const char *in, int w, int h, int *err,
- int q)
- {
- struct jpc *s = NULL;
- int k, err0;
- if(buf==NULL || Sbuf<0 || in==NULL || w<1 || w>32767 || h<1 || h>32767 ||
- q < 1 || q > 5 || (INT_MAX / 4 / (int)sizeof(short) / w) < h)
- {
- err0 = JPC_ERR_INVAL; goto ERR;
- }
- s = (struct jpc*)malloc(sizeof(struct jpc));
- if(s==NULL){ err0 = JPC_ERR_MEMORY; goto ERR;}
- // инициализация структуры jpc
- jpc_init_jpc(s, w, h, q);
- s->pf0 = s->pf1 = buf; // на начало выходного буфера
- s->pf2 = buf + Sbuf; // за край выходного буфера
- s->jpc_fputc = jpc_putc_buf;
- s->jpc_fwrite = jpc_fwrite_buf;
- k=jpc_fun_coder(s, in);
- if(k<0){ err0 = s->err; goto ERR;}
- k = s->pf1 - s->pf0; // длина файла в буфере buf
- free(s);
- if(err != NULL) *err=0;
- return(k);
- ERR:
- if(s != NULL) free(s);
- if(err != NULL) *err = err0;
- return(-1);
- }
- //------------------ jpg_coder --------------------------
- int jpg_coder(char *buf, int Sbuf, const char *in, int w, int h, int *err)
- {
- return(jpg_coder_q(buf, Sbuf, in, w, h, err, 3));
- }
- //------------------ jpg_coder_q_fp --------------------------
- // q -качество рисунка, от 1 до 5. Самое лучшее 5. Типичное 3.
- int jpg_coder_q_fp(FILE *fp, const char *in, int w, int h, int *err, int q)
- {
- struct jpc *s = NULL;
- int k, err0;
- if(fp==NULL || in==NULL || w<1 || w>32767 || h<1 || h>32767 ||
- q < 1 || q > 5 || (INT_MAX / 4 / (int)sizeof(short) / w) < h)
- {
- err0 = JPC_ERR_INVAL; goto ERR;
- }
- s = (struct jpc*)malloc(sizeof(struct jpc));
- if(s==NULL){ err0 = JPC_ERR_MEMORY; goto ERR;}
- // инициализация структуры jpc
- jpc_init_jpc(s, w, h, q);
- s->fp = fp; // выходной файл
- s->jpc_fputc = jpc_putc_fp;
- s->jpc_fwrite = jpc_fwrite_fp;
- k=jpc_fun_coder(s, in);
- if(k<0){ err0 = s->err; goto ERR;}
- k = s->sizefile; // длина JPEG-файла
- free(s);
- if(err != NULL) *err=0;
- return(k);
- ERR:
- if(s != NULL) free(s);
- if(err != NULL) *err = err0;
- return(-1);
- }
- //------------------ jpg_coder_fp --------------------------
- int jpg_coder_fp(FILE *fp, const char *in, int w, int h, int *err)
- {
- return(jpg_coder_q_fp(fp, in, w, h, err, 3));
- }
- //------------------ jpc_strerror ---------------------
- const char *jpc_strerror(int err)
- {
- switch(err){
- case JPC_ERR_WR_FILE : return("JPC_ERR_WR_FILE");
- case JPC_ERR_MEMORY : return("JPC_ERR_MEMORY");
- case JPC_ERR_CODE : return("JPC_ERR_CODE");
- case JPC_ERR_INVAL : return("JPC_ERR_INVAL");
- }
- return("JPC: Unknow error");
- }
- //============= Тестовая обертка ====================
- // Положить 24-битный BMP-файл "in.bmp" и запустить программу без аргументов.
- // Или указать как аргумент имя какого-нибудь 24-битного BMP-файла. После
- // работы программы должны получиться JPEG-файлы "out.jpg" и "opt_out.jpg".
- // Вторым аргументом можно указать качество рисунка от 1 до 5.
- #include <sys/time.h>
- #include "jpg_opt.c"
- //------------------ rd_bmp_24_RGB ------------------
- char *rd_bmp_24_RGB(FILE *fp1, int *w, int *h)
- {
- unsigned char buf[54];
- char *pic=NULL, *p1;
- int i, j, r, g, b, w1, w3, h1, pad=0, uk;
- if(fread(buf, 54, 1, fp1) != 1) goto ERR;
- if(memcmp(buf, "BM", 2)!=0) goto ERR;
- if(memcmp(buf+30, "\0\0\0\0", 4)!=0) goto ERR;
- if(memcmp(buf+28, "\x18\0", 2)!=0) goto ERR;
- w1 = buf[18] + (buf[19]<<8) + (buf[20]<<16) + (buf[21]<<24);
- h1 = buf[22] + (buf[23]<<8) + (buf[24]<<16) + (buf[25]<<24);
- uk = buf[10] + (buf[11]<<8) + (buf[12]<<16) + (buf[13]<<24);
- if(fseek(fp1, uk, 0) < 0) goto ERR;
- *w=w1; *h=h1;
- w3=w1*3;
- if(w3 & 3) pad = 4 - (w3 & 3);
- pic=(char*)malloc(w3*h1);
- if(pic==NULL) goto ERR;
- p1=pic + w3*h1;
- for(i=0; i<h1; i++){
- p1 -= w3;
- for(j=0; j<w1; j++){
- if((b = fgetc(fp1)) < 0) goto ERR;
- if((g = fgetc(fp1)) < 0) goto ERR;
- if((r = fgetc(fp1)) < 0) goto ERR;
- *p1++ = r; *p1++ = g; *p1++ = b;
- }
- p1 -= w3;
- if(pad>0) if(fread(buf, pad, 1, fp1) != 1) goto ERR;
- }
- return(pic);
- ERR:
- if(pic != NULL) free(pic);
- *w=0; *h=0;
- return(NULL);
- }
- //------------------- gettime_dt_mks ----------------------
- // разность двух временных меток в миллисекундах
- int gettime_dt_msek(struct timeval *tv1, struct timeval *tv2)
- {
- return((tv2->tv_sec - tv1->tv_sec)*1000 +
- (tv2->tv_usec - tv1->tv_usec + 500)/1000);
- }
- //--------------- main -----------------
- int main(int argc, char const **argv)
- {
- FILE *fp1=NULL, *fp2=NULL, *fp3=NULL;
- const char *f1;
- const char *f2="out.jpg";
- const char *f3="opt_out.jpg";
- int k, dl1, dl2, t, quality;
- int w, h, err;
- char *buf=NULL, *pic=NULL;
- int Sbuf;
- struct timeval tv1, tv2;
- printf("============================\n");
- if(argc<=1) f1 = "in.bmp";
- else f1 = argv[1];
- if(argc > 2) quality = atoi(argv[2]);
- else quality=3;
- fp1=fopen(f1, "r");
- if(fp1==NULL){ printf("fp1=fopen(%s)=NULL\n", f1); goto ERR;}
- // чтение BMP-файла
- pic = rd_bmp_24_RGB(fp1, &w, &h);
- if(pic==NULL){ printf("pic = rd_bmp_24_RGB(%s)=NULL\n", f1); goto ERR;}
- fclose(fp1); fp1=NULL;
- // буфер для JPEG-файла
- Sbuf = w*h + 1000;
- buf = (char*)malloc(Sbuf);
- if(buf==NULL){ printf("buf=NULL\n"); goto ERR;}
- // JPEG-кодирование
- gettimeofday(&tv1, NULL);
- dl1 = jpg_coder_q(buf, Sbuf, pic, w, h, &err, quality);
- printf("dl1=jpg_coder_q()=%d; err=%d", dl1, err);
- gettimeofday(&tv2, NULL);
- t = gettime_dt_msek(&tv1, &tv2);
- if(dl1<0) printf("; %s", jpc_strerror(err));
- printf("\n");
- printf("w=%d; h=%d\n", w, h);
- printf("t=%d.%03d sec\n", t/1000, t%1000);
- if(dl1>0 && (w*h)>0) printf("Compress=%0.2f %%\n", 100.0 * dl1 / (w*h*3));
- else goto ERR;
- free(pic); pic=NULL;
- // запись неоптимизированного файла
- fp2=fopen(f2, "w");
- if(fp2==NULL){ printf("fp2=fopen(%s)=NULL\n", f2); goto ERR;}
- k = fwrite(buf, 1, dl1, fp2);
- if(k != dl1){ printf("k = fwrite()=%d; dl1=%d\n", k, dl1); goto ERR;}
- fclose(fp2); fp2=NULL;
- //exit(0);
- // оптимизация
- printf("-------------\n");
- fp3=fopen(f3, "w");
- if(fp3==NULL){ printf("fp3=fopen(%s)=NULL\n", f3); goto ERR;}
- gettimeofday(&tv1, NULL);
- dl2 = fjp_opt_hfm(buf, dl1, fp3, &w, &h, &err); // оптимизация
- gettimeofday(&tv2, NULL);
- t = gettime_dt_msek(&tv1, &tv2);
- printf("-------------\n");
- printf("dl2 = fjp_opt_hfm()=%d; err=%d; ", dl2, err);
- printf("%s\n", err==0 ? "" : fjp_strerror(err));
- printf("w=%d; h=%d\n", w, h);
- printf("t=%d.%03d sec\n", t/1000, t%1000);
- printf("dl1=%d\n", dl1);
- printf("dl2=%d\n", dl2);
- printf("n1_FF=%d\n", n1_FF);
- printf("n2_FF=%d\n", n2_FF);
- printf("delta_FF=%d\n", n1_FF - n2_FF);
- printf("d1_DA=%d\n", e1_DA - b1_DA);
- printf("d2_DA=%d\n", e2_DA - b2_DA);
- printf("delta_DA=%d\n", (e1_DA - b1_DA) - (e2_DA - b2_DA));
- printf("delta_C4=%d\n", d1_C4 - d2_C4);
- printf("delta_dl=%d\n", dl1 - dl2);
- if(dl1>0 && dl2>0){
- printf("Compress=%0.2f\n", 100.0 * dl2 / dl1);
- }
- free(buf);
- fclose(fp3);
- printf("============================\n");
- exit(0);
- ERR:
- if(pic!=NULL) free(pic);
- if(buf!=NULL) free(buf);
- if(fp1!=NULL) fclose(fp1);
- if(fp2!=NULL) fclose(fp2);
- if(fp3!=NULL) fclose(fp3);
- printf("============================\n");
- exit(0);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement