⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 open.c

📁 从sourceforge下的图像压缩源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/***
 * 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 + -