'당근이의 AVR 갖구 놀기'(이하 당근이)는 AVR을 한 번 만져본 사람이라면 누구나 한번씩은 방문해봤을 만큼 유명한 네이버 카페 중 하나이다.
처음에는 AVR에 관한 질의가 있어서 찾게 되었고, 많은 부분에 대한 문제해결을 본 게 계기가 되어 내게는 네이버에서 가장 즐겨찾는 카페중 하나가 되었다.
그리고, 현재는 엄마 몰래 리눅스 포팅이라는 강좌를 알게 되어서 자주 들락날락 거리고 있는 중이다.
학부 4학년때 처음으로 임베디드 리눅스에 대한 수업을 듣고 임베디드에 대해 관심을 가지게 되었다. 하지만 그 이후에는 고가의 관련장비도 문제거니와, 다른 프로젝트에 심혈을 기울이고 있는터라, 한동안 잊게 되었다.
그렇게 시간은 흘렀고, 현재 백수로 있는 동안 프로그래밍에 대한 감도 떨어지는 것 같아서 엄마 몰래 리눅스 포팅이라는 강좌를 계기로 다시금 관심분야에 대한 눈을 돌리고자 한다.
분류 전체보기
- 엄마 몰래 리눅스 포팅 0 2009.07.30
- minicom에서 usb-to-serial 인식 2008.11.29
- 프로그램 설치 2008.11.18
- Consider using PASV 2008.11.17 2
- Framework 정의 2007.08.14 2
- jpeg decoder source 2007.02.14
- 오라클(DATABASE MANAGEMENT SYSTEM) 2007.01.25
- RUNTIME_CLASS 2007.01.23
- select.c 2007.01.19
- mfc 2007.01.18
- wave file 구조 2007.01.18
- C++ 요약 2007.01.18
- DirectX 9.0 한글판 2007.01.15
- 컨트롤 2007.01.14
- C/C++ 프리프로세서 명령 2007.01.14
- calculator 2007.01.09
- 그래픽 2007.01.08
- 리소스 2007.01.07
- ORACLE DATA TYPE 2007.01.06
- API Control 2007.01.05
엄마 몰래 리눅스 포팅 0
minicom에서 usb-to-serial 인식
(본인은 vmware v5에 ubuntu 8.10을 설치한 상태)
WindowsXP의 경우는 usb-to-serial을 사용할 경우 가상 포트로 COMn이 잡히게 되어
Linux도 동일하게 가상포트로 잡히는 걸로 생각하였다.
(Windows COM1 == Linux ttyS0 과 동일하다
Windows의 경우 1부터 시작하나 Linux는 0부터 시작하게 된다. 0앞의 S는 serial을 뜻함)
하지만 Linux는 ttyUSB0으로 인식되었다.
(minicom에서 포트를 ttyS0 부터 계속 인식시켜서 안되길래
인터넷을 검색해본 결과 usb-to-serial은 ttyUSBn으로 인식된다는 것을 알았다)
minicom 에서 usb-to-serial은 ttyUSBn으로 할 것!!
프로그램 설치
yum install 패키지명
Debian, Ubuntu 는
apt-get install 패키지명
Consider using PASV
ftp.kernel.org에 접속을 해서 커널을 다운 받으려 했다.
기본 ftp 프로그램으로 접속을 하니 정상적으로 접속은 되었으나,
ls 명령이 먹지 않는다.
Consider using PASV 란 메시지와 함께..
패시브 모드로 접속이 되어 있어서 인 것 같아
자세한 이유는 모르고 네이버에 검색해보니
패시브 모드와 데이터 모드가 있다는 걸 알았는데.
하지만 어떻게 다운을 받는지 나와있는 곳은 없다.
...... 젝힐..
영어는 못하지만 가볍게..
# man ftp를 해보니 훗..
간단하게 해결되었다.
-p란 옵션이 Use passive mode for data transfers 란다..+_+
# ftp -p ftp.kernel.org
하니 ls도 잘 먹고 get도 잘 된다~~
어려운 리눅스~~ 성공성공~~
Framework 정의
Framework에 대한 정의를 내려 보려고 하니..참 막막하기는 하다...
Framework, Architecture 등 너무도 익숙하게 사용하는 용어라 정의하기가 더욱 어려운 것 같다.
google에서 Framework에 대한 정의를 찾아보면 20 여개 정도가 검색이 되는데 그중 아래의 정의가 일반적으로 우리가 생각하는 Framework이 아닐까 생각한다.
In software development, a Framework is a defined support structure in which another software project can be organized and developed. Typically, a framework may include support programs, code libraries and a scripting language amongst other software to help develop and glue together the different components of your project.
소프트웨어 프로젝트에서 활용할 수 있는 기반 구조로 일반적으로 지원 프로그램, 코드 라이브러리 등 프로젝트의 다양한 컴포넌트들을 개발하고 유기적으로 결합하기 위해 사용하는 소프트웨어를 말한다.
과거에 공통 코드라는 명칭으로 사용하던 것들을 좀더 구조화 시켜 Framework이라 부른다고 생각하면 될 것 같다.
이 Framework도 Component Framework, Application Framework, Web Framework 등 분류 기준에 따라 다양하게 분류가 된다.
여기서는 두가지로만 분류하겠다.
1. Component Framework (또는 Vendor Framework) : .NET Framework, J2EE Framework 과 같은 기능 중심의 Framework
2. Application Framework : Component Framework 기반으로 Application 내의 요소(Component)들간의 유기적인 연관 관계를 고려한 Framework (대표적인 것이 Apache Struts Framework, 다양한 SI회사에서 사용하는 Framework [필자의 회사에도 SummaFramework이라는 이름으로 가지고 있다] 등)
이러한 Framework을 활용하는 이유는 당연히 프로젝트의 생산성 향상 및 프로젝트의 표준화 지원을 통해 Quality 향상 등이 이유가 될 것이다. (사실 Framework이라는 표현을 쓰지 않을때에도 공통 코드 형태로 프로젝트 마다 사용해 왔던 것이다..)
이러한 Framework과 Architecture, Component, Library을 비교해 보면
Architecture는 시스템을 구성하고 있는 구성요소들 및 관계의 구조를 표현한 것으로 Framework 보다 좀더 추상적인 개념으로 보면 되겠다.
Component는 특정 기능을 수행하기 위해 잘 정의된 인터페이스를 통해 독립적으로 개발된 소프트웨어 단위로 Framework 기반에서 동작하는 모듈로 생각하면 되겠다.
Library는 재사용 가능한 함수와 루틴들을 모아 놓은 것으로 이러한 Library를 구조화 시켜 Framework을 만든다고 보면 되겠다.
재사용의 범위는 일반적으로
Library < Component < Framework < Architecture
라고 볼 수 있겠다.
jpeg decoder source
Well, here it is the decoder source.
It takes as an input a JPG file and decodes it into a truecolor BMP.
Opposite to the encoder, it's not so optimized or clear as I wanted.
But since I received a lot of emails asking for it, here it is.
It is written long ago and since then I was quite busy learning other stuff
and I haven't modified it as it should [Huffman decoder probably can be made
better and IDCT (the most consuming CPU part) -- should be done faster],
so don't expect a super fast decoder [though it's speed seems reasonable].
Few comments are in romanian.
Some ideas have been taken from Independent JPEG Group's JPEG software.
(IDCT routine is taken with minor modifications)
It compiles under WATCOM C (still my favourite compiler) 10.0 for DOS, and
VISUAL C 5.0 (if you turn on optimizations in VC 5.0, make sure that the option
"assume aliasing across function calls" it's turned on for the "jpegdec.c" module).
I haven't tested it under other compilers.
I don't know when I'll have the time to make it better, but in the meantime,
I'd like to hear from you if you make it more clear and/or faster.
You are free to modify it as you want, but it would be nice to say somewhere
that you used ideas from these routines.
Disclaimer
----------
NO WARRANTY PROVIDED WITH THIS PROGRAM.
So, use it at your own risk.
It's status: freeware.
Author email:
cristic22@yahoo.com
////////////////////////////////////////////////
BEGINNING OF HEADERS
/////////////////////////////////////////////////
#ifndef __JPEGDEC_H__
#define __JPEGDEC_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BYTE unsigned char
#define WORD unsigned short int
#define DWORD unsigned int
#define SDWORD signed int
#define SBYTE signed char
#define SWORD signed short int
int load_JPEG_header(FILE *fp, DWORD *X_image, DWORD *Y_image);
void decode_JPEG_image();
int get_JPEG_buffer(WORD X_image,WORD Y_image, BYTE **address_dest_buffer);
#endif
/////////////////////////////////////////////////
BEGINNING OF PROGRAM SOURCE
//////////////////////////////////////////////////
#include "jpegdec.h"
#include <conio.h>
#include <time.h>
char *FileName="image.jpg";
extern char error_string[90];
typedef struct s_BM_header {
WORD BMP_id ; // 'B''M'
DWORD size; // size in bytes of the BMP file
DWORD zero_res; // 0
DWORD offbits; // 54
DWORD biSize; // 0x28
DWORD Width; // X
DWORD Height; // Y
WORD biPlanes; // 1
WORD biBitCount ; // 24
DWORD biCompression; // 0 = BI_RGB
DWORD biSizeImage; // 0
DWORD biXPelsPerMeter; // 0xB40
DWORD biYPelsPerMeter; // 0xB40
DWORD biClrUsed; //0
DWORD biClrImportant; //0
} BM_header;
typedef struct s_RGB {
BYTE B;
BYTE G;
BYTE R;
} RGB;
void exitmessage(char *message)
{
printf("%s\n",message);exit(0);
}
void write_buf_to_BMP(BYTE *im_buffer, WORD X_bitmap, WORD Y_bitmap, char *BMPname)
{
SWORD x,y;
RGB *pixel;
BM_header BH;
FILE *fp_bitmap;
DWORD im_loc_bytes;
BYTE nr_fillingbytes, i;
BYTE zero_byte=0;
fp_bitmap=fopen(BMPname,"wb");
if (fp_bitmap==NULL) exitmessage("File cannot be created");
if (X_bitmap%4!=0) nr_fillingbytes=4-((X_bitmap*3L)%4);
else nr_fillingbytes=0;
BH.BMP_id = 'M'*256+'B'; fwrite(&BH.BMP_id,2,1,fp_bitmap);
BH.size=54+Y_bitmap*(X_bitmap*3+nr_fillingbytes);fwrite(&BH.size,4,1,fp_bitmap);
BH.zero_res = 0; fwrite(&BH.zero_res,4,1,fp_bitmap);
BH.offbits = 54; fwrite(&BH.offbits,4,1,fp_bitmap);
BH.biSize = 0x28; fwrite(&BH.biSize,4,1,fp_bitmap);
BH.Width = X_bitmap; fwrite(&BH.Width,4,1,fp_bitmap);
BH.Height = Y_bitmap; fwrite(&BH.Height,4,1,fp_bitmap);
BH.biPlanes = 1; fwrite(&BH.biPlanes,2,1,fp_bitmap);
BH.biBitCount = 24; fwrite(&BH.biBitCount,2,1,fp_bitmap);
BH.biCompression = 0; fwrite(&BH.biCompression,4,1,fp_bitmap);
BH.biSizeImage = 0; fwrite(&BH.biSizeImage,4,1,fp_bitmap);
BH.biXPelsPerMeter = 0xB40; fwrite(&BH.biXPelsPerMeter,4,1,fp_bitmap);
BH.biYPelsPerMeter = 0xB40; fwrite(&BH.biYPelsPerMeter,4,1,fp_bitmap);
BH.biClrUsed = 0; fwrite(&BH.biClrUsed,4,1,fp_bitmap);
BH.biClrImportant = 0; fwrite(&BH.biClrImportant,4,1,fp_bitmap);
printf("Writing bitmap ...\n");
im_loc_bytes=(DWORD)im_buffer+((DWORD)Y_bitmap-1)*X_bitmap*4;
for (y=0;y<Y_bitmap;y++)
{
for (x=0;x<X_bitmap;x++)
{
pixel=(RGB *)im_loc_bytes;
fwrite(pixel, 3, 1, fp_bitmap);
im_loc_bytes+=4;
}
for (i=0;i<nr_fillingbytes;i++)
fwrite(&zero_byte,1,1,fp_bitmap);
im_loc_bytes-=2L*X_bitmap*4;
}
printf("Done.\n");
fclose(fp_bitmap);
}
void main(int argc, char *argv[])
{
FILE *fp;
DWORD X_image, Y_image;
BYTE *our_image_buffer;
clock_t start_time, finish_time;
float duration;
if (argc<=1) fp=fopen(FileName,"rb");
else fp=fopen(argv[1],"rb");
if (fp==NULL) exitmessage("File not found ?");
if (!load_JPEG_header(fp,&X_image,&Y_image)) {exitmessage(error_string);return;}
fclose(fp);
printf(" X_image = %d\n",X_image);
printf(" Y_image = %d\n",Y_image);
/*
printf("Sampling factors: \n");
printf("Y : H=%d,V=%d\n", YH,YV);
printf("Cb : H=%d,V=%d\n", CbH,CbV);
printf("Cr : H=%d,V=%d\n", CrH,CrV);
printf("Restart markers = %d\n", Restart_markers);
printf("MCU restart = %d\n", MCU_restart);
getch();
*/
printf("Decoding JPEG image...\n");
// main decoder
start_time = clock();
decode_JPEG_image();
printf("Decoding finished.\n");
finish_time = clock();
duration = (double)(finish_time - start_time) / CLK_TCK;
printf( "Time elapsed: %2.1f seconds\n", duration );
if (!get_JPEG_buffer(X_image,Y_image,&our_image_buffer)) {exitmessage(error_string);return;}
write_buf_to_BMP(our_image_buffer,X_image,Y_image, "image.bmp");
getch();
}
////////////////////////////////////////////////
DECODER SOURCE CODE
////////////////////////////////////////////////
// JPEG decoder module
// Copyright 1999 Cristi Cuturicu
#include "jpegdec.h"
// Used markers:
#define SOI 0xD8
#define EOI 0xD9
#define APP0 0xE0
#define SOF 0xC0
#define DQT 0xDB
#define DHT 0xC4
#define SOS 0xDA
#define DRI 0xDD
#define COM 0xFE
char error_string[90];
#define exit_func(err) { strcpy(error_string, err); return 0;}
static BYTE *buf; // the buffer we use for storing the entire JPG file
static BYTE bp; //current byte
static WORD wp; //current word
static DWORD byte_pos; // current byte position
#define BYTE_p(i) bp=buf[(i)++]
#define WORD_p(i) wp=(((WORD)(buf[(i)]))<<8) + buf[(i)+1]; (i)+=2
// WORD X_image_size,Y_image_size; // X,Y sizes of the image
static WORD X_round,Y_round; // The dimensions rounded to multiple of Hmax*8 (X_round)
// and Ymax*8 (Y_round)
static BYTE *im_buffer; // RGBA image buffer
static DWORD X_image_bytes; // size in bytes of 1 line of the image = X_round * 4
static DWORD y_inc_value ; // 32*X_round; // used by decode_MCU_1x2,2x1,2x2
BYTE YH,YV,CbH,CbV,CrH,CrV; // sampling factors (horizontal and vertical) for Y,Cb,Cr
static WORD Hmax,Vmax;
static BYTE zigzag[64]={ 0, 1, 5, 6,14,15,27,28,
2, 4, 7,13,16,26,29,42,
3, 8,12,17,25,30,41,43,
9,11,18,24,31,40,44,53,
10,19,23,32,39,45,52,54,
20,22,33,38,46,51,55,60,
21,34,37,47,50,56,59,61,
35,36,48,49,57,58,62,63 };
typedef struct {
BYTE Length[17]; // k =1-16 ; L[k] indicates the number of Huffman codes of length k
WORD minor_code[17]; // indicates the value of the smallest Huffman code of length k
WORD major_code[17]; // similar, but the highest code
BYTE V[65536]; // V[k][j] = Value associated to the j-th Huffman code of length k
// High nibble = nr of previous 0 coefficients
// Low nibble = size (in bits) of the coefficient which will be taken from the data stream
} Huffman_table;
static float *QT[4]; // quantization tables, no more than 4 quantization tables (QT[0..3])
static Huffman_table HTDC[4]; //DC huffman tables , no more than 4 (0..3)
static Huffman_table HTAC[4]; //AC huffman tables (0..3)
static BYTE YQ_nr,CbQ_nr,CrQ_nr; // quantization table number for Y, Cb, Cr
static BYTE YDC_nr,CbDC_nr,CrDC_nr; // DC Huffman table number for Y,Cb, Cr
static BYTE YAC_nr,CbAC_nr,CrAC_nr; // AC Huffman table number for Y,Cb, Cr
static BYTE Restart_markers; // if 1 => Restart markers on , 0 => no restart markers
static WORD MCU_restart; //Restart markers appears every MCU_restart MCU blocks
typedef void (*decode_MCU_func)(DWORD);
static SWORD DCY, DCCb, DCCr; // Coeficientii DC pentru Y,Cb,Cr
static SWORD DCT_coeff[64]; // Current DCT_coefficients
static BYTE Y[64],Cb[64],Cr[64]; // Y, Cb, Cr of the current 8x8 block for the 1x1 case
static BYTE Y_1[64],Y_2[64],Y_3[64],Y_4[64];
static BYTE tab_1[64],tab_2[64],tab_3[64],tab_4[64]; // tabelele de supraesantionare pt cele 4 blocuri
static SWORD Cr_tab[256],Cb_tab[256]; // Precalculated Cr, Cb tables
static SWORD Cr_Cb_green_tab[65536];
// Initial conditions:
// byte_pos = start position in the Huffman coded segment
// WORD_get(w1); WORD_get(w2);wordval=w1;
static BYTE d_k=0; // Bit displacement in memory, relative to the offset of w1
// it's always <16
static WORD w1,w2; // w1 = First word in memory; w2 = Second word
static DWORD wordval ; // the actual used value in Huffman decoding.
static DWORD mask[17];
static SWORD neg_pow2[17]={0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
static DWORD start_neg_pow2=(DWORD)neg_pow2;
static int shift_temp;
#define RIGHT_SHIFT(x,shft) \
((shift_temp = (x)) < 0 ? \
(shift_temp >> (shft)) | ((~(0L)) << (32-(shft))) : \
(shift_temp >> (shft)))
#define DESCALE(x,n) RIGHT_SHIFT((x) + (1L << ((n)-1)), n)
#define RANGE_MASK 1023L
static BYTE *rlimit_table;
void prepare_range_limit_table()
/* Allocate and fill in the sample_range_limit table */
{
int j;
rlimit_table = (BYTE *)malloc(5 * 256L + 128) ;
/* First segment of "simple" table: limit[x] = 0 for x < 0 */
memset((void *)rlimit_table,0,256);
rlimit_table += 256; /* allow negative subscripts of simple table */
/* Main part of "simple" table: limit[x] = x */
for (j = 0; j < 256; j++) rlimit_table[j] = j;
/* End of simple table, rest of first half of post-IDCT table */
for (j = 256; j < 640; j++) rlimit_table[j] = 255;
/* Second half of post-IDCT table */
memset((void *)(rlimit_table + 640),0,384);
for (j = 0; j < 128 ; j++) rlimit_table[j+1024] = j;
}
#ifdef _MSC_VER
WORD lookKbits(BYTE k)
{
_asm {
mov dl, k
mov cl, 16
sub cl, dl
mov eax, [wordval]
shr eax, cl
}
}
WORD WORD_hi_lo(BYTE byte_high,BYTE byte_low)
{
_asm {
mov ah,byte_high
mov al,byte_low
}
}
SWORD get_svalue(BYTE k)
// k>0 always
// Takes k bits out of the BIT stream (wordval), and makes them a signed value
{
_asm {
xor ecx, ecx
mov cl,k
mov eax,[wordval]
shl eax,cl
shr eax, 16
dec cl
bt eax,ecx
jc end_macro
signed_value:inc cl
mov ebx,[start_neg_pow2]
add ax,word ptr [ebx+ecx*2]
end_macro:
}
}
#endif
#ifdef __WATCOMC__
WORD lookKbits(BYTE k);
#pragma aux lookKbits=\
"mov eax,[wordval]"\
"mov cl, 16"\
"sub cl, dl"\
"shr eax, cl"\
parm [dl] \
value [ax] \
modify [eax cl];
WORD WORD_hi_lo(BYTE byte_high,BYTE BYTE_low);
#pragma aux WORD_hi_lo=\
parm [ah] [al]\
value [ax] \
modify [ax];
SWORD get_svalue(BYTE k);
// k>0 always
// Takes k bits out of the BIT stream (wordval), and makes them a signed value
#pragma aux get_svalue=\
"xor ecx, ecx"\
"mov cl, al"\
"mov eax,[wordval]"\
"shl eax, cl"\
"shr eax, 16"\
"dec cl"\
"bt eax,ecx"\
"jc end_macro"\
"signed_value:inc cl"\
"mov ebx,[start_neg_pow2]"\
"add ax,word ptr [ebx+ecx*2]"\
"end_macro:"\
parm [al]\
modify [eax ebx ecx]\
value [ax];
#endif
void skipKbits(BYTE k)
{
BYTE b_high,b_low;
d_k+=k;
if (d_k>=16) { d_k-=16;
w1=w2;
// Get the next word in w2
BYTE_p(byte_pos);
if (bp!=0xFF) b_high=bp;
else {
if (buf[byte_pos]==0) byte_pos++; //skip 00
else byte_pos--; // stop byte_pos pe restart marker
b_high=0xFF;
}
BYTE_p(byte_pos);
if (bp!=0xFF) b_low=bp;
else {
if (buf[byte_pos]==0) byte_pos++; //skip 00
else byte_pos--; // stop byte_pos pe restart marker
b_low=0xFF;
}
w2=WORD_hi_lo(b_high,b_low);
}
wordval = ((DWORD)(w1)<<16) + w2;
wordval <<= d_k;
wordval >>= 16;
}
SWORD getKbits(BYTE k)
{
SWORD signed_wordvalue;
signed_wordvalue=get_svalue(k);
skipKbits(k);
return signed_wordvalue;
}
void calculate_mask()
{
BYTE k;
DWORD tmpdv;
for (k=0;k<=16;k++) { tmpdv=0x10000;mask[k]=(tmpdv>>k)-1;} //precalculated bit mask
}
void init_QT()
{
BYTE i;
for (i=0;i<=3;i++) QT[i]=(float *)malloc(sizeof(float)*64);
}
void load_quant_table(float *quant_table)
{
float scalefactor[8]={1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
BYTE j,row,col;
// Load quantization coefficients from JPG file, scale them for DCT and reorder
// from zig-zag order
for (j=0;j<=63;j++) quant_table[j]=buf[byte_pos+zigzag[j]];
j=0;
for (row=0;row<=7;row++)
for (col=0;col<=7;col++) {
quant_table[j]*=scalefactor[row]*scalefactor[col];
j++;
}
byte_pos+=64;
}
void load_Huffman_table(Huffman_table *HT)
{
BYTE k,j;
DWORD code;
for (j=1;j<=16;j++) {
BYTE_p(byte_pos);
HT->Length[j]=bp;
}
for (k=1;k<=16;k++)
for (j=0;j<HT->Length[k];j++) {
BYTE_p(byte_pos);
HT->V[WORD_hi_lo(k,j)]=bp;
}
code=0;
for (k=1;k<=16;k++) {
HT->minor_code[k] = (WORD)code;
for (j=1;j<=HT->Length[k];j++) code++;
HT->major_code[k]=(WORD)(code-1);
code*=2;
if (HT->Length[k]==0) {
HT->minor_code[k]=0xFFFF;
HT->major_code[k]=0;
}
}
}
void process_Huffman_data_unit(BYTE DC_nr, BYTE AC_nr,SWORD *previous_DC)
{
// Process one data unit. A data unit = 64 DCT coefficients
// Data is decompressed by Huffman decoding, then the array is dezigzag-ed
// The result is a 64 DCT coefficients array: DCT_coeff
BYTE nr,k,j,EOB_found;
register WORD tmp_Hcode;
BYTE size_val,count_0;
WORD *min_code,*maj_code; // min_code[k]=minimum code of length k, maj_code[k]=similar but maximum
WORD *max_val, *min_val;
BYTE *huff_values;
SWORD DCT_tcoeff[64];
BYTE byte_temp;
// Start Huffman decoding
// First the DC coefficient decoding
min_code=HTDC[DC_nr].minor_code;
maj_code=HTDC[DC_nr].major_code;
huff_values=HTDC[DC_nr].V;
for (nr = 0; nr < 64 ; nr++) DCT_tcoeff[nr] = 0; //Initialize DCT_tcoeff
nr=0;// DC coefficient
min_val = &min_code[1]; max_val = &maj_code[1];
for (k=1;k<=16;k++) {
tmp_Hcode=lookKbits(k);
// max_val = &maj_code[k]; min_val = &min_code[k];
if ( (tmp_Hcode<=*max_val)&&(tmp_Hcode>=*min_val) ) { //Found a valid Huffman code
skipKbits(k);
size_val=huff_values[WORD_hi_lo(k,(BYTE)(tmp_Hcode-*min_val))];
if (size_val==0) DCT_tcoeff[0]=*previous_DC;
else {
DCT_tcoeff[0]=*previous_DC+getKbits(size_val);
*previous_DC=DCT_tcoeff[0];
}
break;
}
min_val++; max_val++;
}
// Second, AC coefficient decoding
min_code=HTAC[AC_nr].minor_code;
maj_code=HTAC[AC_nr].major_code;
huff_values=HTAC[AC_nr].V;
nr=1; // AC coefficient
EOB_found=0;
while ( (nr<=63)&&(!EOB_found) )
{
max_val = &maj_code[1]; min_val =&min_code[1];
for (k=1;k<=16;k++)
{
tmp_Hcode=lookKbits(k);
// max_val = &maj_code[k]; &min_val = min_code[k];
if ( (tmp_Hcode<=*max_val)&&(tmp_Hcode>=*min_val) )
{
skipKbits(k);
byte_temp=huff_values[WORD_hi_lo(k,(BYTE)(tmp_Hcode-*min_val))];
size_val=byte_temp&0xF;
count_0=byte_temp>>4;
if (size_val==0) {if (count_0==0) EOB_found=1;
else if (count_0==0xF) nr+=16; //skip 16 zeroes
}
else
{
nr+=count_0; //skip count_0 zeroes
DCT_tcoeff[nr++]=getKbits(size_val);
}
break;
}
min_val++; max_val++;
}
if (k>16) nr++; // This should not occur
}
for (j=0;j<=63;j++) DCT_coeff[j]=DCT_tcoeff[zigzag[j]]; // Et, voila ... DCT_coeff
}
void IDCT_transform(SWORD *incoeff,BYTE *outcoeff,BYTE Q_nr)
// Fast float IDCT transform
{
BYTE x;
SBYTE y;
SWORD *inptr;
BYTE *outptr;
float workspace[64];
float *wsptr;//Workspace pointer
float *quantptr; // Quantization table pointer
float dcval;
float tmp0,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7;
float tmp10,tmp11,tmp12,tmp13;
float z5,z10,z11,z12,z13;
BYTE *range_limit=rlimit_table+128;
// Pass 1: process COLUMNS from input and store into work array.
wsptr=workspace;
inptr=incoeff;
quantptr=QT[Q_nr];
for (y=0;y<=7;y++)
{
if( (inptr[8]|inptr[16]|inptr[24]|inptr[32]|inptr[40]|inptr[48]|inptr[56])==0)
{
// AC terms all zero (in a column)
dcval=inptr[0]*quantptr[0];
wsptr[0] = dcval;
wsptr[8] = dcval;
wsptr[16] = dcval;
wsptr[24] = dcval;
wsptr[32] = dcval;
wsptr[40] = dcval;
wsptr[48] = dcval;
wsptr[56] = dcval;
inptr++;quantptr++;wsptr++;//advance pointers to next column
continue ;
}
//Even part
tmp0 = inptr[0] *quantptr[0];
tmp1 = inptr[16]*quantptr[16];
tmp2 = inptr[32]*quantptr[32];
tmp3 = inptr[48]*quantptr[48];
tmp10 = tmp0 + tmp2;// phase 3
tmp11 = tmp0 - tmp2;
tmp13 = tmp1 + tmp3;// phases 5-3
tmp12 = (tmp1 - tmp3) * 1.414213562f - tmp13; // 2*c4
tmp0 = tmp10 + tmp13;// phase 2
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
// Odd part
tmp4 = inptr[8] *quantptr[8];
tmp5 = inptr[24]*quantptr[24];
tmp6 = inptr[40]*quantptr[40];
tmp7 = inptr[56]*quantptr[56];
z13 = tmp6 + tmp5;// phase 6
z10 = tmp6 - tmp5;
z11 = tmp4 + tmp7;
z12 = tmp4 - tmp7;
tmp7 = z11 + z13;// phase 5
tmp11= (z11 - z13) * 1.414213562f; // 2*c4
z5 = (z10 + z12) * 1.847759065f; // 2*c2
tmp10 = 1.082392200f * z12 - z5; // 2*(c2-c6)
tmp12 = -2.613125930f * z10 + z5;// -2*(c2+c6)
tmp6 = tmp12 - tmp7;// phase 2
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
wsptr[0] = tmp0 + tmp7;
wsptr[56] = tmp0 - tmp7;
wsptr[8] = tmp1 + tmp6;
wsptr[48] = tmp1 - tmp6;
wsptr[16] = tmp2 + tmp5;
wsptr[40] = tmp2 - tmp5;
wsptr[32] = tmp3 + tmp4;
wsptr[24] = tmp3 - tmp4;
inptr++;
quantptr++;
wsptr++;//advance pointers to the next column
}
// Pass 2: process ROWS from work array, store into output array.
// Note that we must descale the results by a factor of 8 = 2^3
outptr=outcoeff;
wsptr=workspace;
for (x=0;x<=7;x++)
{
// Even part
tmp10 = wsptr[0] + wsptr[4];
tmp11 = wsptr[0] - wsptr[4];
tmp13 = wsptr[2] + wsptr[6];
tmp12 =(wsptr[2] - wsptr[6]) * 1.414213562f - tmp13;
tmp0 = tmp10 + tmp13;
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
// Odd part
z13 = wsptr[5] + wsptr[3];
z10 = wsptr[5] - wsptr[3];
z11 = wsptr[1] + wsptr[7];
z12 = wsptr[1] - wsptr[7];
tmp7 = z11 + z13;
tmp11= (z11 - z13) * 1.414213562f;
z5 = (z10 + z12) * 1.847759065f; // 2*c2
tmp10 = 1.082392200f * z12 - z5; // 2*(c2-c6)
tmp12 = -2.613125930f * z10 + z5; // -2*(c2+c6)
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
// Final output stage: scale down by a factor of 8
outptr[0] = range_limit[(DESCALE((int) (tmp0 + tmp7), 3)) & 1023L];
outptr[7] = range_limit[(DESCALE((int) (tmp0 - tmp7), 3)) & 1023L];
outptr[1] = range_limit[(DESCALE((int) (tmp1 + tmp6), 3)) & 1023L];
outptr[6] = range_limit[(DESCALE((int) (tmp1 - tmp6), 3)) & 1023L];
outptr[2] = range_limit[(DESCALE((int) (tmp2 + tmp5), 3)) & 1023L];
outptr[5] = range_limit[(DESCALE((int) (tmp2 - tmp5), 3)) & 1023L];
outptr[4] = range_limit[(DESCALE((int) (tmp3 + tmp4), 3)) & 1023L];
outptr[3] = range_limit[(DESCALE((int) (tmp3 - tmp4), 3)) & 1023L];
wsptr+=8;//advance pointer to the next row
outptr+=8;
}
}
void precalculate_Cr_Cb_tables()
{
WORD k;
WORD Cr_v,Cb_v;
for (k=0;k<=255;k++) Cr_tab[k]=(SWORD)((k-128.0)*1.402);
for (k=0;k<=255;k++) Cb_tab[k]=(SWORD)((k-128.0)*1.772);
for (Cr_v=0;Cr_v<=255;Cr_v++)
for (Cb_v=0;Cb_v<=255;Cb_v++)
Cr_Cb_green_tab[((WORD)(Cr_v)<<8)+Cb_v]=(int)(-0.34414*(Cb_v-128.0)-0.71414*(Cr_v-128.0));
}
void convert_8x8_YCbCr_to_RGB(BYTE *Y, BYTE *Cb, BYTE *Cr, DWORD im_loc, DWORD X_image_bytes, BYTE *im_buffer)
// Functia (ca optimizare) poate fi apelata si fara parametrii Y,Cb,Cr
// Stim ca va fi apelata doar in cazul 1x1
{
DWORD x,y;
BYTE im_nr;
BYTE *Y_val = Y, *Cb_val = Cb, *Cr_val = Cr;
BYTE *ibuffer = im_buffer + im_loc;
for (y=0;y<8;y++)
{
im_nr=0;
for (x=0;x<8;x++)
{
ibuffer[im_nr++] = rlimit_table[*Y_val + Cb_tab[*Cb_val]]; //B
ibuffer[im_nr++] = rlimit_table[*Y_val + Cr_Cb_green_tab[WORD_hi_lo(*Cr_val,*Cb_val)]]; //G
ibuffer[im_nr++] = rlimit_table[*Y_val + Cr_tab[*Cr_val]]; // R
/*
// Monochrome display
im_buffer[im_nr++] = *Y_val;
im_buffer[im_nr++] = *Y_val;
im_buffer[im_nr++] = *Y_val;
*/
Y_val++; Cb_val++; Cr_val++; im_nr++;
}
ibuffer+=X_image_bytes;
}
}
void convert_8x8_YCbCr_to_RGB_tab(BYTE *Y, BYTE *Cb, BYTE *Cr, BYTE *tab, DWORD im_loc, DWORD X_image_bytes, BYTE *im_buffer)
// Functia (ca optimizare) poate fi apelata si fara parametrii Cb,Cr
{
DWORD x,y;
BYTE nr, im_nr;
BYTE Y_val,Cb_val,Cr_val;
BYTE *ibuffer = im_buffer + im_loc;
nr=0;
for (y=0;y<8;y++)
{
im_nr=0;
for (x=0;x<8;x++)
{
Y_val=Y[nr];
Cb_val=Cb[tab[nr]]; Cr_val=Cr[tab[nr]]; // reindexare folosind tabelul
// de supraesantionare precalculat
ibuffer[im_nr++] = rlimit_table[Y_val + Cb_tab[Cb_val]]; //B
ibuffer[im_nr++] = rlimit_table[Y_val + Cr_Cb_green_tab[WORD_hi_lo(Cr_val,Cb_val)]]; //G
ibuffer[im_nr++] = rlimit_table[Y_val + Cr_tab[Cr_val]]; // R
nr++; im_nr++;
}
ibuffer+=X_image_bytes;
}
}
void calculate_tabs()
{
BYTE tab_temp[256];
BYTE x,y;
// Tabelul de supraesantionare 16x16
for (y=0;y<16;y++)
for (x=0;x<16;x++)
tab_temp[y*16+x] = (y/YV)* 8 + x/YH;
// Din el derivam tabelele corespunzatoare celor 4 blocuri de 8x8 pixeli
for (y=0;y<8;y++)
{
for (x=0;x<8;x++)
tab_1[y*8+x]=tab_temp[y*16+x];
for (x=8;x<16;x++)
tab_2[y*8+(x-8)]=tab_temp[y*16+x];
}
for (y=8;y<16;y++)
{
for (x=0;x<8;x++)
tab_3[(y-8)*8+x]=tab_temp[y*16+x];
for (x=8;x<16;x++)
tab_4[(y-8)*8+(x-8)]=tab_temp[y*16+x];
}
}
int init_JPG_decoding()
{
byte_pos=0;
init_QT();
calculate_mask();
prepare_range_limit_table();
precalculate_Cr_Cb_tables();
return 1; //for future error check
}
DWORD filesize(FILE *fp)
{
DWORD pos;
DWORD pos_cur;
pos_cur=ftell(fp);
fseek(fp,0,SEEK_END);
pos=ftell(fp);
fseek(fp,pos_cur,SEEK_SET);
return pos;
}
int load_JPEG_header(FILE *fp, DWORD *X_image, DWORD *Y_image)
{
DWORD length_of_file;
BYTE vers,units;
WORD Xdensity,Ydensity,Xthumbnail,Ythumbnail;
WORD length;
float *qtable;
DWORD old_byte_pos;
Huffman_table *htable;
DWORD j;
BYTE precision,comp_id,nr_components;
BYTE QT_info,HT_info;
BYTE SOS_found,SOF_found;
length_of_file=filesize(fp);
buf=(BYTE *)malloc(length_of_file+4);
if (buf==NULL) exit_func("Not enough memory for loading file");
fread(buf,length_of_file,1,fp);
if ((buf[0]!=0xFF)||(buf[1]!=SOI)) exit_func("Not a JPG file ?\n");
if ((buf[2]!=0xFF)||(buf[3]!=APP0)) exit_func("Invalid JPG file.");
if ( (buf[6]!='J')||(buf[7]!='F')||(buf[8]!='I')||(buf[9]!='F')||
(buf[10]!=0) ) exit_func("Invalid JPG file.");
init_JPG_decoding();
byte_pos=11;
BYTE_p(byte_pos);vers=bp;
if (vers!=1) exit_func("JFIF version not supported");
BYTE_p(byte_pos); // vers_lo=bp;
BYTE_p(byte_pos); units=bp;
if (units!=0) //exit_func("JPG format not supported");
;// printf("units = %d\n", units);
WORD_p(byte_pos); Xdensity=wp; WORD_p(byte_pos); Ydensity=wp;
if ((Xdensity!=1)||(Ydensity!=1)) //exit_func("JPG format not supported");
; //{printf("X density = %d\n",Xdensity); printf("Y density = %d\n",Ydensity);}
BYTE_p(byte_pos);Xthumbnail=bp;BYTE_p(byte_pos);Ythumbnail=bp;
if ((Xthumbnail!=0)||(Ythumbnail!=0))
exit_func(" Cannot process JFIF thumbnailed files\n");
// Start decoding process
SOS_found=0; SOF_found=0; Restart_markers=0;
while ((byte_pos<length_of_file)&&!SOS_found)
{
BYTE_p(byte_pos);
if (bp!=0xFF) continue;
// A marker was found
BYTE_p(byte_pos);
switch(bp)
{
case DQT: WORD_p(byte_pos); length=wp; // length of the DQT marker
for (j=0;j<wp-2;)
{
old_byte_pos=byte_pos;
BYTE_p(byte_pos); QT_info=bp;
if ((QT_info>>4)!=0)
exit_func("16 bit quantization table not supported");
qtable=QT[QT_info&0xF];
load_quant_table(qtable);
j+=byte_pos-old_byte_pos;
}
break;
case DHT: WORD_p(byte_pos); length=wp;
for (j=0;j<wp-2;)
{
old_byte_pos=byte_pos;
BYTE_p(byte_pos); HT_info=bp;
if ((HT_info&0x10)!=0) htable=&HTAC[HT_info&0xF];
else htable=&HTDC[HT_info&0xF];
load_Huffman_table(htable);
j+=byte_pos-old_byte_pos;
}
break;
case COM: WORD_p(byte_pos); length=wp;
byte_pos+=wp-2;
break;
case DRI: Restart_markers=1;
WORD_p(byte_pos); length=wp; //should be = 4
WORD_p(byte_pos); MCU_restart=wp;
if (MCU_restart==0) Restart_markers=0;
break;
case SOF: WORD_p(byte_pos); length=wp; //should be = 8+3*3=17
BYTE_p(byte_pos); precision=bp;
if (precision!=8) exit_func("Only 8 bit precision supported");
WORD_p(byte_pos); *Y_image=wp; WORD_p(byte_pos); *X_image=wp;
BYTE_p(byte_pos); nr_components=bp;
if (nr_components!=3) exit_func("Only truecolor JPGS supported");
for (j=1;j<=3;j++)
{
BYTE_p(byte_pos); comp_id=bp;
if ((comp_id==0)||(comp_id>3)) exit_func("Only YCbCr format supported");
switch (comp_id)
{
case 1: // Y
BYTE_p(byte_pos); YH=bp>>4;YV=bp&0xF;
BYTE_p(byte_pos); YQ_nr=bp;
break;
case 2: // Cb
BYTE_p(byte_pos); CbH=bp>>4;CbV=bp&0xF;
BYTE_p(byte_pos); CbQ_nr=bp;
break;
case 3: // Cr
BYTE_p(byte_pos); CrH=bp>>4;CrV=bp&0xF;
BYTE_p(byte_pos); CrQ_nr=bp;
break;
}
}
SOF_found=1;
break;
case SOS: WORD_p(byte_pos); length=wp; //should be = 6+3*2=12
BYTE_p(byte_pos); nr_components=bp;
if (nr_components!=3) exit_func("Invalid SOS marker");
for (j=1;j<=3;j++)
{
BYTE_p(byte_pos); comp_id=bp;
if ((comp_id==0)||(comp_id>3)) exit_func("Only YCbCr format supported");
switch (comp_id)
{
case 1: // Y
BYTE_p(byte_pos); YDC_nr=bp>>4;YAC_nr=bp&0xF;
break;
case 2: // Cb
BYTE_p(byte_pos); CbDC_nr=bp>>4;CbAC_nr=bp&0xF;
break;
case 3: // Cr
BYTE_p(byte_pos); CrDC_nr=bp>>4;CrAC_nr=bp&0xF;
break;
}
}
BYTE_p(byte_pos); BYTE_p(byte_pos); BYTE_p(byte_pos); // Skip 3 bytes
SOS_found=1;
break;
case 0xFF:
break; // do nothing for 0xFFFF, sequence of consecutive 0xFF are for
// filling purposes and should be ignored
default: WORD_p(byte_pos); length=wp;
byte_pos+=wp-2; //skip unknown marker
break;
}
}
if (!SOS_found) exit_func("Invalid JPG file. No SOS marker found.");
if (!SOF_found) exit_func("Progressive JPEGs not supported");
if ((CbH>YH)||(CrH>YH)) exit_func("Vertical sampling factor for Y should be >= sampling factor for Cb,Cr");
if ((CbV>YV)||(CrV>YV)) exit_func("Horizontal sampling factor for Y should be >= sampling factor for Cb,Cr");
if ((CbH>=2)||(CbV>=2)) exit_func("Cb sampling factors should be = 1");
if ((CrV>=2)||(CrV>=2)) exit_func("Cr sampling factors should be = 1");
// Restricting sampling factors for Y,Cb,Cr should give us 4 possible cases for sampling factors
// YHxYV,CbHxCbV,CrHxCrV: 2x2,1x1,1x1; 1x2,1x1,1x1; 2x1,1x1,1x1;
// and 1x1,1x1,1x1 = no upsampling needed
Hmax=YH,Vmax=YV;
if ( *X_image%(Hmax*8)==0) X_round=*X_image; // X_round = Multiple of Hmax*8
else X_round=(*X_image/(Hmax*8)+1)*(Hmax*8);
if ( *Y_image%(Vmax*8)==0) Y_round=*Y_image; // Y_round = Multiple of Vmax*8
else Y_round=(*Y_image/(Vmax*8)+1)*(Vmax*8);
im_buffer=(BYTE *)malloc(X_round*Y_round*4);
if (im_buffer==NULL) exit_func("Not enough memory for storing the JPEG image");
return 1;
}
void resync()
// byte_pos = pozitionat pe restart marker
{
byte_pos+=2;
BYTE_p(byte_pos);
if (bp==0xFF) byte_pos++; // skip 00
w1=WORD_hi_lo(bp, 0);
BYTE_p(byte_pos);
if (bp==0xFF) byte_pos++; // skip 00
w1+=bp;
BYTE_p(byte_pos);
if (bp==0xFF) byte_pos++; // skip 00
w2=WORD_hi_lo(bp, 0);
BYTE_p(byte_pos);
if (bp==0xFF) byte_pos++; // skip 00
w2+=bp;
wordval=w1; d_k=0; // Reinit bitstream decoding
DCY=0; DCCb=0; DCCr=0; // Init DC coefficients
}
void decode_MCU_1x1(DWORD im_loc)
{
// Y
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y,YQ_nr);
// Cb
process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
IDCT_transform(DCT_coeff,Cb,CbQ_nr);
// Cr
process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
IDCT_transform(DCT_coeff,Cr,CrQ_nr);
convert_8x8_YCbCr_to_RGB(Y,Cb,Cr,im_loc,X_image_bytes,im_buffer);
}
void decode_MCU_2x1(DWORD im_loc)
{
// Y
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_1,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_2,YQ_nr);
// Cb
process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
IDCT_transform(DCT_coeff,Cb,CbQ_nr);
// Cr
process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
IDCT_transform(DCT_coeff,Cr,CrQ_nr);
convert_8x8_YCbCr_to_RGB_tab(Y_1,Cb,Cr,tab_1,im_loc,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_2,Cb,Cr,tab_2,im_loc+32,X_image_bytes,im_buffer);
}
void decode_MCU_2x2(DWORD im_loc)
{
// Y
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_1,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_2,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_3,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_4,YQ_nr);
// Cb
process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
IDCT_transform(DCT_coeff,Cb,CbQ_nr);
// Cr
process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
IDCT_transform(DCT_coeff,Cr,CrQ_nr);
convert_8x8_YCbCr_to_RGB_tab(Y_1,Cb,Cr,tab_1,im_loc,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_2,Cb,Cr,tab_2,im_loc+32,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_3,Cb,Cr,tab_3,im_loc+y_inc_value,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_4,Cb,Cr,tab_4,im_loc+y_inc_value+32,X_image_bytes,im_buffer);
}
void decode_MCU_1x2(DWORD im_loc)
{
// Y
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_1,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_2,YQ_nr);
// Cb
process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
IDCT_transform(DCT_coeff,Cb,CbQ_nr);
// Cr
process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
IDCT_transform(DCT_coeff,Cr,CrQ_nr);
convert_8x8_YCbCr_to_RGB_tab(Y_1,Cb,Cr,tab_1,im_loc,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_2,Cb,Cr,tab_3,im_loc+y_inc_value,X_image_bytes,im_buffer);
}
void decode_JPEG_image()
{
decode_MCU_func decode_MCU;
WORD x_mcu_cnt,y_mcu_cnt;
DWORD nr_mcu;
WORD X_MCU_nr,Y_MCU_nr; // Nr de MCU-uri
DWORD MCU_dim_x; //dimensiunea in bufferul imagine a unui MCU pe axa x
DWORD im_loc_inc; // = 7 * X_round * 4 sau 15*X_round*4;
DWORD im_loc; //locatia in bufferul imagine
byte_pos-=2;
resync();
y_inc_value = 32*X_round;
calculate_tabs(); // Calcul tabele de supraesantionare, tinand cont de YH si YV
if ((YH==1)&&(YV==1)) decode_MCU=decode_MCU_1x1;
else {
if (YH==2)
{
if (YV==2) decode_MCU=decode_MCU_2x2;
else decode_MCU=decode_MCU_2x1;
}
else decode_MCU=decode_MCU_1x2;
}
MCU_dim_x=Hmax*8*4;
Y_MCU_nr=Y_round/(Vmax*8); // nr of MCUs on Y axis
X_MCU_nr=X_round/(Hmax*8); // nr of MCUs on X axis
X_image_bytes=X_round*4; im_loc_inc = (Vmax*8-1) * X_image_bytes;
nr_mcu=0; im_loc=0; // memory location of the current MCU
for (y_mcu_cnt=0;y_mcu_cnt<Y_MCU_nr;y_mcu_cnt++)
{
for (x_mcu_cnt=0;x_mcu_cnt<X_MCU_nr;x_mcu_cnt++)
{
decode_MCU(im_loc);
if ((Restart_markers)&&((nr_mcu+1)%MCU_restart==0)) resync();
nr_mcu++;
im_loc+=MCU_dim_x;
}
im_loc+=im_loc_inc;
}
}
int get_JPEG_buffer(WORD X_image,WORD Y_image, BYTE **address_dest_buffer)
{
WORD y;
DWORD dest_loc=0;
BYTE *src_buffer=im_buffer;
BYTE *dest_buffer_start, *dest_buffer;
DWORD src_bytes_per_line=X_round*4;
DWORD dest_bytes_per_line=X_image*4;
if ((X_round==X_image)&&(Y_round==Y_image))
*address_dest_buffer=im_buffer;
else
{
dest_buffer_start = (BYTE *)malloc(X_image*Y_image*4);
if (dest_buffer_start==NULL) exit_func("Not enough memory for storing the JPEG image");
dest_buffer = dest_buffer_start;
for (y=0;y<Y_image;y++) {
memcpy(dest_buffer,src_buffer,dest_bytes_per_line);
src_buffer+=src_bytes_per_line;
dest_buffer+=dest_bytes_per_line;
}
*address_dest_buffer=dest_buffer_start;
free(im_buffer);
}
// release the buffer which contains the JPG file
free(buf);
return 1;
}
////////////////////////////////////////////////
END OF SOURCE CODE
//////////////////////////////////////////////
오라클(DATABASE MANAGEMENT SYSTEM)
RUNTIME_CLASS
이 방법은 여러모로 사용하기 편하고 쓰레드 클래스 생성시에도 사용가능 하지요.
COject 클래스의 매크로 DECLARE_DYNAMIC이나 DECLARE_DYNCREATE 사용시 Ructime으로 객체를 생성할 수 있다하였습니다.
이유룰 간단히 말씀드리면 DECLARE_DYNAMIC이나 DECLARE_DYNCREATE 매크로는 CObject 클래스에서 CRuntimeClass의 static 멤버를 갖게 됩니다.
이 멤버는 template Class로 정의가 되고 이 클래스의 포인터는 RUNTIME_CLASS 매크로를 사용하면 얻을 수 있습니다.
RUNTIME_CLASS는 다음처럼 정의되죠.
#define RUNTIME_CLASS(class_name) (&class_name::class##class_name)으로 정의되 있습니다.
또 CRuntimeClass 구조체는 다음의 데이터를 가지고 있구요.
struct CRuntimeClass
{
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema
CObject* (PASCAL* m_pfnCreateObject)( );
CObject* CreateObject( );
CRuntimeClass* (PASCAL* m_pfnGetBaseClass)( );
CRuntimeClass* m_pBaseClass;
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
};
위 멤버중 중요하게 생각하실 멤버는 m_lpszClassName, m_nObjectSize, m_pfnCreateObject, CreateObject( )가 중요합니다.
각 멤버를 보면 m_lpszClassName은 생성된 클래스 이름, m_nObjectSize는 메모리가 현재 유효한지 검사하기 위해 사용하며 m_pfnCreateObject는 CreateObject()의 함수포인터를 선언하는 곳입니다.
CreateObject 함수가 실제로 그 클래스들을 동적으로 생성시키는 부분입니다.
MFC를 예로 들면 보통 App클래스의 InitInstance 함수에서 다음처럼 되어 있는 부분을 보시기 바랍니다.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);
위에서 CSingleDoctemplate 클래스는 SDI를 정의한 부분입니다.(이에대해서는 MSDN에 자세히 나와 있습니다.)
그리고 그 생성자에서 바로 Application에 대해 Document, MainFrame, View를 동적으로 생성시킵니다.
그런데 위 3가지 클래스의 헤더파일에 선언된 생성자를 보면 모두 protected 로 선언이 되어 있어 CMyView myView; 형태로 객체를 생성시키지 못하지요.
그리고 각 클래스들은 CRuntimeClass 멤버를 사용할 수 있게 DECLARE_DYNAMIC이나 DECLARE_DYNCREATE 매크로를 사용한 것을 볼 수 있을 것입니다.
즉 MFC에서는 위의 형태로 클래스 객체를 동적으로 생성시킬 수 있는 것입니다.
그러면 각각의 CreteObject() 함수는 어떻게 정의되어 있을까요?
view를 예로 들면
CObject* CView::CreateObject()
{
return new CView;
}
형태로 되어 있어 여기서 메모리 로딩이 되지요. 물론 생성자도 호출이 되고...
그러면 여러분의 이해를 돕기위해 간단히 MFC식으로 C++ 코드를 사용하여 한번 코딩해보면
//Runtime 매크로 정의
#define RUN_TIME_CLASS(class_name) (&class_name::class##class_name)
//베이스 클래스 정의및 선언
class CObject; //베이스 클래스 선언
//////////////Runtime 구조체 정의////////////////////////////////////////////
struct CRuntime //CRuntimeClass 대신 CRuntime으로... (그리고 중요부분만 정의)
{
LPCSTR m_lpszClassName;
int m_nObjectSize;
CObject* (*m_pfnCreateObject)( );
CObject* CreateObject( );
};
////////////////베이스 클래스 정의//////////////////////////////////////////
class CObject
{
public:
virtual CRuntime* GetRuntime()const {return NULL; } //Object의 ClassName은 없슴.
static CRuntime classObject; //DYNAMIC 매크로 사용시
virtual ~CObject() {}
protected:
CObject() { cout << "생성자 CObject!!" << endl ; }
};
//static 멤버변수 초기화
CRuntime CObject::classObject = {"CObject", sizeof(CObject), NULL};
CObject* CRuntime::CreateObject()
{
return (*m_pfnCreateObject)(); //함수 포인터를 사용
}
////////////////View 클래스////////////////////////////////////////////////
class CView : public CObject
{
public:
virtual CRuntime* GetRuntime* GetRuntime()const { return &classCView; }
static CRuntime classCView; //DYNAMIC 매크로 사용시
static CObject* CreteObject(); //DYNCREATE 매크로 사용시
protected:
CView() { cout << "생성자 CView!!" << endl; }
};
CRuntime CView::classCView = {"CView", sizeof(CView), CView::CreateObject};
CObject* CView::CreateObject()
{
return new CView; //생성
}
////////////////Document Class ////////////////////////////////////////
class CDoc : public CObject
{
public:
virtual CRuntime* GetRuntime* GetRuntime()const { return &classCDoc; }
static CRuntime classCDoc; //DYNAMIC 매크로 사용시
static CObject* CreteObject(); //DYNCREATE 매크로 사용시
protected:
CDoc() { cout << "생성자 CDoc!!" << endl; }
};
CRuntime CDoc::classCDoc = {"CDoc", sizeof(CDoc), CDoc::CreateObject};
CObject* CDoc::CreateObject()
{
return new CDoc; //생성
}
//////////////////프로그램 메인함수 /////////////
void main()
{
CRuntime* pView = RUN_TIME_CLASS(CView);
CObject* pObjectView = pView->CreateObject();
cout << "View Class Name: " <<
pObjectView->GetRuntime()->m_lpszClassName << endl;
CRuntime* pDoc = RUN_TIME_CLASS(CDoc);
CObject* pObjectDoc = pDoc->CreateObject();
cout << "Doc Class Name: " <<
pObjectDoc->GetRuntime()->m_lpszClassName << endl;
delete pObjectView;
delete pObjectDoc;
}
의 형태로 MFC는 클래스를 동적으로 생성합니다.
물론 소멸은 MFC에서 하는 방법은 아니지만 여러분들이 MFC FrameWork을 직접 분석해 보시면 아실 겁니다.
select.c
/*
select.c
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/timeb.h>
#define BUFSIZE 30
int main(int argc, char * argv)
{
fd_set reads, temps;
int result;
char message[BUFSIZE];
int str_len;
struct timeval timeout;
FD_ZERO(&reads);
FD_SET(0, &reads);
/*
timeout.tv_sec = 5;
timeout.tv_usec = 100000;
*/
while( true )
{
temps = reads;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
result = select(1, &temps, 0, 0, &timeout);
if( result == -1 )
{
puts("select 오류 발생");
exit(1);
}
else if( result == 0 )
{
puts("시간이 초과되었습니다 : sekect");
}
else
{
if( FD_ISSET(0, &temps) )
{
str_len = read(0, message, BUFSIZE);
message[str_len] = 0;
fputs(message, stdout);
}
}
}
}
mfc
wave file 구조
WAVE FILE의 구조
WAVE 파일은 사운드 파일중에 한 형식으로 윈도우에서 가장 흔하게 쓰이는 파일중에 하나이다. 이번에 이 유령넘이 강좌랍시고 주절 거리는
내용은 이넘의 WAVE 파일을 한번 재생해 보자..는 것이다. WAVE 파일을재생하는데는, 쉽게는 SoundPlay() 함수였던가? .. 한줄이면 족하다...
물론, 지금 이 강좌는 그렇게 한줄이면 끝나는 정도가 아닌, WAVE 파일의 밑바닥부터 꼭대기까지 샅샅히 훑어 내려가며, 그 내부를 마구 파헤쳐
WAVE 파일을 맘대로 주무를 수 있도록 하는 경지?에까지 도달하도록하는것이 목표다.
일단, WAVE 파일이고 머고 간에, 기본적인 공식?부터 알아보고 넘어가도록 하자.사운드라는 것에 대해 깊이 있는 지식을 가지고 있는 사람은
볼 필요가 없겠지만, 어디까지나 처음 시작하는 사람들이 볼 것 이라고가정하고 설명하도록 한다.
WAVE 파일을 재생하면서 가끔 등록정보를 보신 분들은 알겠지만, 대게WAVE 파일의 등록정보라고 하면, 16 Bit , Stereo , 44.1 kHz... 등등
의 정보가 보일것이다. 이게 뭐가 중요하냐고? 중요하다.. 정말 중요하다. 이것으로 WAVE 파일이 시작되는 것이기 때문이다.예를 들어서 다음
과 같은 WAVE 파일이 하나 있다고 보자.
------------------------------------------------------------------
[어떤 WAVE 파일의 등록정보]
- 곡명 : 유령이라 불러라!
- 16 Bit
- Stereo
- 44.1 khz
------------------------------------------------------------------
이 세가지 정보면 WAVE 파일의 모든 것?을 알 수 있다. 일단 이 3가지기본적인 정보만으로 이 WAVE 파일의 초당전송량(Bit/Second)이나,전체
재생시간등을 계산해 보자. (이거 배워두면 정말 좋다..-_-;;..그냥..)
일단 계산하는 방식은 모두 곱한다. 16 Bit 이므로 16 을 곱하고,스테레오 방식이기 때문에 (스테레오는 채널이 2개 이기때문에, 2를 곱한다
당연히 모노는 1채널이기 때문에 1을 곱하면 된다.... 1은 안곱해도 되는구나 --;) 그리고 44.1 kHz 라는 것은 1초에 44100 번 발광을 한다는
소리니까 44100을 곱하면 된다.
16 * 2 * 44100 = 1411200 Bit 다.. 다시 바이트로 고쳐주려면, 나누기 8을 하면 된다. (왜 나누기 8을 하냐고 묻는다면.. 아시다시피.. 8 Bit
는 1 Byte 이기 때문이다..) 나누기 8을 한 결과 176400 이라는 숫자가나왔다.
즉, 이 WAVE 파일은 초당 176400 Byte 의 용량을 전송한다는 얘기다..숫자가 너무 크다고?.. 다시 KByte로 환산해 보자.. 172.265625가 나오
는데,귀찮으니까 소수점 아랫것들은 잘라버리고 정수부분만 읽어보자면172 KB 라고 나올 것이다. 그렇다. 이 WAVE 파일은 1초에 172 KB 나 차
지한다. (더럽게 크구만..) 전체 재생시간을 구하는 것 역시 간단하다.단순히 나누기만 하면 되기 때문이다. 전체 파일 크기를 알고 있다면,
" 전체 파일 크기 / 초당 용량 = 전체 재생 시간 (초 단위) "
라는 공식이 성립되는 것이다.자,이제 자신의 컴퓨터에 들어있는 WAVE들을 모조리 불러다가 그 넘들의 재생시간을 구해보고 실제로 플레이
해본다음 비슷하게 맞는지 비교해 보라.
------------------------------------------------------------------
여기서, 숙제.. 다음의 WAVE 파일들의 전체 크기는 얼마나 될까??????
[1] 8 Bit , Mono , 22 kHz
[2] 16 Bit , Mono , 11 kHz
[3] 16 Bit , Stereo , 22 KHz
각각의 WAVE 파일들의 재생시간은 총 1분 30초씩 이다. 그렇다면 각각의 WAVE 파일들의 전체 파일크기는 얼마나 될까?? ( 대한민국 초등교육
과정을 이수한 사람이라면 누구나 풀 수 있는 문제라서 풀이는 생략..)
------------------------------------------------------------------
WAVE 파일은 대게 8 Bit , 16 Bit 가 많이 쓰이는데, 24, 32 Bit 파일은 별도로 치고.. 대표적인 8 / 16 Bit 파일들은 아래의 그림처럼 파일
에 저장되어 있다. 8 Bit 라면 - 1 Byte 이므로 1 Byte 단위 마다 저장되어 있고, 16 Bit 라면 당연히 2 Byte 마다 저장되어 있다. 아래 그림
을 보면 8 Bit 파일은 전부 16개 (16진수 10까지..) 로 되어 있는 반면 16 Bit 는 같은 크기인데도 8 칸 밖에는 안된다. 이론적으로 16 Bit 는
8 Bit 에 비해 2 배의 용량을 차지하기 때문이다. [ D ] 라고 표기되어있는 것은 본인이 편의상 구분하기 쉽게 [ DATA ] 를 줄여 표현한 것이
고.. ( Mono 는 L / R 구분이 없다 ) Stereo에서 [ L ] , [ R ] 이라고
표기 한 것은 양 채널 ( Left Channel, Right Channel ) 을 뜻 한다...
------------------------------------------------------------------
[ 8 Bit Mono ]
1 2 3 4 5 6 7 8 9 A B C D E F 10
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
: D : D : D : D : D : D : D : D : D : D : D : D : D : D : D : D :
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
[ 8 Bit Stereo ]
1 2 3 4 5 6 7 8 9 A B C D E F 10
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
: L : R : L : R : L : R : L : R : L : R : L : R : L : R : L : R :
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
[ 16Bit Mono ]
1 2 3 4 5 6 7 8
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
: D : D : D : D : D : D : D : D :
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
[16Bit Stereo ]
1 2 3 4 5 6 7 8
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
: L : R : L : R : L : R : L : R :
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
------------------------------------------------------------------
이건 어디까지나 2 채널(Stereo)방식만을 봤을때 그렇다는 것이고, 채널이 많아지면 또 저장구조는 당연히 달라지게 된다. 요즘 흔히 말하는
5.1채널이니 7.1채널이니 하는 것들은, 저것과는 모양새가 또 다르다..
------------------------------------------------------------------
WAVE 파일에 대해서 간략하게나마 알아봤는데,이제부터는 정말 자세히파헤쳐 볼 시간이다. WAVE 파일들은 크게 청크 부분과 데이타 부분으로
나뉜다. 실제 사운드가 들어있는 데이타 부분 앞에는 헤더 청크 부분이있는데, WAVE 파일의 구조를 살펴보면 아래와 같다.
------------------------------------------------------------------
1. Wave 파일 포맷(I)
1) PCMWAVEFORMAT 구조체의 구조
-. WAVEFORMAT wf;
-. WORD wBitsPerSample;
2) WAVEFORMAT 구조체의 구조
-. WORD wFormatTag;
-. WORD nChannels;
-. DWORD nSamplesPerSec;
-. DWORD nAvgBytesPerSec;
-. WORD nBlockAlign;
3) 예 : 22kHz 샘플링된 8bit 스테레오 Wave 파일의 구조
PCMWAVEFORMAT PcmWaveFormat;
PcmWaveFormat.wf.wFormatTag = 1;
PcmWaveFormat.wf.nChannels = 2;
PcmWaveFormat.wf.nSamplesPerSec = 22050;
PcmWaveFormat.wf.nAvgBytesPerSec = 44100;
PcmWaveFormat.wf.nBlockAlign = 2;
PcmWaveFormat.wBitsPerSample = 8;
2. Wave 파일 포맷(II)
------------------------------------------------------------------
데이터형 Byte 내용 의미
------------------------------------------------------------------
1) RIFF chunk
- Char 4 "RIFF" 파일의 종류가 RIFF 파일을 의미
- DWORD 4 FILE SIZE 현재부터 끝까지의 파일크기
(파일크기-4Byte 또는, 데이터 크기
+40Byte)
- Char 4 "WAVE" Wave 파일을 의미
2) FMT sub-chunk
- Char 4 "fmt " FMT sub-chunk의 시작
- DWORD 4 16 현재 포인터(16 Byte)
- short 2 wFormatTag PCMWAVEFORMAT의 값
( 1:Wave Format이 PCM 방식 )
- short 2 nChannels 채널 수 ( 1:모노, 2:스테레오 )
- DWORD 4 nSamplesPerSec 샘플링 수
( 11kHz:11025,
22kHz:22050,
44kHz:44100 )
- DWORD 4 nAvgBytesperSec 초당 샘플바이트
( nSamplesPerSec*BlockAlign )
- short 2 BlockAlign 샘플당 바이트( nChannels*비트/8 )
- short 2 wBitsPerSample 샘플당 비트수
3) Data sub-chunk
- Char 4 "data" 데이터청크의 시작
- DWORD 4 DATA SIZE 데이터의 크기
DATA 데이터
------------------------------------------------------------------
WAVE 파일들을 EDITOR 로 읽어보면 파일의 내용이 아래와 같이 나온다원래는 HEX 값이 나와야 하는데 메모장으로 읽어들였더니..아래처럼 나
왔다.. -_-; 그래도 상관없다. 중요한건 제일 처음 " RIFF " 라는 단어로 시작한다는 것이다. 그 다음에 WAVE 파일 포맷임을 알리는 " WAVE "
라는 단어가 온다. 보통 파일포맷에 따라 헤더에 해당 파일포맷임을 리는 식별자가 오는데 GIF나 PCX, 또는 EXE 파일들을 한번씩 열어 보면
같은 단어로 시작한다는 것을 알 수 있을 것이다.
[1] RIFF$?WAVEfmt D쵆Xdata? ...
[2] RIFF?$WAVEfmt D??data? ...
[3] RIFF? WAVEfmt D ? PAD ?
------------------------------------------------------------------
3 개의 WAVE 파일들을 열어봤는데, 모두 RIFF .. WAVE .. fmt 로 시작하고 있다.이 파일들이 WAVE 파일임을 알 수 있는 것이다. 사실 WAVE파
일에도 ADPCM 이니 PCM 이니 하는 식으로 다양한?포맷이 존재하는데 이
것은 쉽게 생각하면 압축방식의 차이다. 여기서 RIFF 파일 형식이라는
말이 나오는데, RIFF에 대해서 설명하자면..
------------------------------------------------------------------
[ RIFF 파일(Resource Interchange File Format) ]
------------------------------------------------------------------
음성이나 비디오 같은 유의 데이터들은 용량이 매우 크기 때문에 이를저장할 시에는 비트 단위보다는 블록 단위로 저장을 하게 된다.
이러한블록은 가변적인 크기를 가질 수 있는데 이를 위해서는 데이터 블록 앞에 헤더를 사용해 이를 정의해 주어야 한다. 일례로
10 MByte 의 음성
데이터를 파일에 저장 하려할 때 블록 단위로 하지 않으면 데이터를 불러오는데 10M의 메모리가 필요하게 된다. 이렇게 된다면 불러오기도 힘
들 뿐만 아니라 불러오는데 걸리는 시간이 많이 걸리는 단점이 생긴다.그러나 10M의 음성데이터를 0.5M 씩 블록으로 나누어 저장한다면 20 개
의 블록을 가질 것이다. 즉, 0.5M씩 메모리에 불러온 후 출력하고, 메모리를 해제한 후 다시 다음 블록을 불러오면 그만큼 메모리도 절약 할
수 있어 매우 편리하게 된다. 또한 데이터 저장 블록 앞에 블록의 데이터 크기를 넣어주는데, 이는 예를 들자면 어느 시간동안 모노로 듣다가
후에 스테레오로 들을 수 있는 상황 등에 대처하기 쉽다. 이럴 때 데이터 블록 앞에 데이터에 대한 정보를 만들어 준다. 각각의 부분 하나 하
나는 청크(Chunk)라고 하고 처음에 나오는 상자를 부모 청크,그 하단에위치하는 부분을 자식 청크, 데이터들은 데이터 청크라고 한다.이와 같
은 구성 데이터를 저장하는 방식을 RIFF라 하고 위와 같은 구성으로 저장된 데이터를 RIFF 파일이라 한다. WAVE 파일이나 AVI 파일이 바로
RIFF 파일이다.
기타
다음으로 알아두면 앞으로 강좌를 이해하기에 좋을 압축방식들에 대한정보들을 소개한다.
[ PCM(Pulse Code Modulation) 방식 ]
이 방식은 가장 널리 사용되는 방식으로서 음성을 아날로그에서 디지털로 변환하여 양자화(작은 단위화)한 데이터를 그대로 저장한 후 재생할
때에는 그 데이터를 디지털에서 아날로그로 재변환하여 음성 파형을 만든다. 이 방식은 양자화를 할 때 생기는 오차가 존재하지만 재생 시 상
당히 우수한 품질을 가진다.이 방식의 특징은 제로 크로스의 방법에 비해 생성되는 데이터의 양이 많다는 점이다.예를 들어, 샘플링 주파수를
8Khz로 하고 양자화 시 정밀도를 8bit로 하면 8000 * 8 = 64000/sec = 64Kbit/sec로 초당 64KB가 생성된다. 그러나 최근에는 메모리의 가격이
많이 떨어지고 있어서 뛰어난 음성 품질을 보장할수 있는 PCM방식을 많이 사용하고 있다.
[ DM(Delta Modulation) 방식 ]
DM 방식은 제로 크로스 방식과 PCM 방식의 중간적인 형태로 볼 수 있다이 방식은 어느 시점n의 파고와 바로 전 시점 (n-1)의 파고를 비교하여
그 차이점을 1,0,-1로 표현한다. DM 방식의 단점은 원파형의 급격한 변화를 따라가지 못한다는 것이다. DM 방식의 하드웨어 구현은 바로 이전
값에 1 또는 -1을 더하기만 하면 되므로 아주 간단하다.
[ DPCM(Differencial PCM) 방식 ]
우리의 음성 파형을 실제로 보면, 서로 인접한 샘플링 시점의 비교에서파형이 크게 변하지 않는다. 이점에 착안하여 만든 방식이 DPCM 방식이
다. DPCM 방식은 개선된 PCM 방식이라 할 수 있다. 즉, PCM 방식은 파고 값을 그대로 저장하지만 DPCM 방식은 이전의 값과의 차이만을 저장
하는 것이다. 음성의 파형이 크게 변하지 않으므로 차이값도 작아져서 bit-rate를 낮출 수 있다.
[ ADPCM(Adaptive Differencial PCM) 방식 ]
ADPCM 방식은 위의 여러 가지 방식의 단점을 보완한 것이다. DM 방식이나 DPCM 방식은 압축된 비트수로 표현 되는 최대의 변화량이 실제 파형
의 변화량보다 작기 때문에 실제로 구현하면 재생 파형이 원 파형의 급격한 변화를 나타내지 못한다. 이를 막기 위하여 양자화할때 시간 간격
을 작게 하면 bit-rate를 증가시키는 결과를 가져오게 된다.ADPCM 방식은 파형의 변화량이 급격히 변할 때는 양자화 할 때의 단위를 크게하여
차분값을 이용하는 것으로 파형의 진폭이 클경우 약간의 잡음이 있어도 사람이 잘 감지하지 못하는 점을 이용한 것이다.
C++ 요약
DirectX 9.0 한글판
|
|
컨트롤
가. 컨트롤(control)이란 사용자와의 인터페이스를 이루는 도구 (사용자로부터 명령과 입력을 받아들이고
출력 결과를 보여준다, 즉 입출력 도구)
나. 프로그램은 실행중에 끊임없이 사용자와 통신을 하는데 컨트롤을 통해 명령과 정보를 받아들이고
또한 컨트롤을 통해 실행 결과를 사용자에게 보고한다.
다. 컨트롤도 하나의 윈도우이다. 화면상의 일정한 영역을 차지하며 자신의 고유 메시지를 처리할 수
있는 능력을 가지고 있으며 차일드 윈도우로 존재한다. 윈도우를 만들 때는 WNDCLASS형의 구조체를
정의하고 RegisterClass함수로 등록한 후 CreateWindow 함수를 호출한다. 그러나 컨트롤은 윈도우즈가
운영체제 차원에서 제공하기 때문에 윈도우 클래스를 등록할 필요없이 미리 등록되어 있는 윈도우 클래스를
사용하기만 하면 된다. 미리 정의된 윈도우 클래스에는 다음과 같은 종류가 있다
라. 윈도우 클래스의 종류
윈도우 클래스 | 컨트롤
----------------------------------
button | 버튼, 체크, 라디오
static | 텍스트
scrollbar | 스크롤바
edit | 에디트
listbox | 리스트 박스
combobox | 콤보 박스
마. 윈도우 클래스들은 시스템 부팅시에 운영체제에 의해 등록되므로 윈도우 클래스를 따로 등록할 필요없이
CreateWindow함수의 첫 번째 인수로 클래스 이름만 주면 해당 컨트롤을 만들수 있다.
2. button
가. CreateWindow(TEXT("button"), TEXT("Click Me"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
20, 20, 100, 25, hWnd, (HMENU)0, g_hInst, NULL);
== CreateWindow(만들고자 하는 윈도우의 클래스, 캡션, 스타일,
위치, x위치, y위치, 폭, 높이, 부모 윈도우, 핸들, 부모윈도우 인스턴스 핸들, 사용자정의데이터);
나. 스타일
스타일 설명
------------------------------------------------------------------------------
BS_PUSHBUTTON 푸시 버튼
BS_DEFPUSHBUTTON 디폴트 푸시 버튼
BS_CHECKBOX 체크 박스
BS_3STATE 3가지 상태를 가지는 체크 박스
BS_AUTOCHECKBOX 자동 체크 박스
BS_AUTO3STATE 3가지 상태를 가지는 자동 체크 박스
BS_RADIOBUTTON 라디오 버튼
BS_AUTORADIOBUTTON 자동 라디오 버튼
BS_GROUPBOX 그룹 박스
다. 부모와의 통신
1) 버튼을 클릭할 경우 WM_COMMAND 메시지를 부모 윈도우에게 보내며 이때 전달되는 정보는
인수 설명
--------------------------
HIWORD(wParam) 통지코드(왜 메시지를 보냈는가를 나타내는 값)
LOWORD(wParam) 컨트롤의 ID (아홉번째 인수)
lParam 메시지를 보낸 차일드 윈도우의 윈도우 핸들
2) 부모 윈도우는 WM_COMMAND에서 LOWORD(wParam)값을 조사하여 어떤 컨트롤이 눌러졌는지에
따라 적절한 처리를 한다. WM_COMMAND 메시지는 컨트롤의 통지 메시지뿐만 아니라 메뉴항목,
엑셀러레이터 등의 명령을 처리하는 중요한 일을 한다. 이름 그대로 버튼을 누르거나, 메뉴를 선택하거나
엑셀러레이터를 누르는 등 사용자로부터의 명령이 될 만한 것들을 모두 처리한다. 이때 컨트롤의 ID, 메뉴 ID
엑셀러레이터 ID등은 모두 LOWORD(WPARAM)으로 전달되므로 이 세가지 명령들끼리는 0~65535까지의
범위에서 상호 중복되지 않는 ID를 가져야한다.
가) 일반적인 메세지 처리 루틴
case WM_COMMAND:
switch( LOWORD(wParam) ) // ID에 따른 분기
case 메뉴 1: 처리 1; break;
case 메뉴 2: 처리 2; break;
case 엑셀러레이터 1: 처리 3; break;
case 컨트롤 1:
switch( HIWORD(wParam) ) // 통지 코드에 따른 분기
case 통지코드 1: 처리 1; break;
case 통지코드 2: 처리 2; break;
3. 체크 박스
가. 푸시 버튼은 사용자로부터 명령을 받아들이기 위해 사용하는데 비해 체크 박스는 참, 거짓의 진위적인
선택을 입력받을 때 주로 사용된다. 체크 박스도 푸시버튼과 마찬가지로 차일드 윈도우이며 스타일에
따라 4가지 종류의 체크박스가 있다. 우선 선택 가능한 옵션의 개수에 따라 두가지 상태를 가지는
체크박스와 세가지상태를 가지는 체크 박스로 구분된다. 또한 동작 방법에 따라 자동 체크 박스와
수동 체크 박스로 나누어지는데 수동 체크 박스는 선택/비선택 상태를 부모 윈도우가 직접 바꾸어야
하며 자동 체크 박스는 스스로 체크 상태를 바꾼다.자동 체크 박스는 별도의 코드를 작성하지 않아도
체크 상태를 자동으로 토글할 수 있는 장점이 있기는 하지만 체크 상태를 결정하기 위해 좀 더 복잡한
조건을 점검하기에는 어울리지 않는다.
나. 컨트롤의 메시지
1) 체크 박스는 사용자가 마우스로 클릭할 때마다 부모 윈도우로 BN_CLICKED 메시지를 보낸다. 컨트롤이
부모 윈도우로 보내는 통지 메시지와는 달리 부모 윈도우가 체크 박스의 상태를 알아보거나 상태를
바꾸고자 할 때도 차일드 윈도우로 메시지를 보낸다. 통지 메시지는 차일드가 부모로 보내는 보고 메시지이고
그냥 메시지는 부모가 차일드에게 어떤 지시를 내리기 위해 보내는 명령이다. 메시지의 종류는 컨트롤마다
다르다.
메시지 설명
-----------------------------------
BM_GETCHECK 체크 박스가 현재 체크되어 있는 상태를 조사하며 wParam, lParam은 사용하지 않는다.
체크 상태는 리턴값으로 돌려진다.
BM_SETCHECK 체크 박스의 체크 상태를 변경하며 wParam에 변경할 체크 상태를 지정한다.
BM_GETCHECK에 의해 리턴되는 값, BM_SETCHECK에 의해 설정되는 체크박스의 상태
상수 값 의미
BM_UNCHECKED 0 현재 체크되어 있지 않다.
BM_CHECKED 0 현재 체크되어 않다.
BM_INDETERMINATE 0 체크도 아니고 안 체크도 아닌 상태
<------ BN_CLICKED : 클릭되었음 -------------
부모 윈도우 ------ BM_GETCHECK : 체크 상태 질문 -------> 체크 박스
------ BM_SETCHECK : 체크 상태 변경 ------->
4. 라디오 버튼
가. BS_RADIOBUTTON, BS_AUTORADIOBUTTON 둘 중 하나의 스타일을 지정하면 라디오 버튼이 되며
체크 박스와 마찬가지로 수동, 자동의 두가지 종류가 있으며 라디오 버튼이 체크 상태를 스스로 변경
하는 그렇지 않은가의 차이가 있다. 수동 라디오 버튼이 필요한 상황은 사실상 거의 없으며 대개의
경우는 자동 라디오 버튼으로 충분하다. 하나의 선택 사항에 대해 여러 개의 라디오 버튼들이
그룹을 이루어 사용된다는 특징이 있다. 같은 그룹에 속한 라디오 버튼은 오직 하나만 선택 가능
나. 라디오 버튼의 그룹을 구성하는 방법은 간단하다. 그룹을 이루는 첫 번째 라디오 버튼에만 WS_GROUP
스타일을 주고 나머지 라디오 버튼은 WS_GROUP 스타일을 주지 않으면 된다. 최초로 WS_GROUP을 가지는
라디오 버튼부터 다음 WS_GROUP 스타일을 가지는 라디오 버튼 직전까지가 한 그룹이 된다.
5. 에디트
가. EDIT 윈도우 클래스로부터 생성하며 CREATEWINDOW 함수로 스타일 인수로 지정하면 된다.
부모 윈도우는 이 메시지를 받았을 때 적절한 처리를 하면 된다.EN_CHANGE 문자열이 변경되었다.
EN_KILLFOCUS, EN_SETFOCUS 포커스를 잃고 얻었을 때의 메시지가 있다.
나. 컨트롤도 윈도우와 동격이다. 일단 화면상의 사각영역을 차지한다는 점에 있어서 윈도우와 같은데
메인 윈도우의 차일드로 존재하며 타이틀 바가 없기 때문에 사용자가 직접 이동시킬 수 없을 뿐이다.
또한 윈도우처럼 스타일을 가지며 만들 때 지정한 스타일에 따라 모양이나 기능이 달라진다.
컨트롤이 윈도우라느 결정적인 증거는 스스로 메시지를 처리할 수 있는 능력을 가진다는 점이다.
버틍을 마우스로 누르면 쑥 들어가는 모양으로 바뀌고 에디트는 키보드 입력을 받으면 문자열을 조립하여
보여준다. eH한 WM_PAINT 메시지를 처리하기 때문에 스스로 자신을 복구(REPAIR)할 수 있고 부모윈도우가
메시지를 보내면 그 메시지를 처리한다. 체크 박스는 BM_SETCHECK 메시지를 받으면 WPARAM값에 따라
자신의 체크 상태를 스스로 변경한다.
6. 리스트 박스
가. 리스트 박스는 선택 가능한 여러 개의 항목들을 나열해 놓고 그 중 하나(또는 여러개)를 선택하는 컨트롤
이며 여기서 항목이란 주로 문자열이다. 리스트 박스도 일종의 윈도우이며 "listbox"라는 윈도우 클래스로
생성한다. 차일드 컨트롤로 생성하는 것이 보통이므로 WS_CHILD|WS_VISIBLE 스타일은 기본적으로 지정
해야 하며 이 외에 다음과 같은 여러 가지 고유의 스타일을 지정할 수 있다. 어떤 스타일을 지정하는가에
따라 리스트박스와 모양과 동작이 달라진다.
스타일 설명
LBS_MULIPLESEL 여러개의 항목을 선택 가능, 적용하지 않으면 디폴트로 하나의 선택만 가능
LBS_NOTIFY 사용자가 목록중 하나를 선택했을 때 부모 윈도우로 통지 메시지를 보낸다.
LBS_SORT 추가된 항목들을 자동 정렬한다.
LBS_OWNERDRAW 문자열이 아닌 비트맵이나 그림을 넣을 수 있다..
LBS_STANDARD LBS_NOTIFY|LBS_SORT|WS_BORDER
나. 부모 윈도우로 통지 메시지를 보내는 것이 일반적이르모 LBS_NOTIFY 스타일은 거의 필수적으로 선택
하는 것이 좋으며 그 외는 필요할 때 선택하면 된다. 부모 윈도우가 리스트 박스를 조작하고자 할때는
리스트 박스 메시지를 사용한다.
메시지 설명
LB_ADDSTRING 리스트 박스에 항목을 추가 LPARAM으로 추가하고자 하는 문자열의 번지를 넘겨줌
LB_DELETESTRING 항목을 삭제, WPARAM으로 항목의 번호를 넘겨주면 남은 항목수를 리턴
LB_GETCURSEL 현재 선택된 항목의 번호를 조사
LB_GETTEXT 지정한 항목의 문자열을 읽는다. WPARAM에 항목번호, LPARAM에 문자열
LB_GETCOUNT 항목의 개수를 조사한다.
LB_SETCURSEL WPARAM이 지정한 항목을 선택한다
다. 리스트 박스에서 어떤 사건이 발생했을 때 부모 윈도우로 다음과 같은 통지 메시지를 보낸다.
메시지 설명
LBN_DBLCLK 리스트 박스를 더블 클릭하였다.
LBN_ERRSPACE 메모리가 부족하다
LBN_KILLFOCUS 키보드 포커스를 잃었다.
LBN_SELCANCEL 사용자가 선택을 취소하였다
LBN_SELCHANGE 사용자에 의해 선택이 변경되었다.
LBN_SETFOCUS 키보드 포커스를 얻었다.
자주 사용되는 통지 메시지는 선택이 변경될 때 보내지는 LBN_SELCHANGE이다
7. 콤보 박스
가. 에디트컨트롤과 리스트 박스를 결합이다. 그래서 목록에 있는 항목중의 하나를 선택할 수도 있고 원하는
항목이 없을 경우 에디트에 직접 입력해 넣을 수도 있다. combobox 윈도우 클래스를 사용하며 세 가지
종류가 있는데 스타일로 원하는 종류를 선택
스타일 설명
CBS_SIMPLE 에디트와 리스트 박스를 가지되 리스트 박스가 항상 펼쳐져 있다.
CBS_DROPDOWN 에디트와 리스트 박스를 가진다.
CBS_DROPDOWNLIST 리스트 박스만 가지며 에디트에 항목을 입력할 수는 없다.
8. 스크롤 바
가. 비교적 복잡한 컨트롤로 윈도우의 스크롤 상태를 고나리하기 위해 사용하기도 하며 일정 범위에 있는 값을
대충 선택할 때도 사용한다. scrollbar 위노우 클래스로 생성하며 수평 스크롤 바일경우 SBS_HORZ 스타일을
수직 스크롤 일때는 SBS_VERT 스타일을 지정한다.
BOOL SetScrollRange(HWND hWnd, int nBar, int nMinPos, int nMaxPos, BOOL bRedraw);
(스크롤 바 윈도우 핸들, 표준 또는 별도 스크롤바를 지정하는 값, 최대값, 최소값, ?)
int SetScrollPos(HWND hWnd, int nBar, int nPos, BOOL bRedraw);
(?, ?, 현재 위치, ?);
나. 다른 컨트롤은 WM_COMMAND로 통지메시지를 보내는데 스크롤 바는 WM_HSCROLL, WM_VSCROLL
이라는 별도의 메시지를 부모 윈도우로 보낸다.
인수 설명
LOWORD(WPARAM) 스크롤 바 내의 어디를 눌렀는가?
HIWORD(WPARAM) 현재 위치
LPARAM 스크롤 바의 윈도우 핸들
다. LOWORD(WPARAM)으로 전달되는 값은 사용자의 스크로로 요구사항을 나타냄
값 설명
SB_LINELEFT, SB_LINEUP 사용자가 왼쪽 화살표를 눌렀음
SB_LINERIGHT, SB_LINEDOWN 사용자가 오른쪽 화살표를 눌렀음
SB_PAGELEFT, SB_PAGEUP 사용자가 왼쪽 몸통을 눌렀음
SB_PAGERIGHT, SB_PAGEDOWN 사용자가 오른쪽 몸통을 눌렀음
SB_THUMBPOSITION 스크롤 박스를 드래그한 후 마우스 버튼을 놓았다.
SB_THUMBTRACK 스크롤 박스를 드래그하고 있는 중 마우스버튼 놓을때까지 계속 전달
9. 스태틱
가. 입력은 없고 오로지 문자열만 보여줌 WM_CREATE에서 스태틱 컨트롤을 만들기만 할 뿐 그외의 코드는
작성할 필요가 없다. 스태틱 컨트롤은 실행중에 부모 윈도우로 통지 메시지를 보낼 필요가 없기 때문에 ID를
-1로 지정하며 여러개의 스태틱 컨트롤이 있을 모든 경우도 -1의 같은 ID를 사용해도 된다. -1은 ID를 주지
않는다는 뜻이며 더 이상 컨트롤을 프로그래밍할 필요가 없을 때 사용된다. 물론 필요하면 줄수도 있다.
나. TextOut으로 출력한 문자열과는 달리 스태틱 컨트롤은 스스로 메시지를 처리할 수 있는 윈도우이기 때문에
배치해 놓기만 하면 WM_PAINT와 같은 통지 메시지로 복구할 필요가 없다. 또한 색상, 글꼴 크기 등
운영체제의 세팅이 바뀔 경우 이런 변화에 대해서도 스스로 대처한다는 장점이 있다.
C/C++ 프리프로세서 명령
C++ 프리프로세서 명령
16.1 서론
16.2 C++ 프리프로세서
16.3 파일의 include
16.4 단순한 문자열 치환
16.5 인수 없는 매크로
16.6 인수 있는 매크로
16.7 매크로 정의 해체
16.8 조건 컴파일러
16.9 #pragma
16.10 정리
◈ 16.2 C++프리프로세서
-C++프리프로세서 명령의 규칙은 C와 동일
-프리프로세서는 컴파일러에 넘겨주시 전에 프로그램의 소스 코드를 처리하는 프로그램이다.
-프리프로세서 명령은 기호 #이 앞에 놓여지고 프리프로세서 제어행이라고 부름.
-제어행의 내용에 따라 하나 또는 그 이상의 기능을 실행함.
■파일의 include
-다음이 있으면 파일이 include됨
|
|
|
|
#include |
| ||
|
|
■문자열의 치환, 매크로 전개나 정의해제
-문자열의 치환, 매크로 전개나 정의해제 기능은, 다음의 명령으로 구현됨
|
|
|
|
#define #undef |
| ||
|
|
■조건 컴파일의 명령
-조건 컴파일은, 다음의 제어행을 조합해서 구현됨
|
|
|
|
#if #else #endif #if #elif #endif #ifdef #endif #ifndef #endif |
| ||
|
|
■디버그 작업의 보조
-다음의 제어행은 디버그를 지원함.
|
|
|
|
#pragma |
| ||
|
|
◈ 16.3 파일의 include(1)
|
|
|
|
// test16_1.cpp//오류발생 //#include <iostream.h> //#include <stdio.h> void main(void) { cout <<"Hi there ! \n"; printf ( "Hi there again ! \n"); } |
| ||
|
|
-오류 매시지
|
|
|
|
error C2065: 'cout' : undeclared identifier error C2297: '<<' : illegal, right operand has type 'char [13]' error C2065: 'printf' : undeclared identifier |
| ||
|
|
◈ 16.3 파일의 include(2)
|
|
|
|
// test16_2.cpp #include <iostream.h> #include <stdio.h> void main(void) { cout <<"Hi there ! \n"; printf ( "Hi there again ! \n"); } |
| ||
|
|
-실행 결과
|
|
|
|
Hi there ! Hi there again ! |
| ||
|
|
-#include 명령은 컴파일 시에 명령 뒤에 있는 파일명의 모든 내용을 include함.
-헤더 파일 iostream.h는 cout의 정의를, stdio.h는 printf()의 정의를 포함
-#include 명령의 3가지 형식
■#include <filename>
∙<>괄호 안의 파일명은 컴파일러에게 현재의 작업 디렉토리 이외의 미리 준비된 디렉토리(표준 디렉토리)의 리스트로부터 그 파일을 찾도록 지시
■#include “filename”
∙컴파일러에게 현재의 작업 디렉토리 내에서 그 파일을 찾도록 지시
■#include “c:\wkspace\kdhong\"filename”
∙컴파일러에게 지정된 경로 내에서 그 파일을 찾도록 지시, 그 디렉토리에서 발견되지 않으면 표준 디렉토리를 찾음.
|
|
|
|
// test_16.3 cpp #include <iostream.h> // cout 에 필요 #include <stdio.h> // printf()에 필요 #include "D:\Lecture2K-2\C++\nykwak.h" void main(void) { cout <<"Hi there ! \n"; printf ( "Hi there again ! \n"); cout <<"a from nykwak.h is " <<a <<"\n"; } |
| ||
|
|
-가령, D:\Lecture2K-2\C++\nykwak.h에 int a = 5;라는 선언문이 삽입되어 있을 경우, 실행 결과는, 다음과 같다.
|
|
|
|
Hi there ! Hi there again ! a from nykwak.h is 5 |
| ||
|
|
◈ 16.3 파일의 include(3)
|
|
|
|
// test_16.4 cpp//오류발생 #include <iostream.h> // cout 에 필요 #include <stdio.h> // printf()에 필요 #include "D:\Lecture2K-2\C++\kdhong.h" void main(void) { cout <<"Hi there ! \n"; printf ( "Hi there again ! \n"); cout <<"a from kdhong.h is " <<a <<"\n"; } |
| ||
|
|
-가령, D:\Lecture2K-2\C++\kdhong.h에
int a = 5
라는 선언문이 삽입되어 있을 경우, 메러 메시지는, 다음과 같다.
|
|
|
|
error C2144: syntax error : missing ';' before type 'void' fatal error C1004: unexpected end of file found |
| ||
|
|
◈ 16.4 단순한 문자열 치환
-일반적으로, #define 제어행을 사용할 때, 대문자를 사용.(그 이유는 프로그램 중에서 #define되는 변수를 쉽게 확인할 수 있기 때문.)
|
|
|
|
// test16_5.cpp//문자열 치환 #include <iostream.h> #define HELLO "Hi there ! \n" void main(void) { cout <<HELLO ; } |
| ||
|
|
-실행 결과
|
|
|
|
Hi there ! |
| ||
|
|
◈ 16.5 인수 없는 매크로
|
|
|
|
// test16_6.cpp//인수 없는 매크로 #include <iostream.h> // I/O에 필요 #define SQUARE_TWO 2*2 void main(void) { int a; a = SQUARE_TWO; cout <<"a is " <<a <<"\n"; } |
| ||
|
|
-실행 결과
|
|
|
|
a is 4 |
| ||
|
|
-다음 제어행 중,
|
|
|
|
#define SQUARE_TWO 2*2 |
| ||
|
|
#define는 제어행으로, SQUARE_TWO는 매크로 템플리트이고, 2*2는 매크로 전개임.
◈ 16.6 인수 있는 매크로(1)
|
|
|
|
//test16_7.cpp #include <iostream.h> #define ADD(X) (X+X) void main(void) { int b; b = ADD(4); cout <<"b is " <<b <<"\n"; } |
| ||
|
|
-실행 결과
|
|
|
|
b is 8 |
| ||
|
|
◈ 16.6 인수 있는 매크로(2)
|
|
|
|
//test16_8.cpp//오류발생 #include <iostream.h> #define ADD (X) (X+X) void main(void) { int b; b = ADD(4); cout <<"b is " <<b <<"\n"; } |
| ||
|
|
-오류 메시지
|
|
|
|
error C2065: 'X' : undeclared identifier |
| ||
|
|
◈ 16.6 인수 있는 매크로(3)
|
|
|
|
//test16_9.cpp//오류발생 #include <iostream.h> //매크로명과 파라미터 사이의 괄호가 없는 것에 주의 #define ADD(X) X+X void main(void) { int b; b = ADD(4)*5; cout <<"b is " <<b <<"\n"; } |
| ||
|
|
-실행 결과
|
|
|
|
b is 24 |
| ||
|
|
-test16_9.cpp의 동작 설명
|
|
|
|
b = ADD(4)*5; |
| ||
|
|
|
|
|
|
b = 4 + 4 * 5; |
| ||
|
|
즉, 곱셈은 덧셈보다 연산우선순위가 빠르기 때문에 다음과 같이 계산됨
|
|
|
|
b = 4 + (4 * 5); |
| ||
|
|
그러나, 기대했던 것은 다음과 같은 것임.
|
|
|
|
b = (4 + 4) * 5; |
| ||
|
|
(따라서, 괄호를 생략해서는 안됨)
◈ 16.7 매크로 정의 해제
-이미 정의된 (#define) 매크로는 다음과 같은 제어행으로 정의를 해제할 수 있음.
|
|
|
|
#undef |
| ||
|
|
|
|
|
|
// test16_10.cpp//오류발생 #include <iostream.h> #define FOUR 4 void main(void) { int a = FOUR; cout <<"a is " <<a <<"\n"; #undef FOUR int b = FOUR; cout <<"b is " <<b <<"\n"; } |
| ||
|
|
-오류 메시지
|
|
|
|
error C2065: 'FOUR' : undeclared identifier |
| ||
|
|
-메크로를 해제하는 이유는, 매크로 명을 필요로 하는 코드 부분만으로 유효 범위를 한정하기 위함.
◈ 16.8 조건 컴파일러
-조건 컴파일러는 소스 코드 중의 다음 키워드가 발견되면 수행됨.
|
|
|
|
#if - #else - #endif #if - #elif - #endif #ifdef - #endif #ifndef - #endif |
| ||
|
|
16.8.1 #if - #else - #endif(1)
-키워드 #if에는 상수식, 코드블록이 이어지고, 그 뒤에 키워드 #endif가 놓여짐.
|
|
|
|
// test16_11a .cpp #include <iostream.h> // I/O 에 필요 #define FIVE 5 #define ZERO 0 void main(void) {
#if (FIVE) cout <<"FIVE is TRUE, i.e. non-zero \n"; #else cout <<"FIVE is FALSE, i.e. zero \n"; #endif #if (ZERO) cout <<"ZERO is TRUE, i.e. non-zero \n"; #else cout <<"ZERO is FALSE, i.e. zero \n"; #endif cout <<"This code is outside the blocks \n"; } |
| ||
|
|
-실행 결과
|
|
|
|
FIVE is TRUE, i.e. non-zero ZERO is FALSE, i.e. zero This code is outside the blocks |
| ||
|
|
16.8.1 #if - #else - #endif(2)
|
|
|
|
// test16_11.cpp//MS Visual C++의 경우, 실행되지만 오동작 #include <iostream.h> void main(void) { const int a = 5; const int b = 0; #if (a) cout <<"a is TRUE, i.e. non-zero \n"; #else cout <<"a is FALSE, i.e. zero \n"; #endif #if (b) cout <<"b is TRUE, i.e. non-zero \n"; #else cout <<"b is FALSE, i.e. zero \n"; #endif
cout <<"This code is outside the blocks \n"; } |
| ||
|
|
-실행 결과
|
|
|
|
a is FALSE, i.e. zero b is FALSE, i.e. zero This code is outside the blocks |
| ||
|
|
16.8.1 #if - #else - #endif(3)
|
|
|
|
// test16_12.cpp//MS Visual C++의 경우, 실행되지만 오동작 #include <iostream.h> void main(void) { int a = 5;//a와 b는 변수로서 선언되고 있다. int b = 0; #if (a) cout <<"a is TRUE, i.e. non-zero \n"; #else cout <<"a is FALSE, i.e. zero \n"; #endif #if (b) cout <<"b is TRUE, i.e. non-zero \n"; #else cout <<"b is FALSE, i.e. zero \n"; #endif
cout <<"This code is outside the blocks \n"; } |
| ||
|
|
-실행 결과
|
|
|
|
a is FALSE, i.e. zero b is FALSE, i.e. zero This code is outside the blocks |
| ||
|
|
16.8.1 #if - #else - #endif(4)
#if-#else-#endif와 정규 if-else-endif 제어 구조의 차이는, 전자에서는 case 평가를 프로그램이 컴파일되기 이전에 한다는 점이다. 테스트 조건 안에 변수를 두어서는 안된다. 왜냐하면, 변수의 값은 실행중에 변할 수도 있기 때문.
16.8.2 #if - #elif - #endif
#if-#elif-#endif는 #if-#else-#endif와 유사
|
|
|
|
// test16_11b.cpp #include <iostream.h> // I/O 에 필요 #define FIVE 5 #define ZERO 0 void main(void) {
#if (FIVE) cout <<"FIVE is TRUE, i.e. non-zero \n"; #elif cout <<"FIVE is FALSE, i.e. zero \n"; #endif #if (ZERO) cout <<"ZERO is TRUE, i.e. non-zero \n"; #elif(ZERO) cout <<"ZERO is FALSE, i.e. zero \n"; #endif
cout <<"This code is outside the blocks \n"; } |
| ||
|
|
-실행 결과
|
|
|
|
FIVE is TRUE, i.e. non-zero This code is outside the blocks |
| ||
|
|
16.8.3 #ifdef-#endif
-2개의 제어행 사이의 코드 블록은, 명령의 뒤에 있는 매크로명이 그 앞에 정의되어 있을 때에만 컴파일됨.
|
|
|
|
// test16_14.cpp #include <iostream.h> //#define COMPILE void main(void) { #ifdef COMPILE cout <<"This code will be compiled \n"; #endif } |
| ||
|
|
-실행 결과
|
|
|
|
|
| ||
|
|
16.8.4 #ifndef-#endif
-#indef-#endif문의 반대로, 제어행 사이 코드블록은, 매크로 명이 정의되어 있지 않을 때만 컴파일됨.
|
|
|
|
// test16_14.cpp #include <iostream.h> #define COMPILE void main(void) { #ifndef COMPILE cout <<"This code will be compiled \n"; #endif } |
| ||
|
|
-실행 결과
|
|
|
|
|
| ||
|
|
◈ 16.#pragma
-이 제어행은 컴파일러에 여러 가지 지령을 줄 수 있다. 특수한 지령은 처리계의 독자적인 지령이다.
MSDNdpt의 progma에 대한 설명
Each implementation of C and C++ supports some features unique to its host machine or operating system. Some programs, for instance, need to exercise precise control over the memory areas where data is placed or to control the way certain functions receive parameters. The #pragma directives offer a way for each compiler to offer machine- and operating-system-specific features while retaining overall compatibility with the C and C++ languages. Pragmas are machine- or operating-system-specific by definition, and are usually different for every compiler.
Syntax
#pragma token-string
The token-string is a series of characters that gives a specific compiler instruction and arguments, if any. The number sign (#) must be the first non-white-space character on the line containing the pragma; white-space characters can separate the number sign and the word pragma. Following #pragma, write any text that the translator can parse as preprocessing tokens. The argument to #pragma is subject to macro expansion.
If the compiler finds a pragma it does not recognize, it issues a warning, but compilation continues.
Pragmas can be used in conditional statements, to provide new preprocessor functionality, or to provide implementation-defined information to the compiler. The C and C++ compilers recognize the following pragmas:
alloc_text comment init_seg1 optimize
auto_inline component inline_depth pack
bss_seg data_seg inline_recursion pointers_to_members1
check_stack function intrinsic setlocale
code_seg hdrstop message vtordisp1
const_seg include_alias once warning
calculator
그래픽
GDI 오브젝트는 GDI가 그래픽 출력을 위해 사용하는 도구임과 동시에 사용자가 GDI의 출력을 조장할 수
이쓴 도구이기도 하다. 원하는 색상과 모양의 모브젝트를 만들고 DC에 선택해 놓으면 이후부터 선택된
오브젝트의 속성대로 출력
2. GDI 오브젝트를 만들 때 핸들을 발급받으며 선택하거나 삭제할 때는 이 핸들만 가지고 GDI 오브젝트를
사용 DC가 BeginPaint나 GetDC 함수에 의해 처음 만들어 졌을 때 디폴트로 선택된 GDI 오브젝트는
아래와 같음
GDI 오브젝트 핸들타입 설명 디폴트
펜 HPEN 선을 그을 때 사용 검정색의 가는 실선
브러시 HBRUSH 면을 채울때 사용 흰색
폰트 HFONT 문자 출력에 사용되는 글꼴 시스템 글꼴
비트맵 HBITMAP 비트맵 이미지 선택되지 않음
팔레트 HPALLETTE팔레트 선택되지 않음
리전 HRGN 화면상의 영역 선택되지 않음
3. Stock Object
가. 윈도우가 기본적으로 제공하는 GDI 오브젝트
나. 운영체제가 부팅할 때부터 미리 만들어 놓아 일부러 만들지 않아도 언제든지 사용가능 하며
사용한 후 파괴할 필요도 없음
1) HGDIOBJ GetStockObject(int fnObject); 주로 브러시와 펜이 스톡 오브젝트로 제공됨
함수는 여러 종류의 스톡 오브젝트를 리턴하므로 대입하기 전에 원하는 타입으로 캐스팅
2) HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj); 이전에 쓰던 오브젝트를 리턴
4. 색상
RGB 매크로 함수를 사용하여 색상값을 만듬
typedef DWORD COLORREF;
#define RGB(r, g, b)
((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b)<<16)))
5. PEN
가. 기본 스톡 펜은 흰색, 검정색, 투명색 세 가지 뿐이며 원색 펜은 직접 만들어서 사용
HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor);
(선의 모양, 선의 폭, 선의 색상) 펜의 핸들을 리턴 리턴후에는 반드시 파괴
BOOL DeleteObject(HGDIOBJ hObject); GDI 오브젝트를 삭제할 때 사용
6. BRUSH
가. 기본 스톡 브러시는 단색 브러시가 있음, 만드는 건 PEN과 동일
HBRUSH CreateSolidBrush(COLORREF crColor); 단색의 브러시 제작
HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref); 무늬와 색상을 지정할수 있음
7. Old의 의미
가. GDI 오브젝트를 생성하고 파괴하지 않으면 안됨
나. GDI 오브젝트를 저장하는 리소스 영역은 메인 메모리와는 다른 특수한 영역으로 이 영역의 크기가
그리 크지 못해 오브젝트를 많이 만들면 금방 가득차 버림
다. DC에 선택되어 있는 오브젝트는 삭제할 수 없기 때문에 Old라는 GDI 오브젝트를 사용하여
사용중인 오브젝트를 Old라는 오브젝트로 교체후 삭제함
라. 코드의 범용성을 위해서는 항상 Old 오브젝트를 사용하여 DC를 원래대로 돌려놓는 습관을
가지는 것이 좋음
8. 투명 오브젝트
스톡 오브젝트에는 투명색의 오브젝트가 존재함
9. 그리기 모드
가. 윈도우즈에서 사용하는 디폴트 그리기 모드는 R2_COPYPEN 모드라서 그려지는 그림이
기존 그림을 덮어버림
1) int SetROP2(HDC hdc, int fnDrawMode);
int GetROP2(HDC hdc);
나. 마우스를 따라 선을 이동시킬 때 이미 그려진 그림을 보존해야 하므로 그리는 중의 선을 반점 모드로
그려 이 선이 지워질 때 원래대로 복구해 놓고 가야하는 것이다. 그러기 위해서느 절대 색상으로 삭제,
그리기 해서는 안되면 이미 그려진 그림과 논리 연산을 취하는 다른 방법을 사용해야 한다. R2_NOT는
이런 작업이 가능한 그리기 모드의 한 예인데 흑백 환경에서는 이 모드가 가장 편리하며 컬러 환경에는
R2_NOTXORPEN이 가장 완벽함
10. BITMAP
비트맵은 대용량이라 직접 출력하는 함수는 제공하지 않으며 약간의 준비를 거친 후 출력해야 한다.
이렇게 준비 동작을 취한 후 출력하면 여러번 출력할 때 이미 준비된 데이터를 전송하기만 하면
출력 속도도 빠르고 예비동작을 미리 취해 놓을 수 있다는 점에서도 유리하다. 비트맵은 화면으로
직접 출력할 수 없으며 반드시 메모리 DC에 미리 준비해 놓고 사용해야 한다
가. 메모리 DC란 화면 DC와 동일한 특성을 가지며 그 내부에 출력 표면을 가진 메모리 영역이다.
메모리에 있기는 하지만 화면 DC에서 사용할 수 있는 모든 출력을 메모리 DC 에서도 할 수 있다.
나. HDC CreateCompatibleDC(HDC hdc);
화면 DC의 핸들을 주면 화면 DC와 동일한 특성을 가지는 DC를 메모리에 만들어 핸들을 리턴
다. HBITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName);
(비트맵 리소스를 가진 인스턴스의 핸들, 비트맵 리소스의 이름)
라. BOOL BitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc,
int nXSrc, int nYSrc, DWORD dwRop);
(복사 대상 DC, X좌표, Y좌표, 폭, 높이, 복사원 DC, 복사원X좌표, 복사원 Y좌표, 래스터 연산방법)
마. BOOL StretchBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, DWORD dwRop);
확대, 축소가 가능
11. FONT
HFONT CreateFont(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight,
DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet,
DWORD FdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality,
DWORD fdwPitchAndFamily, LPCTSTR lpszFace);
(폰트의 높이, 폰트의 폭, 폰트의 각도, 개별문자 기울기, 폰트의 두께, 폰트 속성, 문자셋,
출력 정확도, 클리핑 정확도, 논리적 폰트를 물리적 폰트와 얼마나 근접시킬 것인가 지정,
폰트의 피치와 그룹을 설정, 글꼴의 이름)
가. LOGFONT 구조체를 사용하여 폰트를 정의하고 CreateFontIndirect 함수로 폰트를 만드는 방법
LOGFONT 구조체는 CreateFont 함수의 인수 전체를 멤버로 가지는 구조체로 LOGFONT에
원하는 값을 먼저 대입한 후 CreateFontIndirect 함수로 이 구조체의 번지를 넘기면 됨
HFONT CreateFontIndirect(CONST LOGFONT * lplf);
나. 텍스트의 색상
COLORREF SetTextColor(HDC hdc, COLORREF crColor); 글자 색상
COLORREF SetBkColor(HDC hdc, COLORREF crColor); 글자 배경색상
int SetBkMode(HDC hdc, int iBkMode); 글자배경색상 모드(투명, 불투명) 기본은 불투명
리소스
가. 분담 작업으로 전문성을 높임, 개발과 디자인을 동시에 수행함으로써 전체적인 개발 기간 단축효과
나. 재사용에 유리
다. 모듈 분할 컴파일 방식의 장점과 같이 매번 컴파일할 필요가 없음
라. 실행중에 교체가 가능한 모듈임
2. 리소스 편집기들은 리소스 ID에 겹따옴표없이 IDR_MENU1 식으로 이름을 지정하면 이 이름을
resource.h에 정수형의 매크로로 정의하고 사용되지 않은 정수를 배정한다. 정수 타입의 리소스 ID를
문자열 포인터에 대입할 수 없으므로 적당히 캐스팅해야 하는데 이 캐스팅을 대신하는 매크로가
MAKEINTRESOURCE 이다
( #define MAKEINTRESOURCE(i) (LPSTR)((DWORD)((WORD)(i))) )
3. WM_COMMAND
가. 메뉴 항목을 선택하면 WM_COMMAND 메시지가 발생
나. 어떤 메뉴 항목이 선택되었는가는 WPARAM의 하위 워드로 전달되므로 LOWORD(WPARAM)을 읽어
판단
다. WndProc에서는 WM_COMMAND 메시지를 받을 경우 switch 문으로 다시 LOWORD(WPARAM)의
값에 따라 분기를 하여 각 메뉴 항목에 따른 처리를 수행
4. Accelerator
가. 설정 기능을 곧바로 실행하는 키보드 조합키
나. HACCEL LoadAccelerators(HINSTANCE hInstance, LPCTSTR lpTableName);
리소스로부터 엑셀러레이터 테이블을 읽어들이며 그 핸들을 리턴
다. int TranslateAccelerator(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg);
키보드 메시지를 WM_COMMAND 메시지로 변경하여 액셀러레이터가 동작할 수 있도록 함
5. 문자열 테이블
가. 대량의 문자열을 사용하는 프로그램은 리소스에 문자열을 정의해 놓고 필요할 때마다
리소스의 문자열을 읽어와 사용(최대 4K까지의 길이를 가질 수 있음)
나. int LoadString(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax);
hInstance가 정의하고 있는 uID 문자열을 길이 nBuffexMax의 lpBuffer 문자 배열로 읽어오라는 뜻)
다. 장점
1) 문자열 자체가 코드와 분리됨으로써 문자열만 따로 관리할 수 있으며 프로젝ㅌ를 유지하는데 도움
2) 많은 문자열을 다루는 대형 프로젝트에는 메시지만을 전문적으로 관리하는 사람이 따로 있어
문체의 일관성 확보와 메시지의 내용을 정확하게 할 수 있으며 수정하기도 편리
3) 다국어 버전을 쉽게 만들 수 있으며 문자열을 고쳐도 소스를 다시 컴파일 할 필요가 없어
개발 속도가 빨라진다.
ORACLE DATA TYPE
ORACLE DATA TYPE
API Control
CreateWindows(Text("button"), .............. );
첫번째 인수는 Button 생성시 이름이 고정되어 있음