📄 open.c
字号:
/***
* open.c
***
* soucast knihovny libopen
* 2007-04-29
* xbarin02@stud.fit.vutbr.cz
***
* soubor s fcemi, ktere provadeji vlastni kompresi obrazku (DCT a DWT)
*/
#include "open.h"
// std. headery
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
// kvuli M_PI na Windows - #undef ***ANSI a #define ***XOPEN
#define __USE_XOPEN
#undef __STRICT_ANSI__
#include <math.h>
// ke kompresi koeficientu pouzivam libbzip2
#include <bzlib.h>
// funkce pro vypis ladicich informaci a chyb
#include "error.h"
// velikost bloku (X i Y), po kterem se ma transformace provadet
#define LENGTH 8
// funkce provadejici vlastni transformace (2D DCT a DWT)
#include "transform.c"
// jeden blok, ktery bude kompromovat (bude Y'Cb'Cr)
typedef
struct
{
double y[LENGTH][LENGTH]; // [y,x]
double u[LENGTH][LENGTH];
double v[LENGTH][LENGTH];
} TYBlock;
// zlinearizovane a zquantizovane koeficienty
typedef
struct
{
uint16 lin[LENGTH*LENGTH];
} TLinBlock;
// kvantizacni matice
typedef
int TQuantMat[LENGTH][LENGTH];
// indexy pro zig-zag skanovani (1D)
const int zigzag[LENGTH*LENGTH] = {
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,
};
// [y,x]; std. JPEG quantizacni matice pro luma (Y')
const int QM[LENGTH][LENGTH] = {
{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}
};
// [y,x]; std. JPEG Q.M. pro chroma (C'b, C'r)
const int QMc[LENGTH][LENGTH] = {
{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},
};
/***
* pomocna fce, pro overeni spravne velikosti datovych typu
*/
int check_sizeof()
{
if(CHAR_BIT != 8)
return(1);
if(sizeof(uint8) != 1 || sizeof(int8) != 1)
return(2);
if(sizeof(uint16) != 2 || sizeof(int16) != 2)
return(3);
if(sizeof(uint32) != 4 || sizeof(int32) != 4)
return(4);
return(0);
}
/***
* prevede dany RGB blok z FB do YCbCr v TYBlock (vraci/staticke), za okrajem
* vraci 0 (korektni)
*/
TYBlock *rgb2yuv(PFrameBuff fbuff, uint32 x, uint32 y)
{
uint32 w = fbuff->w;
uint32 h = fbuff->h;
static TYBlock yuv;
for(uint32 _y=0; _y<LENGTH; _y++)
for(uint32 _x=0; _x<LENGTH; _x++)
{
if( ((y+_y) < h) && ((x+_x) < w) )
{
unsigned i = (y+_y)*w+(x+_x);
uint8 r = fbuff->buff[i].r;
uint8 g = fbuff->buff[i].g;
uint8 b = fbuff->buff[i].b;
yuv.y[_y][_x] = 0.299 *r + 0.587 *g + 0.114 *b ;
yuv.u[_y][_x] = - 0.1687*r - 0.3313*g + 0.5 *b + 128.0;
yuv.v[_y][_x] = 0.5 *r - 0.4187*g - 0.0813*b + 128.0;
}
else
{
//za okrajem
yuv.y[_y][_x] = 0.0;
yuv.u[_y][_x] = 0.0;
yuv.v[_y][_x] = 0.0;
}
}
return(&yuv);
}
/***
* kvantizuje/linearizuje dany blok koeficientu dle dane QM do TLinBlock
* (unsigned, urceny pro kompresi)
*/
void quant(double m[LENGTH][LENGTH], TQuantMat qm, TLinBlock *lin)
{
for(int ib=0; ib<64; ib++)
{
int j = zigzag[ib];
int x = j % 8;
int y = j / 8;
int16 tmp = (int16)round( m[y][x]/qm[y][x] );
if( tmp < 0 ) // zaporne
tmp = -2*tmp-1; //-1=1,-2=3,-3=5
else
tmp = tmp*2; // 0=0,1=2,2=4,3=6
lin->lin[ib] = (uint16)tmp;
}
return;
}
/***
* zkomprimuje linearizovany blok BZ2 do souboru (w)
*/
int compress(bz_stream *bstrm, char *addr, unsigned size, FILE *desc)
{
uint8 outbuf[1024];
bstrm->avail_in = size;
bstrm->next_in = addr;
int ret;
do
{
bstrm->avail_out = 1024;
bstrm->next_out = (char *)outbuf;
ret = BZ2_bzCompress(bstrm, BZ_RUN);
if(ret != BZ_RUN_OK)
{
eprintf("BZ2_bzCompress() fails!");
return(3);
}
unsigned have = 1024 - bstrm->avail_out;
if(0 != have)
{
if( 1 != fwrite(outbuf,have,1,desc) )
dprintf("compress()/fwrite() fails!\n");
}
}
while(0 != bstrm->avail_in);
return(0);
}
/***
* ukonci kompresi (flushne zbytek BZ2 dat z pameti do souboru (w))
*/
int compress_flush(bz_stream *bstrm, FILE *desc)
{
uint8 outbuf[1024];
bstrm->avail_in = 0;
bstrm->next_in = NULL;
int ret;
do
{
bstrm->avail_out = 1024;
bstrm->next_out = (char *)outbuf;
ret = BZ2_bzCompress(bstrm, BZ_FINISH);
//if(ret != BZ_STREAM_END)
//{
// eprintf("BZ2_bzCompress() fails!");
// return(3);
//}
unsigned have = 1024 - bstrm->avail_out;
if(0 != have)
{
if( 1 != fwrite(outbuf,have,1,desc) )
printf("compress_flush()/fwrite() fails!\n");
}
}
while(BZ_STREAM_END != ret);
return(0);
}
/***
* fce, kt. provadi vlastni kompresi obrazku z FB pomoci metody DCT/DWT a
* kvality (v %) do souboru (w)
*/
int openCompress(FILE *descriptor, PFrameBuff framebuffer, openMethod method, int quality)
{
dprintf("OpenCompress()\n");
if(quality < 1)
quality = 1;
if(quality > 100)
quality = 100;
uint8 q8 = (int8)quality;
// pomocne w,w8,h,h8
uint32 w8, w = framebuffer->w;
uint32 h8, h = framebuffer->h;
w8 = (w/LENGTH + ((w%LENGTH!=0)?1:0))*LENGTH;
h8 = (h/LENGTH + ((h%LENGTH!=0)?1:0))*LENGTH;
// vse defaultni
bz_stream bstrm;
bstrm.bzalloc = NULL;
bstrm.bzfree = NULL;
bstrm.opaque = NULL;
int ret = BZ2_bzCompressInit(&bstrm,9,0,0);
if(ret != BZ_OK)
{
eprintf("BZ2_bzCompressInit() fails!");
return(3); // BZ error
}
// zapsat hlavicku
ret = compress(&bstrm, (char *)&(framebuffer->w), sizeof(uint32)*1, descriptor);
if(ret)
{
eprintf("Internal error/1!");
return(ret);
}
ret = compress(&bstrm, (char *)&(framebuffer->h), sizeof(uint32)*1, descriptor);
if(ret)
{
eprintf("Internal error/2!");
return(ret);
}
ret = compress(&bstrm, (char *)&(q8), sizeof(uint8)*1, descriptor);
if(ret)
{
eprintf("Internal error/3!");
return(ret);
}
void (*f_t)(double [LENGTH][LENGTH], double [LENGTH][LENGTH]);
TQuantMat qm_y, qm_c;
// urcit metodu a spocitat QM
uint8 methd;
if(DCT == method)
{
// --- Q.M. ---
int q = quality;
if(q < 50)
q = 5000/q;
else
q = 200-q*2;
q*=6;
int tmp;
for(int x=0; x<LENGTH; x++)
for(int y=0; y<LENGTH; y++)
{
// Y
tmp = (QM[y][x]*q+50)/100;
if(tmp < 1)
tmp = 1;
if(tmp > 32767)
tmp = 32767;
qm_y[y][x] = tmp;
// CbCr
tmp = (QMc[y][x]*q+50)/100;
if(tmp < 1)
tmp = 1;
if(tmp > 32767)
tmp = 32767;
qm_c[y][x] = tmp;
}
// --- Q.M. ---
// prirazeni funkci
f_t = &fct2D;
methd = 0;
}
else
if(DWT == method)
{
// --- Q.M. ---
int q = quality;
q = (101-q)*1;
int tmp;
for(int x=0; x<LENGTH; x++)
for(int y=0; y<LENGTH; y++)
{
// Y
tmp = (QM[y][x]*q+50)/100;
if(tmp < 1)
tmp = 1;
if(tmp > 32767)
tmp = 32767;
qm_y[y][x] = tmp;
// CbCr
tmp = (QMc[y][x]*q+50)/100;
if(tmp < 1)
tmp = 1;
if(tmp > 32767)
tmp = 32767;
qm_c[y][x] = tmp;
}
// --- Q.M. ---
// prirazeni funkci
f_t = &fwt2D;
methd = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -