Wednesday, August 4, 2010

頹廢

發現自己喜歡上頹廢。

無可救藥的愛上這種特質,當一個人能擁有頹廢的自由,
是多讓人羨慕又為他感到可憐。

可是我卻無可自拔地迷戀上它。

Saturday, February 6, 2010

Audrey Hepburn - Moon River

Audrey Hepburn - Moon River



Moon River, wider than a mile,
月河,你如此地寬
I'm crossing you in style some day.
總有一天,我會遇見優雅的妳
Oh, dream maker, you heart breaker,
喔,織夢者,你總是讓人心碎
wherever you're going I'm going your way.
不論你去那,我會跟著你的腳步
Two drifters off to see the world.
兩個流浪的人要去看這個世界
There's such a lot of world to see.
世界有那麼多的東西等著我們去發掘
We're after the same rainbow's end--
我們跟隨著同一道彩虹的末端
waiting 'round the bend,
在那轉彎處等待
my huckleberry friend,
我的朋友
Moon River and me.
還有月河和我

Tuesday, June 2, 2009

成功

『成功是最差的老師,他什麼都不會教你,只會教會你驕傲』

在這四年中,
我好像真的就如同這句話所說的,
什麼都沒學到。

表面上看起來很風光,
實際上四年下來我失去的似乎比得到的還要多。

Sunday, May 10, 2009

飛蛾

今天晚上突然出現一大群的飛蛾在家裡的窗戶外面,
突然來了一大群我嚇到了!

把窗戶關了起來,但是沒想到它還是想辦法鑽進來,
為了就是接近黑暗中耀眼的燈光。

當它們在接近光明的同時,
它們的生命也一步一步走向死亡..

Saturday, May 9, 2009

Using Jpeglib to Convert BMP to Jpeg

繼上一篇Using Jpeglib to Convert JPEG to BMP之後,我們想利用Jpeglib來將BMP轉成Jpeg。轉換格式其實最最重要的就是要讀對標頭檔(Header)也要填對它,所以之前所提的BMP Header是很重要的一環,在之前的文章也提到過了

利用jpeglib做jpeg壓縮的流程大致上與解壓縮是一樣的,重要的是要填對jpeg compression parameters:

int BmptoJpeg(char *input, char *output)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *out;
unsigned char *line, *buffer;
int row_width;
int i, j;

if ( (out = fopen(output,"wb")) == NULL ) {
printf("BmptoJpeg: ...can't open %s\n", output);
return FALSE;
}

cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);

jpeg_set_defaults(&cinfo);
jpeg_stdio_dest(&cinfo, out);
jpeg_set_quality(&cinfo, 75, TRUE);
jpeg_start_compress(&cinfo, TRUE);

/* set row width and calulate padding data*/
row_width = cinfo.image_width*cinfo.input_components;
/* !!!assume the input source store in buffer!!! */
line = buffer;

/* output to jpeg file */
for (i = 0; i < cinfo.image_height; i++, line+=row_width)
jpeg_write_scanlines(&cinfo, &line, 1);

jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);

fclose(in);
fclose(out);

return TRUE;
}


上列的code大致上就是整個jpeglib產生jpeg的流程,要特別注意的是buffer,在上面這個例子是假定buffer是存著圖的RGB資料(RAW Data)。了解整個產生jpeg流程之後,我們要來著手在bmp header的處理部份,之前提過的bmp header架構這裡也就不再提了。這邊要做的就是把bmp header裡的寬、高等資訊讀出,並且設定到jpeg compression的parameters:


int getBmpHeader(bmp_header *header, struct jpeg_compress_struct *info, FILE *in)
{
fread(header, 1, sizeof(bmp_header), in);

if (header->bmpType != 0x4d42 ) {
printf("getBmpHeader: ...it's not a BMP file\n");
return FALSE;
}

if (header->bmpCompress != 0 || header->bmpBpp != 24) {
printf("getBmpHeader: ...doesn't support compressed BMP format\n");
return FALSE;
}

info->image_width = header->bmpWidth;
info->image_height = (header->bmpHeight < 0)?
0-header->bmpHeight:header->bmpHeight;
info->input_components = header->bmpBpp/8;
info->in_color_space = JCS_RGB;

return TRUE;
}


設定之後其實也還有一項很重要的方不要忘了,就是bmp裡圖檔資料的格式是BGRBGR,而我們要輸入給jpeglib的資料是RGBRGB,所以color format轉換又要出現了:


int convertColor(unsigned char *color, int width)
{
int i, ptr;
char tmp;

for(i = 0, ptr=0; i < width; i++, ptr=i*3) {
tmp = color[ptr];
color[ptr] = color[ptr+2];
color[ptr+2] = tmp;
}
}


這些都做完之後,我們就可以將jpeglib產生jpeg的流程做結合,做結合要注意的地方就是jpeglib產生jpeg時是採用一個line一個line做讀取,我們使用的做法是先將bmp的圖檔資料讀到memory中,再從memory一行一行的取出並做color format轉換再寫入到jpeg檔。另外還有一點要注意就是bmp是要對齊4bytes/row,所以我們也要試先算出多餘的資料,在每個line做累加的時候把這些多餘的資料捨去:


int BmptoJpeg(char *input, char *output)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
bmp_header binfo;
FILE *in, *out;
unsigned char *line, *buffer;
int row_width;
int i, j;

if ( (in = fopen(input,"rb")) == NULL ) {
printf("BmptoJpeg: ...can't open %s\n", input);
return FALSE;
}

if ( (out = fopen(output,"wb")) == NULL ) {
printf("BmptoJpeg: ...can't open %s\n", output);
return FALSE;
}

cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);

/* get bmp header info and set jpeg
compression parameters */
if (getBmpHeader(&binfo, &cinfo, in) == FALSE)
return FALSE;

jpeg_set_defaults(&cinfo);
jpeg_stdio_dest(&cinfo, out);
jpeg_set_quality(&cinfo, 75, TRUE);
jpeg_start_compress(&cinfo, TRUE);

/* set row width and calulate padding data*/
row_width = cinfo.image_width*cinfo.input_components
+ cinfo.image_width%4;
/* memory allocate for input buffer */
buffer = (unsigned char *)malloc(cinfo.image_width*cinfo.image_height*cinfo.input_components);
/* input from bmp file */
fread(buffer, 1, cinfo.image_width*
cinfo.image_height*cinfo.input_components, in);
line = buffer;

/* output to jpeg file */
for (i = 0; i < cinfo.image_height; i++, line+=row_width) {
convertColor(line, cinfo.image_width);
jpeg_write_scanlines(&cinfo, &line, 1);
}

jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);

fclose(in);
fclose(out);

free(buffer);

return TRUE;
}


上列的code其實還不算完整,這是對於沒有做壓縮(且沒有platte)的BMP是有效的,加上這個code並未做倒置的動作(BMP的圖檔資料是從左下到右上的順序做讀取),所以這個code還不算完整

Reference:
Wiki: BMP file format
IJG jpeglib

Friday, May 8, 2009

Using Jpeglib to Convert JPEG to BMP

下載Jpeglib

ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz


將Jpeglib解壓縮

tar -zxvf jpegscr.v6b.tar.gz


Build Share library

./configure --enable-shared
make


Build完之後會在.lib資料夾底下看到libjpeg.so的檔案,如果沒有這個檔案則表示沒有Build成Share Library或者是根本沒有Build成功。如果有這個檔案則我們可以開始作安裝的動作(預設安裝目錄是在/usr/local,如果要更改目錄則在一開始configure的時候加上--prefix=安裝目錄)

make install


接著就可以開始寫轉換的程式了!首先我們先了解Jpeglib如何將Jpeg檔解壓縮:


int JpegtoBmp(char *input)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *in;
JSAMPARRAY buffer;
int row_width;

if ( (in = fopen(input, "rb")) == NULL ) {
printf("readJPEG: ...can't open %s\n", input);
return FALSE;
}

cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, in);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);

/* SAMPLEs per row in output buffer */
row_width = cinfo.output_width * cinfo.output_components;
/* set buffer */
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_width, 1);

while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, buffer, 1);
/* !!!output row data!!! */
}

jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);

fclose(in);
return TRUE;
}


大致的流程就如上面的程式碼所看到的,比較要注意的就是struct jpeg_decompress_struct這個東西,當我們在做解壓縮的時候,這個struct裡面有一些參數可以設定解壓縮的一些模式、輸出的格式等等,詳細可以參考jpeglib裡面的libjpeg.doc這個說明檔

了解整個jpeglib的解壓縮流程之後接著我們要來看要如何產生一個BMP File,首先我們要先了解BMP的Header:




由上面所列的Header我們可以定義出一個BMP Header的Struct:

typedef struct
{
unsigned short bmpType;
unsigned long bmpSize;
unsigned long bmpRev;
unsigned long bmpOffset;
unsigned long bmpHeaderSize;
long bmpWidth;
long bmpHeight;
unsigned short bmpPlanes;
unsigned short bmpBpp;
unsigned long bmpCompress;
unsigned long bmpDataSize;
long bmpHPelsPerMeter;
long bmpVPelsPerMeter;
unsigned long bmpColors;
unsigned long bmpImportant;
}__attribute__ ((packed)) bmp_header;




接著我們設計一個function來產生一個BMP Header,這邊要注意一點,因為BMP讀的順序是從左下到右上如上圖所示,所以我們利用B設定BMP Header裡的高將高改成負的,這樣就可以讓順序改成從左上到右下讀取,這樣不需再做另外倒置的處理:


int setBmpHeader(bmp_header *header, struct jpeg_decompress_struct *info)
{
long size;
size = info->output_width*info->output_height*3;

header->bmpType = 0x4d42;
header->bmpSize = size + sizeof(bmp_header);
header->bmpRev = 0;
header->bmpOffset = header->bmpSize - size;
header->bmpHeaderSize = 40;
header->bmpWidth = info->output_width;
header->bmpHeight = 0-info->output_height;
header->bmpPlanes = 1;
header->bmpBpp = 24;
header->bmpCompress = 0;
header->bmpDataSize = size;
header->bmpHPelsPerMeter = 0;
header->bmpVPelsPerMeter = 0;
header->bmpColors = 0;
header->bmpImportant = 0;

}


我們透過struct jpeg_decompress_struct來取得原始jpeg檔的大小(寬、高)來對產生的BMP做Header的設定動作。因為BMP儲存的格式是BGRBGR 但是jpeglib解出來的jpeg color format是RGBRGB 所以要作轉換,我們需要一個color format轉換的function:


int convertColor(char *color, int width)
{
int i, ptr;
char tmp;

for(i = 0, ptr= 0; i < width; i++, ptr=i*3) {
tmp = color[ptr];
color[ptr] = color[ptr+2];
color[ptr+2] = tmp;
}
}


接著我們將jpeg最原始的解壓縮程式改寫,並將BMP Header設定與Color Format轉換加入,但是還要注意一點就是BMP的資料每列一定要對齊4bytes/row 所以在寫入資料的時候必須要注意是否有補滿4bytes/row,所以我們在寫入每一列時,我們必須先計算一列有多少個byte然後對它做除以4取餘數,看我們需要多少個0需要做填入的動作:


int JpegtoBmp(char *input, char *output)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
bmp_header binfo;
FILE *in, *out;
JSAMPARRAY buffer;
int row_width;
int num_padding;

if ( (in = fopen(input, "rb")) == NULL ) {
printf("readJPEG: ...can't open %s\n", input);
return FALSE;
}

if ( (out = fopen(output, "wb+")) == NULL ) {
printf("readJPEG: ...can't open %s\n", output);
return FALSE;
}

cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, in);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
setBmpHeader(&binfo, &cinfo);

/* write BMP header */
fwrite(&binfo, 1, sizeof(bmp_header), out);
/* SAMPLEs per row in output buffer */
row_width = cinfo.output_width * cinfo.output_components;
/* calculate number of padding */
num_padding = cinfo.output_width%4;
/* set buffer */
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_width, 1);

while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, buffer, 1);
convertColor(buffer[0], cinfo.output_width);
fwrite(buffer[0], 1, row_width, out);
fwrite("0", 1, num_padding, out);
}

jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);

fclose(in);
fclose(out);
return TRUE;
}


Reference:
Wiki: BMP file format
IJG jpeglib

Sunday, May 3, 2009

Friendship

友誼真的是一件很奇妙的東西,
很久不見的朋友會很想知道他們最近在做什麼。
但是一旦熱絡起來之後,又變回當初認識的那個樣子,
想回到自己築好的保護巢裡..

『君子之交淡如水』有點這種感覺吧!
最要好的朋友卻不是在身邊的朋友,當朋友知道太多自己的事之後,
便會有衝突出現,人還是要有一點私人的空間,
這樣人和人的相處才會長長久久。