Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Для dxdy, 10 апреля 2018 г.
- // Файл "jpg_opt.c"
- // Аргументом указать имя входного JPEG-файла. После работы программы
- // должен получиться оптимизированный файл "test.jpg".
- // gcc jpg_opt.c -o jpg_opt.cgi -Wall -Werror -O3
- // ./jpg_opt.cgi
- /***************************************************
- * Функция оптимизации кодов Хаффмана в JPEG-файле.
- * Для JPEG-файлов, закодированных базовым способом (baseline).
- *
- * int fjp_opt_hfm(const char *in_buf, int len_in_buf, FILE *fp,
- * int *w, int *h, int *err)
- *
- * in_buf -входной буфер содержит JPEG-файл;
- * len_in_buf -длина данных во входном буфере;
- * fp -выходной файл;
- * w, h -ширина и высота;
- * err -возврат ошибки, можно NULL.
- *
- * Возврат: длина выходного файла или -1.
- * Для распечатки ошибок есть функция
- * const char *fjp_strerror(int err)
- * **************************************************/
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <limits.h>
- #define FJP_FL_TEST 1 // 0 -тестовая распечатка выключена, 1 -включена
- // макросы ошибок
- #define FJP_ERR_RD_FILE 1
- #define FJP_ERR_SYNTAX 2
- #define FJP_ERR_NOT_SUPPORT 3
- #define FJP_ERR_MEMORY 4
- #define FJP_ERR_DECODE 5
- #define FJP_ERR_INVAL 6
- #define FJP_ERR_WR_FILE 7
- // отладочные глобальные переменные
- int n1_FF = 0; // счетчик байтов 0xFF в скане входного файла
- int n2_FF = 0; // счетчик байтов 0xFF в скане выходного файла
- int d1_C4 = 0; // длина таблиц Хаффмана во входном файле
- int d2_C4 = 0; // длина таблиц Хаффмана в выходном файле
- int b1_DA = 0; // начало скана во входном файле
- int e1_DA = 0; // конец скана во входном файле
- int b2_DA = 0; // начало скана в выходном файле
- int e2_DA = 0; // конец скана в выходном файле
- int fl = 0; // для функции оптимизации, для максимальной длины кодов
- int maxlen = 0; // максимальная длина кода до уменьшения
- //--- таблицы Хаффмана (кодирование) ---
- // вынесены в отдельную структуру, чтоб не обнулялись
- // на второй проход.
- // структура для построения дерева Хаффмана
- struct s_fjp_tree {
- unsigned int a[257];
- unsigned int b[257];
- int pa[257];
- int pp[257];
- int p[257];
- int bl_count[257];
- };
- // структура кодов Хаффмана
- struct s_fjp_sym {
- unsigned int freq; // частота символа
- int hcod; // код Хаффмана
- int bits; // длина кода Хаффмана
- };
- // обобщенная структура для кодирования Хаффмана
- struct s_fjp1 {
- struct s_fjp_tree tree[1];
- struct {
- struct s_fjp_sym sym[256];
- int n;
- char buf[16+256]; // таблицы для файла JPEG
- } fsym[8];
- };
- //--- обобщенная структура ---
- struct s_fjp {
- const char *p0; // начало входного буфера
- const char *p1; // текущая позиция входного буфера
- const char *p2; // за край данных входного буфера
- char buf_C4[2048]; // буфер для подменных таблиц Хаффмана
- char buf[8192]; // вспомогательный буфер
- int rstN; // число макроблоков рестарта
- int rstn; // счетчик макроблоков рестарта
- int nextrst; // счетчик циклов рестарта
- int idcomp[4]; // идентификаторы компрнентов
- int dchfm[4]; // номера DC-таблиц Хаффмана в массиве shfm
- int achfm[4]; // номера AC-таблиц Хаффмана в массиве shfm
- int w; // ширина
- int h; // высота
- int ncomp; // число компонентов
- int fl_start; // счетчик сканов
- int xblok; // x -размер макроблока в пикселях
- int yblok; // y -размер макроблока в пикселях
- int xm; // ширина рисунка в макроблоках (с краевыми)
- int ym; // высота рисунка в макроблоках (с краевыми)
- int nblok; // общее число макроблоков
- int bit_count; // счетчик битов (декодирование)
- unsigned long ch; // буфер битов (декодирование)
- int bit_count2; // счетчик битов (кодирование)
- unsigned long ch2; // буфер битов (кодирование)
- int err;
- //--- структура компонентов ---
- struct{
- int dchfm; // DC-таблица Хаффмана в массиве shfm (ниже)
- int achfm; // AC-таблица Хаффмана в массиве shfm (ниже)
- int nx; // число матриц на макроблок в ширину
- int ny; // число матриц на макроблок в высоту
- int n; // число матриц на макроблок
- } comp[4];
- //--- таблицы Хаффмана (декодирование) ---
- struct{
- char sym[256]; // список символов в порядке возрастания кода
- int n; // число символов
- int max[17]; // Все коды длины len меньше max[len]
- int idx[17]; // Если код Хаффмана прибавить к элементу этого массива
- // для соответствующей длины кода, то получится индекс
- // массива sym, по которому лежит нужный символ
- // i = idx[len] + cod; symbol = sym[i];
- } shfm[8];
- struct s_fjp1 *s1; // структура вынесена, чтоб не обнулялась вместе с этой
- int fl; // 0 -первый проход; 1 -второй
- FILE *fp; // выходной файл
- int sizefile; // длина файла
- };
- //-------------- fjp_hfm_code --------------------
- // расчет кодов Хаффмана
- // buf -сюда заряжает таблицу кодов для файла JPEG
- int fjp_hfm_code(struct s_fjp_tree *tree, struct s_fjp_sym *sym, char *buf)
- {
- int i, j, k, n, cod, bits, len;
- unsigned int t, aa, ab, bb;
- unsigned int *a = tree->a; // частоты листьев
- unsigned int *b = tree->b; // частоты узлов
- int *pa = tree->pa; // родительский узел листа
- int *pp = tree->pp; // родительский узел узла
- int *p = tree->p; // номер символа, его значение
- int *bl_count = tree->bl_count; // счетчики числа кодов для разных длин
- // зарядка исходных массивов (a[0] -подставной символ)
- memset(tree, 0, sizeof(struct s_fjp_tree));
- for(a[0]=1, i=0, n=1; i < 256; i++){
- if(sym[i].freq > 0){
- a[n] = sym[i].freq;
- p[n++] = i;
- }
- }
- memset(buf, 0, 16+n-1);
- if(n==1) return(0); // n -число используемых символов алфавита + 1
- if(n==2){ bl_count[1] += 2; goto RET;}
- // сортировка по возрастанию частоты символов
- for(i=1; i<n; i++){
- for(j=n-1; j>i; j--){
- if(a[j] < a[j-1]){
- t = a[j]; a[j] = a[j-1]; a[j-1] = t;
- t = p[j]; p[j] = p[j-1]; p[j-1] = t;
- }
- }
- }
- // создание дерева
- for(k=0, i=0, j=0; k<(n-1); k++){
- if(i<(n-1)) aa = a[i] + a[i+1]; else aa = UINT_MAX;
- if(i<n && j<k) ab = a[i] + b[j]; else ab = UINT_MAX;
- if(j<(k-1)) bb = b[j] + b[j+1]; else bb = UINT_MAX;
- if(aa <= ab && aa <= bb){
- b[k] = aa;
- pa[i++] = k; pa[i++] = k; // родительский узел
- }
- else if(ab <= aa && ab <= bb){
- b[k] = ab;
- pa[i++] = k; pp[j++] = k; // родительский узел
- }
- else{
- b[k] = bb;
- pp[j++] = k; pp[j++] = k; // родительский узел
- }
- }
- // обход дерева
- for(--k, i=0; i<n; i++){ // k -индекс корневого узла
- for(len=1, j=pa[i]; j<k; j=pp[j], len++);
- bl_count[len]++;
- }
- // уменьшение длин кодов
- for(i=n-1; i>16; i--){
- for(; bl_count[i]>0;){
- if(fl==0){ //-------------------------------отладочная-------
- maxlen = i;
- fl=1;
- }
- for(j=i-2; j>0 && bl_count[j]<=0; j--);
- bl_count[i] -= 2;
- bl_count[i-1]++;
- bl_count[j]--;
- bl_count[j+1] += 2;
- }
- }
- RET:
- // зарядка выходного массива
- for(k=16; k>0 && bl_count[k]==0; k--);
- bl_count[k]--; // удаление подставного символа
- for(i=1; i<=16; i++) *buf++ = bl_count[i];
- for(cod=0, i=n-1, bits=1; bits <= k; bits++){
- for(j=0; j < bl_count[bits]; j++){
- *buf++ = t = p[i--];
- sym[t].bits = bits;
- sym[t].hcod = cod++;
- }
- cod = cod << 1;
- }
- return(n-1);
- }
- //------------------ fjp_init_struct --------------------------
- void fjp_init_struct(struct s_fjp *s, const char *in_buf, int len_in_buf,
- struct s_fjp1 *s1, FILE *fp)
- {
- int i;
- memset(s, 0, sizeof(struct s_fjp));
- s->p0 = in_buf;
- s->p1 = in_buf;
- s->p2 = in_buf + len_in_buf;
- s->s1 = s1;
- s->fp = fp;
- for(i=0; i<4; i++) s->dchfm[i] = -1;
- for(i=0; i<4; i++) s->achfm[i] = -1;
- return;
- }
- //------------- fjp_putc_fp -----------
- int fjp_putc_fp(int ch, struct s_fjp *s)
- {
- int k;
- k = fputc(ch, s->fp);
- if(k < 0){ s->err = FJP_ERR_WR_FILE; return(-1);}
- s->sizefile++;
- return(k);
- }
- //----------------- fjp_fwrite_fp ------------
- int fjp_fwrite_fp(const char *buf, int Selem, int n, struct s_fjp *s)
- {
- int k;
- k = fwrite(buf, Selem, n, s->fp);
- if(k != n){ s->err = FJP_ERR_WR_FILE; return(-1);}
- s->sizefile += (Selem * n);
- return(n);
- }
- //------------------- fjp_put_bits -------------------
- // положить в выходной поток bits бит.
- int fjp_put_bits(int cod, int bits, struct s_fjp *s)
- {
- int val;
- s->ch2 = (s->ch2 << bits) + (((1 << bits) - 1) & cod);
- s->bit_count2 += bits;
- while(s->bit_count2 >= 8){
- s->bit_count2 -= 8;
- val=(s->ch2 >> s->bit_count2) & 255;
- if(fjp_putc_fp(val, s) < 0) return(-1);
- if(val==0xFF){
- if(fjp_putc_fp(0, s) < 0) return(-1);
- n2_FF++; //------------------------------------отладочная-----
- }
- }
- return(0);
- }
- //--------------- fjp_flush_bits --------------
- // сбросить в выходной поток оставшиеся биты
- int fjp_flush_bits(struct s_fjp *s)
- {
- int val, bits;
- bits = s->bit_count2;
- if(bits > 0){
- val = ((s->ch2 << (8-bits)) | ((1 << (8-bits)) - 1)) & 255;
- if(fjp_putc_fp(val, s) < 0) return(-1);
- if(val==0xFF){
- if(fjp_putc_fp(0, s) < 0) return(-1);
- n2_FF++; //------------------------------------отладочная-----
- }
- }
- s->bit_count2 = s->ch2 = 0;
- return(0);
- }
- //-------------- fjp_fgetc_buf ------------
- // подобна fgetc
- int fjp_fgetc_buf(struct s_fjp *s)
- {
- if(s->p1 >= s->p2){ s->err = FJP_ERR_RD_FILE; return(-1);}
- return((*s->p1++)&255);
- }
- //------------------ fjp_fread_buf -----------------------
- // подобна fread
- int fjp_fread_buf(char *buf, int Selem, int n, struct s_fjp *s)
- {
- int len;
- if(Selem<0 || n<0) return(0);
- if(Selem==0 || n==0) return(n);
- len = Selem * n;
- if(len > (s->p2 - s->p1)){ s->err = FJP_ERR_RD_FILE; return(-1);}
- memmove(buf, s->p1, len);
- s->p1 += len;
- return(n);
- }
- //------------------ fjp_get_n_bit --------------------
- // взять n бит
- int fjp_get_n_bits(struct s_fjp *s, int n)
- {
- int k, k1;
- while(s->bit_count < n){
- k=fjp_fgetc_buf(s);
- if(k<0) return(-1);
- if(k == 0xFF){
- k1=fjp_fgetc_buf(s);
- if(k1 < 0) return(-1);
- if(k1 != 0){ s->err = FJP_ERR_DECODE; return(-1);}
- n1_FF++; //------------------------------------отладочная-----
- }
- s->ch = (s->ch << 8) | k;
- s->bit_count += 8;
- }
- s->bit_count -= n;
- k = (s->ch >> s->bit_count)&((1 << n) - 1);
- return(k);
- }
- //-------------------- fjp_make_h_tree -----------------------
- // построение таблицы Хаффмана. id -номер таблицы Хаффмана
- int fjp_make_h_tree(const char *buf, int Lbuf, struct s_fjp *s, int id)
- {
- int i, k, n, cod, len;
- if(Lbuf < 16){ s->err = FJP_ERR_SYNTAX; return(-1);}
- for(i=0, n=0; i<16; i++) n = n + (buf[i]&255); // подсчёт символов
- if(n==0 || n>256 || (n+16)>Lbuf){ s->err = FJP_ERR_SYNTAX; return(-1);}
- memset(&s->shfm[id], 0, sizeof(s->shfm[0]));
- memmove(s->shfm[id].sym, buf + 16, n); // символы
- s->shfm[id].n = n;
- for(len = 1, cod = 0, i=0; len <= 16; len++){
- k = buf[len-1] & 255; // число кодов текущей длины
- if(k > 0){
- s->shfm[id].idx[len] = i - cod;
- i += k;
- cod += k;
- if(cod > ((1 << len) - 1)){ s->err = FJP_ERR_SYNTAX; return(-1);}
- s->shfm[id].max[len] = cod; // максимальный код текущей длины + 1
- }
- cod <<= 1;
- }
- return(n);
- }
- //------------------ fjp_get_h_cod --------------------
- // взять код Хаффмана. id -номер таблцы Хаффмана
- int fjp_get_h_cod(struct s_fjp *s, int id)
- {
- int *max, cod, len, k, k1;
- max = s->shfm[id].max; // массив максимальных кодов для разных длин
- for(cod=0, len=1; len<=16; len++){
- if(s->bit_count <= 0){
- k = fjp_fgetc_buf(s);
- if(k < 0) return(-1);
- if(k == 0xFF){
- k1=fjp_fgetc_buf(s);
- if(k1 < 0) return(-1);
- if(k1 != 0){ s->err = FJP_ERR_DECODE; return(-1);}
- n1_FF++; //--------------------------------отладочная-----
- }
- s->ch = k;
- s->bit_count = 8;
- }
- s->bit_count--;
- cod = cod << 1;
- if((s->ch & (1 << s->bit_count)) != 0) cod = cod | 1;
- if(cod < max[len]){
- k = s->shfm[id].idx[len] + cod;
- return(s->shfm[id].sym[k] & 255);
- }
- }
- s->err = FJP_ERR_DECODE;
- return(-1);
- }
- //--------------- fjp_get_cod --------------------
- // взять код Хаффмана и значение коэффициента
- int fjp_get_cod(struct s_fjp *s, int id)
- {
- int hcod, bits, k;
- struct s_fjp_sym *sym = s->s1->fsym[id].sym;
- hcod = k = fjp_get_h_cod(s, id);
- if(k < 0) return(-1);
- if(s->fl > 0){
- if(fjp_put_bits(sym[k].hcod, sym[k].bits, s) < 0) return(-1);
- }
- else sym[k].freq++;
- bits = k & 15;
- if(bits==0) return(hcod);
- k = fjp_get_n_bits(s, bits);
- if(k < 0) return(-1);
- if(s->fl > 0){
- if(fjp_put_bits(k, bits, s) < 0) return(-1);
- }
- return(hcod);
- }
- //------------- fjp_get_matric ---------------
- // Взять матрицу базового JPEG
- int fjp_get_matric(struct s_fjp *s, int comp)
- {
- int hcod, ft, id;
- id = s->comp[comp].dchfm; // номер DC-таблицы Хаффмана
- hcod = fjp_get_cod(s, id); // получаем DC-diff
- if(hcod<0) return(-1);
- id = s->comp[comp].achfm; // номер AC-таблицы Хаффмана
- ft = 1;
- while(ft <= 63){
- hcod = fjp_get_cod(s, id);
- if(hcod<0) return(-1);
- if((hcod & 0x0F)==0){
- if(hcod == 0x00) break;
- if(hcod == 0xF0){ ft += 16; continue;}
- s->err = FJP_ERR_DECODE; return(-1);
- }
- else ft += (hcod >> 4);
- ft++;
- }
- return(0);
- }
- //------------ fjp_make_rst -----------
- // обработка рестарта
- int fjp_make_rst(struct s_fjp *s)
- {
- int k;
- k=fjp_fgetc_buf(s);
- if(k<0) return(-1);
- if(k!=0xFF){ s->err = FJP_ERR_DECODE; return(-1);}
- k=fjp_fgetc_buf(s);
- if(k<0) return(-1);
- if(((k & 0xF8)!=0xD0)||((k&7)!=s->nextrst)){
- s->err = FJP_ERR_DECODE; return(-1);
- }
- s->nextrst = (s->nextrst + 1) & 7;
- s->rstn = 0;
- s->bit_count = 0;
- s->ch = 0;
- if(s->fl > 0){
- if(fjp_flush_bits(s) < 0) return(-1);
- if(fjp_putc_fp(0xFF, s) < 0) return(-1);
- if(fjp_putc_fp(k, s) < 0) return(-1);
- }
- return(0);
- }
- //------------- fjp_get_blok_base -------------
- // взять макроблок базового JPEG-файла
- int fjp_get_blok_base(struct s_fjp *s)
- {
- int comp, k, n;
- for(comp=0; comp < s->ncomp; comp++){
- for(n=0; n < s->comp[comp].n; n++){
- k = fjp_get_matric(s, comp);
- if(k<0) return(-1);
- }
- }
- return(0);
- }
- //------------- fjp_get_scan_base ---------------
- // взять скан базового JPEG-файла
- int fjp_get_scan_base(struct s_fjp *s)
- {
- int x, y, xm, ym;
- xm = s->xm; // ширина рисунка в макроблоках
- ym = s->ym; // высота рисунка в макроблоках
- for(y=0; y<ym; y++){
- for(x=0; x<xm; x++){
- if(s->rstN > 0){ // обработка рестарта
- if(s->rstn >= s->rstN){
- if(fjp_make_rst(s) < 0) return(-1);
- }
- s->rstn++;
- }
- if(fjp_get_blok_base(s) < 0) return(-1);
- }
- }
- if(s->fl > 0){ if(fjp_flush_bits(s) < 0) return(-1);}
- return(0);
- }
- //---------------- fjp_get_marker -----------------
- // взять маркер
- int fjp_get_marker(struct s_fjp *s)
- {
- int k;
- k=fjp_fgetc_buf(s); if(k<0) return(-1);
- if(k != 0xFF){ s->err = FJP_ERR_SYNTAX; return(-1);}
- k=fjp_fgetc_buf(s); if(k<0) return(-1);
- return(k);
- }
- //---------------- fjp_get_2_byte -----------------
- // взять два байта
- int fjp_get_2_byte(struct s_fjp *s)
- {
- int k, n;
- k=fjp_fgetc_buf(s); if(k<0) return(-1);
- k=k<<8;
- n=fjp_fgetc_buf(s); if(n<0) return(-1);
- return(k+n);
- }
- //------------- fjp_get_segment -----------------
- // взять сегмент в буфер
- int fjp_get_segment(char *buf, int Sbuf, struct s_fjp *s)
- {
- int k;
- k=fjp_get_2_byte(s); if(k<0) return(-1);
- k=k-2;
- if(k<=0) return(0);
- if(k > Sbuf){ s->err = FJP_ERR_SYNTAX; return(-1);}
- if(fjp_fread_buf(buf, k, 1, s) < 0) return(-1);
- return(k);
- }
- //----------------- fjp_rol_segment ---------------
- // пропустить сегмент
- int fjp_rol_segment(char *buf, int Sbuf, struct s_fjp *s)
- {
- int k, n, m, dl;
- dl=fjp_get_2_byte(s); if(dl<0) return(-1);
- dl -= 2; if(dl<=0) return(0);
- k=dl;
- if(s->fl > 0){
- if(fjp_putc_fp((dl+2) >> 8, s) < 0) return(-1);
- if(fjp_putc_fp(dl+2, s) < 0) return(-1);;
- }
- while(k>0){
- if(k>Sbuf) n=Sbuf;
- else n=k;
- m=fjp_fread_buf(buf, n, 1, s); if(m<0) return(-1);
- k=k-n;
- if(s->fl > 0){
- if(fjp_fwrite_fp(buf, n, 1, s) < 0) return(-1);
- }
- }
- return(dl);
- }
- //--------------------- fjp_decode_DD -------------
- // установка рестарта
- int fjp_decode_DD(struct s_fjp *s, char *buf, int Lbuf)
- {
- if(Lbuf != 2){ s->err = FJP_ERR_SYNTAX; return(-1);}
- s->rstN = ((buf[0]&255)<<8)+ (buf[1]&255);
- return(0);
- }
- //---------------- fjp_decode_C4 -----------------------
- // взять таблицы Хаффмана
- int fjp_decode_C4(struct s_fjp *s, char *buf, int Lbuf)
- {
- int k, k1, k2, i, id, ch, dl=0, dl0;
- char *v1 = s->buf_C4;
- for(i=0; (i+17) < Lbuf; i += (k+17)){
- ch = buf[i]&255;
- k1 = (ch >> 4) & 15; // 0 -DC, 1 -AC-коэффициенты
- k2 = ch & 15; // идентификатор таблицы
- if(k1>1 || k2>3){ s->err = FJP_ERR_SYNTAX; return(-1);}
- if(k1==0){ s->dchfm[k2] = id = k2;}
- else{ s->achfm[k2] = id = k2 + 4;}
- k = fjp_make_h_tree(buf+i+1, Lbuf-1-i, s, id);
- if(k<0) return(-1);
- if(s->fl > 0){
- dl0 = s->s1->fsym[id].n + 16;
- dl = dl + dl0 + 1;
- #if FJP_FL_TEST > 0
- printf("T4: dl1=%3d; dl2=%3d; n1=%3d; n2=%3d; %s[%d]\n",
- Lbuf, dl, k, s->s1->fsym[id].n, k1==0 ? "DC":"AC", k2);
- #endif
- if(dl > (int)sizeof(s->buf_C4)){
- s->err = FJP_ERR_SYNTAX; return(-1);
- }
- *v1++ = ch;
- memmove(v1, s->s1->fsym[id].buf, dl0);
- v1 += dl0;
- }
- }
- d1_C4 = d1_C4 + Lbuf; //-------------------------------отладочная------
- d2_C4 = d2_C4 + dl;
- if(s->fl > 0){
- if(fjp_putc_fp(((dl+2)>>8)&255, s) < 0) return(-1);
- if(fjp_putc_fp(((dl+2)&255), s) < 0) return(-1);
- if(fjp_fwrite_fp(s->buf_C4, dl, 1, s) < 0) return(-1);
- }
- return(0);
- }
- //---------------- fjp_decode_C0 -----------------------
- // ширина, высота, прореживание, id таблиц квантования
- int fjp_decode_C0(struct s_fjp *s, const char *buf, int Lbuf)
- {
- int k, i, comp;
- int nx=0, ny=0;
- int nxmax=0, nymax=0;
- if(Lbuf<9){ s->err = FJP_ERR_SYNTAX; return(-1);}
- s->h = ((buf[1]&255)<<8)+(buf[2]&255);
- s->w = ((buf[3]&255)<<8)+(buf[4]&255);
- if(buf[0]!=8 || s->w < 1 || s->w > 32767 || s->h < 1 || s->h > 32767 ||
- (INT_MAX / 4 / (int)sizeof(int) / s->w) < s->h)
- {
- s->err = FJP_ERR_NOT_SUPPORT; return(-1);
- }
- k = buf[5] & 255; // число компонент в рисунке
- if(k!=1 && k!=3 && k!=4){ s->err = FJP_ERR_NOT_SUPPORT; return(-1);}
- if(Lbuf<(6 + k * 3)){ s->err = FJP_ERR_SYNTAX; return(-1);}
- s->ncomp = k; // число компонент в рисунке
- for(comp=0, i=6; comp < s->ncomp; comp++){
- s->idcomp[comp] = buf[i++] & 255; // идентификатор компонента
- k = buf[i++] & 255; // индикатор прореживания
- nx = (k >> 4);
- ny = k & 15;
- if(nx!=1 && nx!=2){ s->err = FJP_ERR_NOT_SUPPORT; return(-1);}
- if(ny!=1 && ny!=2){ s->err = FJP_ERR_NOT_SUPPORT; return(-1);}
- s->comp[comp].nx = nx; // размер макроблока в матрицах по x
- s->comp[comp].ny = ny; // размер макроблока в матрицах по y
- s->comp[comp].n = nx * ny; // всего матриц в одном макроблоке
- if(nxmax < nx) nxmax = nx;
- if(nymax < ny) nymax = ny;
- k = buf[i++] & 255; // Идентификатор таблицы квантования
- }
- s->xblok = nxmax<<3; // пикселей на макроблок по x
- s->yblok = nymax<<3; // пикселей на макроблок по y
- s->xm = (s->w + s->xblok - 1)/s->xblok; // ширина рисунка в макроблоках
- s->ym = (s->h + s->yblok - 1)/s->yblok; // высота рисунка в макроблоках
- s->nblok = s->xm * s->ym; // размер рисунка в макроблоках
- return(0);
- }
- //---------------- fjp_decode_DA -----------------------
- // графика
- int fjp_decode_DA(struct s_fjp *s, const char *buf, int Lbuf)
- {
- int k, n, k1, k2, comp=0, ncomp, idcomp;
- const char *p1;
- if(Lbuf<6){ s->err = FJP_ERR_SYNTAX; return(-1);}
- p1=buf;
- k=(*p1++)&255; // число компонент в этом скане
- if((k!=1 && k!=3 && k!=4) || k > s->ncomp || Lbuf < (4 + k*2)){
- s->err = FJP_ERR_SYNTAX; return(-1);
- }
- ncomp = k; // число компонент в этом скане
- // обнуляем
- s->bit_count = 0;
- s->ch = 0;
- s->rstn = s->nextrst = 0;
- for(n=0; n<ncomp; n++){
- idcomp = (*p1++)&255; // идентификатор компонента
- for(k=0; k < s->ncomp; k++){ if(s->idcomp[k] == idcomp) break;}
- if(k >= s->ncomp){ s->err = FJP_ERR_SYNTAX; return(-1);}
- comp = k;
- k=(*p1++)&255;
- k1=(k>>4)&15; // Идентификатор таблицы Хаффмана для DC
- k2=k&15; // Идентификатор таблицы Хаффмана для AC
- if(k1>3 || k2>3){ s->err = FJP_ERR_NOT_SUPPORT; return(-1);}
- s->comp[comp].dchfm = s->dchfm[k1];
- s->comp[comp].achfm = s->achfm[k2];
- // проверяем наличие таблиц Хаффмана
- if(s->comp[comp].dchfm < 0 || s->comp[comp].achfm < 0){
- s->err = FJP_ERR_SYNTAX; return(-1);
- }
- }
- if(*p1!=0 || *(p1+1)!=63 || *(p1+2)!=0){
- s->err = FJP_ERR_SYNTAX; return(-1);
- }
- b1_DA = (int)(s->p1 - s->p0); //----------------------отладочная------
- b2_DA = s->sizefile;
- k=fjp_get_scan_base(s); // базовый
- e1_DA = (int)(s->p1 - s->p0); //----------------------отладочная------
- e2_DA = s->sizefile;
- if(k<0) return(-1);
- return(0);
- }
- //---------------- fjp_fun -----------------
- int fjp_fun(struct s_fjp *s)
- {
- int dl, mark;
- START:
- mark=fjp_get_marker(s); // взять маркер
- #if FJP_FL_TEST > 0
- if(mark<0) printf("mark=%d\n", mark);
- else printf("mark=0x%02X\n", mark);
- #endif
- if(mark<0) goto ERR;
- if(s->fl > 0){
- if(fjp_putc_fp(0xFF, s) < 0) goto ERR;
- if(fjp_putc_fp(mark, s) < 0) goto ERR;
- }
- //маркеры, не имеющие длины
- if(mark==0xD9) goto RET; // конец файла
- if((mark & 0xF7)==0xD0) goto START;
- //эти сегменты копировать без обработки
- if(mark==0xFE || (mark & 0xF0)==0xE0 || mark==0xDB){
- if(fjp_rol_segment(s->buf, sizeof(s->buf), s) < 0) goto ERR;
- goto START;
- }
- //другие сегменты обрабатывать
- dl=fjp_get_segment(s->buf, sizeof(s->buf), s);
- if(dl<0) goto ERR;
- //0xC4, таблицы Хаффмана, обрабатывается особым образом, не копировать
- if(mark==0xC4){
- if(fjp_decode_C4(s, s->buf, dl) < 0) goto ERR;
- goto START;
- }
- if(s->fl > 0){ //копирование. Для 0xDA копирует заголовк
- if(fjp_putc_fp((dl+2) >> 8, s) < 0) goto ERR;
- if(fjp_putc_fp((dl+2), s) < 0) goto ERR;
- if(fjp_fwrite_fp(s->buf, dl, 1, s) < 0) goto ERR;
- }
- //обработка
- if(mark==0xC0){ // ширина, высота, прореживание, id таблиц квантования
- if(fjp_decode_C0(s, s->buf, dl) < 0) goto ERR;
- }
- else if(mark==0xDD){ // рестарт
- if(fjp_decode_DD(s, s->buf, dl) < 0) goto ERR;
- }
- else if(mark==0xDA){ // графика
- if(s->fl_start > 0){ s->err = FJP_ERR_SYNTAX; goto ERR;}
- s->fl_start++;
- if(fjp_decode_DA(s, s->buf, dl) < 0) goto ERR;
- }
- else { s->err = FJP_ERR_NOT_SUPPORT; goto ERR;}
- goto START;
- RET:
- if(s->fl_start == 0){ s->err = FJP_ERR_SYNTAX; goto ERR;}
- return(0);
- ERR:
- return(-1);
- }
- //------------ fjp_fun_1 ---------------
- int fjp_fun_1(struct s_fjp *s)
- {
- int i, k;
- struct s_fjp1 *s1;
- if(fjp_fun(s) < 0) return(-1); //первый проход
- fjp_init_struct(s, s->p0, s->p2 - s->p0, s->s1, s->fp);
- s->fl = 1;
- s1 = s->s1;
- for(i=0; i<8; i++){
- k = fjp_hfm_code(s1->tree, s1->fsym[i].sym, s1->fsym[i].buf);
- s1->fsym[i].n = k;
- #if FJP_FL_TEST > 0
- if(fl>0){ //--------------------------------------отладочная------
- printf("-----maxlen=%d; ", maxlen);
- if(i<4) printf("DC[%d]\n", i);
- else printf("AC[%d]\n", i-4);
- fl=0;
- }
- #endif
- }
- n1_FF = n2_FF = d1_C4 = d2_C4 = 0; //------------------отладочная------
- #if FJP_FL_TEST > 0
- printf("----------\n");
- #endif
- k = fjp_fun(s); //второй проход
- return(k);
- }
- //---------------- fjp_opt_hfm ------------------
- int fjp_opt_hfm(const char *in_buf, int len_in_buf, FILE *fp,
- int *w, int *h, int *err)
- {
- struct s_fjp *s = NULL;
- struct s_fjp1 *s1=NULL;
- int k, err0;
- if(in_buf==NULL || len_in_buf <= 0 || fp==NULL || w==NULL || h==NULL){
- err0 = FJP_ERR_INVAL; goto ERR;
- }
- *w = *h =0;
- s = (struct s_fjp*)malloc(sizeof(struct s_fjp));
- if(s==NULL){ err0 = FJP_ERR_MEMORY; goto ERR;}
- s1 = (struct s_fjp1*)malloc(sizeof(struct s_fjp1));
- if(s1==NULL){ err0 = FJP_ERR_MEMORY; goto ERR;}
- fjp_init_struct(s, in_buf, len_in_buf, s1, fp);
- memset(s1, 0, sizeof(struct s_fjp1));
- k=fjp_fun_1(s);
- if(k<0){ err0 = s->err; goto ERR;}
- k = s->sizefile;
- *w = s->w;
- *h = s->h;
- free(s);
- free(s1);
- if(err != NULL) *err=0;
- return(k);
- ERR:
- if(s != NULL) free(s);
- if(s1 != NULL) free(s1);
- if(err != NULL) *err = err0;
- return(-1);
- }
- //---------- fjp_strerror -----------
- const char *fjp_strerror(int err)
- {
- switch(err){
- case FJP_ERR_RD_FILE : return("FJP_ERR_RD_FILE");
- case FJP_ERR_SYNTAX : return("FJP_ERR_SYNTAX");
- case FJP_ERR_NOT_SUPPORT : return("FJP_ERR_NOT_SUPPORT");
- case FJP_ERR_MEMORY : return("FJP_ERR_MEMORY");
- case FJP_ERR_DECODE : return("FJP_ERR_DECODE");
- case FJP_ERR_INVAL : return("FJP_ERR_INVAL");
- case FJP_ERR_WR_FILE : return("FJP_ERR_WR_FILE");
- }
- return("FJP: Unknow error");
- }
- #if 1
- //============= Тестовая обертка ====================
- // Аргументом указать имя входного JPEG-файла. После работы программы
- // должен получиться оптимизированный файл "test.jpg".
- #include <sys/time.h>
- //------------- 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);
- }
- //---------------- fjp_opt_hfm_1 ------------------
- // обертка для fjp_opt_hfm()
- int fjp_opt_hfm_1(const char *f1, const char *f2)
- {
- FILE *fp1=NULL, *fp2=NULL;
- int k, dl1, dl2, w, h, err, t;
- char *buf=NULL;
- struct timeval tv1, tv2;
- fp1=fopen(f1, "r");
- if(fp1==NULL){ printf("fp1=fopen(%s)=NULL\n", f1); goto ERR;}
- // измерение длины JPEG-файла
- fseek(fp1, 0, SEEK_END);
- dl1 = ftell(fp1);
- rewind(fp1);
- fp2=fopen(f2, "w");
- if(fp2==NULL){ printf("fp2=fopen(%s)=NULL\n", f2); goto ERR;}
- buf = (char*)malloc(dl1);
- if(buf==NULL){ printf("buf = (char*)malloc(dl1)=NULL\n"); goto ERR;}
- k = fread(buf, dl1, 1, fp1);
- if(k != 1){ printf("k = fread(fp1)=%d\n", k); goto ERR;}
- fclose(fp1); fp1=NULL;
- printf("-------------\n");
- gettimeofday(&tv1, NULL);
- dl2 = fjp_opt_hfm(buf, dl1, fp2, &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(fp2);
- printf("-------------\n");
- return(0);
- ERR:
- if(buf != NULL) free(buf);
- if(fp1 != NULL) fclose(fp1);
- if(fp2 != NULL) fclose(fp2);
- printf("-------------\n");
- return(-1);
- }
- //-------- main --------------------
- // printf("\n");
- int main(int argc, char **argv)
- {
- const char *f2="test.jpg";
- if(argc < 2){ printf("Err-arg\n"); exit(0);}
- fjp_opt_hfm_1(argv[1], f2);
- exit(0);
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement