'1.소프트웨어 이야기 > 04.Apple' 카테고리의 다른 글
애플에 자신이 등록한 제품 정보를 알고 싶을때.. (0) | 2010.10.21 |
---|---|
Object-C 학습자료 (0) | 2009.12.24 |
Apple 개발 관련 문서 링크 (0) | 2009.11.26 |
애플에 자신이 등록한 제품 정보를 알고 싶을때.. (0) | 2010.10.21 |
---|---|
Object-C 학습자료 (0) | 2009.12.24 |
Apple 개발 관련 문서 링크 (0) | 2009.11.26 |
0. 시작하기에 앞서
병렬처리 프로그래밍을 위한 기법중 OpenMP를 이용하는 방법에 대해서 보도록 할 것이다.
불과 10여년 전만 하더라도 병렬 처리를 위한 프로그래밍은 사치에 가까웠고 CPU를 여러 개 장착한 PC는 보기 힘들었다. 하지만 최근 CPU의 발달은 Hz 속도를 거의 한계에 다다르게 하였다:현재 한계는 약 3GHz 전후이다. 물론 이론상으로는 5GHz도 가능하지만 엄청난 발열과 전력 소비로 인해서 효과적이지 못하다. 그리하여 CPU 벤더들은 Hz속도의 경쟁보다는 복수개의 코어로 진화할 수 밖에 없게 되었다.
그러나 기존 프로그램은 멀티 코어를 지원하도록 작성된 경우가 거의 없기에 심각한 문제로 대두되기 시작했다. 앞으로의 추세는 병렬 처리를 위한 멀티 쓰레드 프로그래밍이지만 이 분야가 결코 쉽지 않다는 점이 발목을 잡는다. 일반적인 native multi-thread programming은 고급 레벨이 아니고서는 작성하기 힘들어서 해당 분야 전공자가 아닌 응용 프로그래머는 손대기가 힘들었다. 예를 들어 물리나 수학, 화학에서 C, C++, fotran을 이용한 수치계산을 한다고 가정해보자. 연구중인 앨거리즘이나 휴리스틱 기법을 테스트하려고 하는데 더 빠른 계산을 위해서 고급 멀티 쓰레드 프로그래밍을 배우려고 한다면 얼마나 걸릴 것인가? 물론 천재적인 사람이라면 금방 가능하겠지만 일반적으로는 프로그래밍 배우는데 몇개월에서 반 년이상을 투자해야 제대로 할 수 있을 것이다 그러나 이는 배보다 배꼽이 더 큰 문제가 되어버린다.
따라서 간단한 멀티 쓰레드 프로그래밍을 구현하기 위한 좀 더 쉬운 adaptive multi-thread programming 기법으로 OpenMP가 나오게 되었다. OpenMP는 뛰어난 프로그래밍 실력을 아니더라도 단 몇일만 투자해도 쉽게 멀티 쓰레드 프로그래밍을 할 수 있게 도와 준다.
#pragma omp parallel [clause[ [, ]clause] ...] new-line
structured-block
# include <stdio.h>
int main()
{
printf("Hello world\n");
return 0;
}
여기에 OpenMP 지시어를 추가하여 멀티 쓰레드 프로그램으로 바꾸면 아래처럼 작성된다.
# include <stdio.h>
int main()
{
#pragma omp parallel
{
printf("Hello world\n");
}
return 0;
}
실제로 엄청 간단하지 않은가? 그러면 컴파일 해보자. $ gcc -fopenmp -o helloworld_omp helloworld.c파일명이 helloworld.c라고 가정할 때 위와 같이 컴파일하면 된다.
$ ./helloworld_omp
Hello world Hello world
# include <stdio.h>앞의 예제에서 달라진 것은 omp.h 헤더를 포함한 것과 병렬구간을 시작하기 전에 omp_set_num_threads(4)를 실행한 것이다.
# include <omp.h>
int main()
{
omp_set_num_threads(4);
#pragma omp parallel
{
printf("Hello world\n"); }
return 0;
}
$ gcc -fopenmp -o loop_exam1 loop_exam1.c결과를 보면 0번 쓰레드가 0~3까지 처리하고, 1번 쓰레드가 4~7까지 처리하는 것으로 나온다. 위에는 이쁘지 않게 순서가 거꾸로 출력되었지만, 이 순서는 항상 같으리라고 보장할수는 없다. 따라서 출력 순서는 그냥 신경쓰지 말자.
$ ./loop_exam1
[1-4] Hello world [1-5] Hello world [1-6] Hello world [1-7] Hello world [0-0] Hello world [0-1] Hello world
[0-2] Hello world
[0-3] Hello world
#include <stdio.h>위의 pi 구하는 소스코드가 어떻게 나왔는지는 그냥 양념으로 알아두자.
#include <stdlib.h> int num_steps=1000000000; /* 10억번 : 너무 많으면 조금 줄이시길... */
int main()
{
int i;
double x, step, sum = 0.0;
step = 1.0/(double) num_steps;
for (i=0; i<num_steps; i++) {
x = (i+0.5) * step;
sum += 4.0/(1.0 + x*x);
}
printf("PI = %.8f (sum = %.8f)\n", step*sum, sum);
return EXIT_SUCCESS;
}
$ make pi_numerical_integrationtime명령으로 수행 시간을 보니 약 8.994초이며 user/sys영역에서 소비한 CPU타임도 이와 같은 것을 볼때 1개의 CPU만 사용했음을 알 수 있다. 이번에는 OpenMP를 적용하도록 소스코드를 수정하겠다. 중간에 #pragma omp parallel for 구문을 넣어주었다.
$ time ./pi_numerical_integration
PI = 3.14159265 (sum = 2513274122.87223005)
real 0m8.994s
user 0m8.993s
sys 0m0.001s
#include <stdio.h>이제 컴파일 후 실행해야한다. 컴파일은 make에 CFLAGS (Compiler flags) 변수에 openmp기능을 넣고 컴파일한다. (make를 이용하는 것이 쉬워서인데 gcc 명령어를 직접 타이핑하는게 좋다면 gcc -o pi_numerical_integration -fopenmp pi_numerical_integration.c 를 모두 타이핑하면 된다.)
#include <stdlib.h>
int num_steps=1000000000; /* 10억번 : 너무 많으면 조금 줄이시길... */
int main()
{
int i;
double x, step, sum = 0.0;
step = 1.0/(double) num_steps;
#pragma omp parallel for
for (i=0; i<num_steps; i++) {
x = (i+0.5) * step;
sum += 4.0/(1.0 + x*x);
}
printf("PI = %.8f (sum = %.8f)\n", step*sum, sum);
return EXIT_SUCCESS; }
$ make CFLAGS="-fopenmp" pi_numerical_integration
$ time ./pi_numerical_integration
PI = 2.26234349 (sum = 1809874795.18165779)
real 0m50.394s
user 1m38.686s sys 0m0.013s
#include <stdio.h>이제 컴파일후 실행해보면 real time이 약 CPU개수만큼 줄어드는 것을 볼 수 있다.
#include <stdlib.h>
int num_steps=1000000000; /* 10억번 : 너무 많으면 조금 줄이시길... */
int main()
{
int i; double x, step, sum = 0.0;
step = 1.0/(double) num_steps;
#pragma omp parallel for private(x) reduction(+:sum)
for (i=0; i<num_steps; i++) {
x = (i+0.5) * step;
sum += 4.0/(1.0 + x*x);
}
printf("PI = %.8f (sum = %.8f)\n", step*sum, sum);
return EXIT_SUCCESS; }
* 연습문제 (멀티 쓰레딩과 reentrant 함수의 관계에 대한 문제)
각변의 길이가 1인 정사각형이 있다. 그리고 정사각형 안에 반지름(r)이 1인 원호를 그리도록 하자.
그러면 중점으로부터 원호까지의 최단 길이는 무조건 1이 된다.
그러면 이제 정사각형 안에 임의의 점(x,y)좌표를 찍어서 중점에서 선분을 연결하고 아랫변까지 선분을 내리면 직각삼각형이 된다.
그리고 이 직각삼각형의 길이는 x, 높이는 y가 된다.
피타고라스의 정리에 의해 (x의 제곱)+(y의 제곱)=(빗변의 제곱)이 되는데, 빗변이 길이가 1보다 작으면
원호 안에 찍힌 점이 되고, 1보다 크면 원호 밖에 정사각형 내부에 찍힌 점이 된다.
원호의 넓이는 반지름 r=1일 때 pi/4이 된다. 따라서 위의 수많은 랜덤 좌표를 찍은 뒤에 (원호 내부의 점의 개수)/(전체 랜덤 수)는 pi/4와 같아질 것이다. 그러면 이제 기본 코딩을 해보자.
#include <stdlib.h>
이제 컴파일 후 실행을 해 보겠다. 소스코드의 파일명은 pi_monte.c라고 저장했다.
#include <stdio.h>
#include <time.h>
#include <math.h>
#define LOOP_ITERATION 200000000
int hits;
int main()
{
int i;
double x, y, rns;
time_t t_now;
printf("Loop iteration = %ld\n", (long)LOOP_ITERATION);
rns = 1.0/(double)RAND_MAX;
t_now = time(0);
srand((unsigned int)t_now);
for (i=0; i<LOOP_ITERATION; i++) {
x = (double)rand() * rns;
y = (double)rand() * rns;
if (x*x + y*y < 1) {
hits++;
}
}
printf("pi = %f\n", 4*(double)hits/LOOP_ITERATION);
return 0;
}
$ gcc -o pi_monte pi_monte.c
CPU를 한 개만 사용했기 때문에 real과 user+sys 시간이 같게 나온다.
$ time ./pi_monte
Loop iteration = 200000000
pi = 3.141588
real 0m8.726s
user 0m8.702s
sys 0m0.023s
이제 여기에 OpenMP를 적용해보도록 하자. 중복되는 코드는 모두 생략하고 중간에 loop부분만 적도록 하겠다.
...생략...
자 이제 수정된 소스코드를 컴파일하고 다시 실행해보겠다.
#pragma omp parallel for private(x,y) reduction(+:hits)
for (i=0; i<LOOP_ITERATION; i++) {
x = (double)rand() * rns;
y = (double)rand() * rns;
if (x*x + y*y < 1) {
hits++;
}
}
...생략...
$ gcc -o pi_monte_omp -fopenmp pi_monte.c
OpenMP버전의 실행 시간이 엄청나게 증가한 것을 볼 수 있다.
$ time ./pi_monte_omp
Loop iteration = 200000000
pi = 3.141513
real 0m54.909s
user 0m54.173s
sys 0m53.115s
이는 뭔가 문제가 발생한 것이다. profiler가 있으면 cache miss가 많아진 것을 추적할 수 있다. 그러면 왜 cache miss가 많아졌을까?
이는 멀티 쓰레드 안전(thread-safe, MT-safe)한 함수를 사용하지 않았기 때문이다.
단도직입으로 원인은 rand()함수이다. rand()함수는 내부에 static 변수(BSS영역)를 사용하기 때문에 lock 없이 사용하면
오염된 공간을 쓸 수 있다. 그렇다고 lock으로 보호하는 것은 성능상으로 좋지 못하다. 따라서 MT-safe한 랜덤생성 함수로
대체해야 한다. 마침 rand()의 reentrant 버전인 rand_r()이 있으므로 이를 사용하도록 바꾸면 된다.
* reentrant에 대한 이해가 필요하다면...http://sunyzero.egloos.com/4188321 글을 읽도록 한다.
그러면 이제 수정된 버전을 보도록 하겠다.
#define _REENTRANT
중요한 변화를 확인하기 위해 LOOP_ITERATION이 100 이하인 경우에는 루프를 돌때마다 rand_r()로 얻어진 x, y, state의 값을 출력하도록 디버깅 코드를 심어놨다. 그러면 LOOP_ITERATION을 20으로 줄여서 컴파일&실행으로 디버깅 해보자.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#ifdef LOOP_ITERATION
#define LOOP_ITERATION 200000000
#endif
int hits;
int main()
{
unsigned int state;
int i;
double x, y, rns;
printf("Loop iteration = %ld\n", (long)LOOP_ITERATION);
rns = 1.0/(double)RAND_MAX;
state = (unsigned int)time(0);
#pragma omp parallel for firstprivate(state) private(x, y) reduction(+:hits)
for (i=0; i<LOOP_ITERATION; i++)
{
x = (double)rand_r(&state) * rns;
y = (double)rand_r(&state) * rns;
#if LOOP_ITERATION < 100
printf("THR[%d:%d] x,y/state = %f,%f/%u\n", omp_get_thread_num(), i, x, y, state);
#endif
if (x*x + y*y < 1) { hits++; }
}
printf("pi = %f (hits = %d)\n", (double)hits/LOOP_ITERATION * 4, hits);
return 0;
}
$ gcc -o pi_monte_omp_logging -DLOOP_ITERATION=20 -fopenmp pi_monte.c
iteration이 20번이므로 pi의 정확도는 일단 포기하자. 지금은 pi의 결과를 보려는 것이 아니라, 각 쓰레드의 x, y값을 확인하기 위함이다. 0번째 쓰레드의 첫번째 데이터와 1번째 쓰레드의 첫번째 데이터를 비교하니 뭔가 이상하다. 이해를 돕기 위해 두개만 따로 떼어서 보도록 하자.
$ ./pi_monte_omp_logging
Loop iteration = 20
THR[0:0] x,y/state = 0.739258,0.373189/1534713604
THR[0:1] x,y/state = 0.741886,0.152093/434332526
THR[0:2] x,y/state = 0.399359,0.675170/1402811528
THR[0:3] x,y/state = 0.140991,0.510551/3217124562
THR[0:4] x,y/state = 0.117010,0.018486/2612351692
THR[0:5] x,y/state = 0.151627,0.286311/535820534
THR[0:6] x,y/state = 0.412198,0.450266/361487824
THR[0:7] x,y/state = 0.126866,0.324974/1313573850
THR[0:8] x,y/state = 0.923697,0.862684/1937324436
THR[0:9] x,y/state = 0.828232,0.810037/3167316350
THR[1:10] x,y/state = 0.739258,0.373189/153471360
THR[1:11] x,y/state = 0.741886,0.152093/434332526
THR[1:12] x,y/state = 0.399359,0.675170/1402811528
THR[1:13] x,y/state = 0.140991,0.510551/3217124562
THR[1:14] x,y/state = 0.117010,0.018486/2612351692
THR[1:15] x,y/state = 0.151627,0.286311/535820534
THR[1:16] x,y/state = 0.412198,0.450266/361487824
THR[1:17] x,y/state = 0.126866,0.324974/1313573850
THR[1:18] x,y/state = 0.923697,0.862684/1937324436
THR[1:19] x,y/state = 0.828232,0.810037/3167316350
pi = 3.200000 (hits = 16)
THR[0:0] x,y/state = 0.739258,0.373189/1534713604
THR[1:10] x,y/state = 0.739258,0.373189/1534713604
둘이 놀랍도록 일치하지 않은가? 왜 이런 문제가 발생할까? 이는 rand_r()함수에 사용하는 seed값 변수인 state의 초기값이 모든 쓰레드들에 대해서 같기 때문에 발생하는 문제다. 그렇다면 각 쓰레드가 seed를 다르게 가져가도록 소스코드를 수정해야 한다.
#define _REENTRANT
#pragma omp critical 지시어는 아래의 블럭공간을 락으로 보호해준다. 즉 state1으로부터 state2라는 seed값을 생성하는 코드 부분은 각 쓰레드들이 직렬적으로 실행하게 되므로 각각 다른 seed (=state2)를 가질 수 있게 해준다.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#ifdef LOOP_ITERATION
#define LOOP_ITERATION 200000000
#endif
int hits;
int main()
{
unsigned int state1, state2;
int i;
double x, y, rns;
printf("Loop iteration = %ld\n", (long)LOOP_ITERATION);
rns = 1.0/(double)RAND_MAX;
state1 = (unsigned int)times(NULL);
#pragma omp parallel private(x, y, state2) reduction(+:hits) shared(state1)
{
#pragma omp critical
state2 = rand_r(&state1);
printf("THR[%d] state1/state2 = %u/%u\n", omp_get_thread_num(), state1, state2);
#pragma omp for
for (i=0; i<LOOP_ITERATION; i++) {
x = (double)rand_r(&state2) * rns;
y = (double)rand_r(&state2) * rns;
#if LOOP_ITERATION < 100
printf("THR[%d:%d] x,y/state,hits = %f,%f/%u,%d\n", omp_get_thread_num(), i, x, y, state2,hits);
#endif
if (x*x + y*y < 1) { hits++; }
}
}
printf("hits(%d), pi = %f\n", hits, (double)hits/LOOP_ITERATION * 4);
return 0;
}
그러면 이제 수정된 버전의 확인을 위해 LOOP_ITERATION을 20번으로 지정하고 컴파일하여 다시 실행해보자.
$ gcc -o pi_monte_omp_logging -DLOOP_ITERATION=20 -fopenmp pi_monte.c
실행 결과를 보면 이제 x, y값이 각 쓰레드마다 달라지는 것을 볼 수 있다.
$ ./pi_monte_omp_logging
Loop iteration = 20
THR[0] state1/state2 = 2209777173/920556694
THR[0:0] x,y/state,hits = 0.007502,0.800638/402955376,0
THR[0:1] x,y/state,hits = 0.031584,0.366846/1879397754,1
THR[0:2] x,y/state,hits = 0.084310,0.126795/2318644788,2
THR[0:3] x,y/state,hits = 0.219188,0.054924/839319838,3
THR[0:4] x,y/state,hits = 0.315477,0.640078/2081973432,4
THR[0:5] x,y/state,hits = 0.423693,0.287051/4130577282,5
THR[0:6] x,y/state,hits = 0.738140,0.376765/2380434428,6
THR[0:7] x,y/state,hits = 0.127375,0.723816/3248220326,7
THR[0:8] x,y/state,hits = 0.832496,0.256793/3481063424,8
THR[0:9] x,y/state,hits = 0.939841,0.108509/3174395018,9
THR[1] state1/state2 = 2209777173/754906038
THR[1:10] x,y/state,hits = 0.446803,0.061819/2639594128,0
THR[1:11] x,y/state,hits = 0.919237,0.585474/2439875226,1
THR[1:12] x,y/state,hits = 0.122634,0.254468/2048737876,1
THR[1:13] x,y/state,hits = 0.204702,0.526382/3058641982,2
THR[1:14] x,y/state,hits = 0.642845,0.756832/477247192,3
THR[1:15] x,y/state,hits = 0.550340,0.531024/1736039586,4
THR[1:16] x,y/state,hits = 0.926036,0.217729/4074357788,5
THR[1:17] x,y/state,hits = 0.266219,0.975137/2510577606,6
THR[1:18] x,y/state,hits = 0.663719,0.557898/2880736800,6
THR[1:19] x,y/state,hits = 0.491536,0.580296/2760522154,7
hits(18), pi = 3.600000
그러면 이제 기능상의 문제는 해결되었으니 원래대로 200,000,000번의 시행 횟수로 실행시간을 비교해보자.
$ gcc -o pi_monte_omp -fopenmp pi_monte.c
싱글 쓰레드 버전이 8.6초 걸린 것에 비해 OpenMP로 돌린 버전은 2.4초로 확 줄어들었다. 원래대로라면 듀얼코어니 4.3초정도가 나와야 하겠지만, rand_r()자체가 rand()보다 가볍기 때문에 그로 인해서 속도가 더 빨라졌다. 즉 싱글 쓰레드 버전이라고 해도 rand()보다는 rand_r()을 사용하면 더 빠르다라는 교훈도 덤으로 알려드리는 문제였다.
$ time ./pi_monte_omp
Loop iteration = 200000000
THR[0] state1/state2 = 319398670/265139008
THR[1] state1/state2 = 319398670/1387545353
hits(157082826), pi = 3.141657
real 0m2.414s
user 0m4.737s
sys 0m0.013s
5. Section construct
section construct는 task level parallelism에 사용하며, 각각의 작업들이 서로 관련이 없는 경우에 사용한다.
(task 레벨의 병렬화이므로 divide and conquer 형태의 문제해결에도 적용가능하다.)
단 각각의 섹션은 누가 먼저 종료하든지 #pragram omp sections 블록의 끝에는 implicit barrier가 있으므로 대기하게 된다.
참고로 병렬구간내에 섹션구간만 존재하는 경우라면 #pragma omp parallel sections로 구문을 합칠 수 있다.
그러면 이번에는 앞에서 loop construct때 연습했던 2가지 pi 구하는 방법(numerical integration, monte carlo simulation)을
sections를 이용해서 동시에 작동시키도록 바꿔보자.
* 연습문제 (섹션별로 task를 할당하는 방법)
앞에서 Single threaded 버전으로 만들었던 소스코드들을 연달아 붙여두면 된다.
우선 Numerical Integration 방법의 소스코드를 다시 보자.
#include <stdio.h>
이번에는 Monte Carlo simulation방법을 다시 보겠다.
#include <stdlib.h>
int num_steps=1000000000; /* 10억번 : 너무 많으면 조금 줄이시길... */
int main()
{
int i;
double x, step, sum = 0.0;
step = 1.0/(double) num_steps;
for (i=0; i<num_steps; i++)
{
x = (i+0.5) * step;
sum += 4.0/(1.0 + x*x);
}
printf("PI = %.8f (sum = %.8f)\n", step*sum, sum);
return EXIT_SUCCESS;
}
#include <stdlib.h>
이제 이 2개의 소스코드를 합쳐야 한다. 주의할 점은 두번째 Monte Carlo simulation에서는 rand()함수 대신에 rand_r()을 사용하는 것을 잊지 말아야 한다. 항상 Non-multi-threaded model을 Multi-threaded model로 바꿀때는 MT-safe function이나 reentrant function으로 골라 써야 한다는 점이다.
#include <stdio.h>
#include <time.h>
#include <math.h>
#define LOOP_ITERATION 200000000
int hits;
int main()
{
int i;
double x, y, rns;
time_t t_now;
printf("Loop iteration = %ld\n", (long)LOOP_ITERATION);
rns = 1.0/(double)RAND_MAX;
t_now = time(0);
srand((unsigned int)t_now);
for (i=0; i<LOOP_ITERATION; i++)
{
x = (double)rand() * rns;
y = (double)rand() * rns;
if (x*x + y*y < 1) { hits++; }
}
printf("pi = %f\n", 4*(double)hits/LOOP_ITERATION);
return 0;
}
그리고 false-sharing문제를 피하기 위해서 동일 캐시 라인에 올라갈 수 있는 전역변수나 힙 메모리를 사용하면 안된다는 점이다. 왠만하면 쓰레드 로컬 변수에서 대부분 해결하도록 하자.
그러면 둘을 #pragma omp sections로 합친 코드를 보겠다. 보기 좋게 출력부분의 수정을 했으나 기본 코드는 같다.
#define _XOPEN_SOURCE 600
이제 실행을 해보자.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <sys/times.h>
#include <omp.h>
#ifndef LOOP_ITERATION
#define LOOP_ITERATION 200000000
#endif
double pi[2];
int main()
{
clock_t start_m, end_m;
clock_t sc_clk_tck = sysconf(_SC_CLK_TCK);
start_m = times(NULL);
printf("LOOP ITERATION = %ld\n",(long)LOOP_ITERATION);
#ifdef _OPENMP
omp_set_num_threads(2);
#endif
#pragma omp parallel
{
#pragma omp sections
{
#pragma omp section
{
int i;
double x, step, hits;
float t_elapsed;
clock_t start, end;
hits = 0.0;
#ifdef _OPENMP
printf("[SECTION] integration method by thread(%d)\n", omp_get_thread_num());
#else
printf("[SECTION] start integration method\n");
#endif
start = times(NULL); /* get clock tick */
step = 1.0/(double) LOOP_ITERATION;
for (i=0; i<LOOP_ITERATION; i++)
{
x = (i+0.5) * step;
hits += 1.0/(1.0 + x*x);
}
pi[0] = 4 * hits * step;
end = times(NULL);
t_elapsed = (float) (end - start)/sc_clk_tck;
#ifdef _OPENMP
printf("[SECTION] end integration method by thread(%d):elapsed time(%.02f sec)\n",
omp_get_thread_num(), t_elapsed);
#else
printf("[SECTION] end integration method: elapsed time(%.02f sec)\n",
t_elapsed);
#endif
}
#pragma omp section
{
int i, state, hits;
double x, y, rns;
float t_elapsed;
clock_t start, end;
#ifdef _OPENMP
printf("[SECTION] monte carlo method by thread(%d)\n", omp_get_thread_num());
#else
printf("[SECTION] start monte carlo method\n");
#endif
start = times(NULL); /* get clock tick */
state = time(0);
rns = 1.0/(double)RAND_MAX;
hits = 0;
for (i=0; i<LOOP_ITERATION; i++)
{
x = (double)rand_r((unsigned int *)&state) * rns;
y = (double)rand_r((unsigned int *)&state) * rns;
if (x*x + y*y < 1) { hits++; }
}
pi[1] = (hits / LOOP_ITERATION) * 4;
end = times(NULL);
t_elapsed = (float) (end - start)/sc_clk_tck;
#ifdef _OPENMP
printf("[SECTION] end monte carlo method by thread(%d): elapsed time(%.02f sec)\n",
omp_get_thread_num(), t_elapsed);
#else
printf("[SECTION] end monte carlo method: elapsed time(%.02f sec)\n",
t_elapsed);
#endif
}
}
}
end_m = times(NULL);
printf("integration PI = %.8f\n", pi[0]);
printf("monte carlo PI = %.8f\n", pi[1]);
printf("* Total elapsed time(%.02f sec)\n", (double)(end_m - start_m)/sc_clk_tck);
return EXIT_SUCCESS;
}
$ gcc -o pi_sections_omp -fopenmp pi_sections.c
당연히 Numerical Integration이 더 빠르기 때문에 먼저 끝난다. 하지만 implicit barrier가 있기 때문에 대기하게 된다. Monte Carlo simulation은 더 오래 걸리기 때문에 전체 수행 시간은 Monte Carlo simulation이 끝나는 시간에 종료한다.
$ time ./pi_sections_omp
LOOP ITERATION = 200000000
[SECTION] integration method by thread(0)
[SECTION] monte carlo method by thread(1)
[SECTION] end integration method by thread(0):elapsed time(1.79 sec)
[SECTION] end monte carlo method by thread(1): elapsed time(5.05 sec)
integration PI = 3.14159265
monte carlo PI = 3.14161276
* Total elapsed time(5.05 sec)
real 0m5.052s
user 0m6.858s
sys 0m0.016s
[#M_더보기|접기|
$ gcc -o omp_single -fopenmp omp_single.c
$ ./omp_single
1. Hello world 2. Hello world 2. Hello world
char * get_time0(char *buf, size_t sz_buf);이제 실행해보면 배리어 효과때문에 마지막 실행한 19:12:28에서 5초뒤에 phase2가 실행되는 것을 볼 수 있다.
int main() {
int t_sleep; char buf[16];
#pragma omp parallel private(t_sleep, buf)
{
#pragma omp single nowait
sleep(1);
printf("[%s] phase1:sleep %ld sec.\n", get_time0(buf, sizeof(buf)), t_sleep = times(NULL)%8);
sleep(t_sleep);
#pragma omp barrier
/* explicit barrier */
printf("[%s] phase2. Hello world\n", get_time0(buf, sizeof(buf)));
}
return 0;
}
char * get_time0(char *buf, size_t sz_buf)
{
time_t t0; struct tm tm_now;
if (buf == NULL) return NULL;
if (time(&t0) == ((time_t)-1)) return NULL;
localtime_r(&t0, &tm_now);
if (strftime(buf, sz_buf, "%H:%M:%S", &tm_now) == 0) return NULL;
return buf;
}
$ ./omp_barrier
[19:12:27] phase1:sleep 1 sec.
[19:12:28] phase1:sleep 5 sec.
[19:12:33] phase2. Hello world
[19:12:33] phase2. Hello world
9. critical & atomic construct
critical construct와 atomic construct는 공유(shared) 영역을 보호하는 lock의 일종이다. 따라서 critical과 atomic을 사용한 영역은 쓰레드 중에 단 하나의 쓰레드만 진입하고 나머지는 대기하게 된다. 즉 직렬실행구간이 된다. 따라서 역으로 말하면 critical과 atomic을 남발하는 프로그래밍을 하면 성능이 확 떨어진다는 소리이다. 그럼에도 불구하고 꼭 lock이 필요한 기능이므로 잘 익혀두어야만 한다.
우선 둘의 차이부터 이해하고 넘어가자. 만일 두 단어만 보고도 감이 오는 사람은 학생 때 운영체제 수업에서 critical section이나 atomic operation을 배운 사람일 것이다.
• critical : 범용적인 lock
• atomic : critical보다 가볍고 빠른 lock (critical의 special한 케이스)
critical은 노멀한 lock이지만 atomic은 매우 가벼운 용도에만 사용한다. 가볍다는 것은 보통 1개의 스칼라 변수를 업데이트 하는 정도를 의미한다. 만일 변수 업데이트를 넘어서 계산이나 캐스팅, 복잡한 데이터 핸들링을 하는 경우라면 critical을 사용하도록 한다.
[참고로 정수형 변수 1개의 값을 변경하는 정도라면 atomic 없이 프로그래밍을 하는 것도 추천한다. atomic을 쓰지 않으면 수치상의 오류가 생기는 경우도 있겠지만 일반적으로는 10ppm(part per million) 이하인 경우이므로 무시할 수 있는 오차 일 수 있다. 왜냐하면 atomic의 가벼운 lock도 멀티 쓰레드에서는 성능을 많이 떨어뜨리기 때문이다.]
[보충 설명: 일반적으로 공유된 데이터에 복수개의 쓰레드가 접근할 경우에는 무조건 lock으로 보호해야만 한다. 모든 교과서나 매뉴얼에는 이렇게 나와있다. 그러나 프로그래머가 어느 정도 멀티 쓰레드에 대한 이해가 깊어지면 교과서나 매뉴얼을 응용할 수 있어야만 한다. 필자가 앞에서 정수형 변수 1개의 값을 업데이트하는 경우에는 lock을 쓰지 않는 것도 좋다고 했는데 이는 감히 교과서에는 쓸 수 없는 내용이다. 하지만 공유된 변수가 약간의 오차가 생겨도 괜찮은 경우, 즉 근접해나 근사치를 계산하는 시뮬레이션이나 휴리스틱 코드라면 atomic을 쓰지 않을 경우 더 빠르게 작동할 수 있다. 그리고 빠른 실행이 가능해졌기 때문에 시행횟수를 더 늘림으로서 오차를 보정할 수 있게된다. 그러므로 오차 보정이 가능한 수치계산이나 오차보다 속도가 더 중요한 문제라면 atomic을 생략하는 것도 고려하라는 뜻이 담겨있는 것이다. 그러나 주의할 점은 꼭 프로그래밍을 할 때 atomic을 선택적으로 적용할 수 있도록 코딩해두고 atomic을 사용한 버전과 사용하지 않은 버전의 차이를 꼭 비교해봐야 한다. 만일 atomic을 사용하지 않은 버전이 메리트가 없다면 반드시 lock을 사용한 버전을 택하는 것이 좋다.
9.1 critical construct
#pragma omp critical [(lock_name)]
critical에서 락 이름(lock_name)을 생략하는 경우는 동일한 lock을 사용하는 것으로 간주되어 critical 지시어가 여러 번 나오더라도 동일하게 보호되는 구간이 된다. 자세한 것은 예제를 보면서 익히도록 하자. 예제로 아래와 같은 pseudo code가 있다.
#pragma omp parallel for
위의 예제에서 chk_process() 함수가 lock으로 보호되어야 한다면 critical 지시어를 사용하여 아래와 같이 할 수 있다.
for (i=0; i<MAX_ITERATION; i++)
{
process_a();
chk_process();
process_b();
chk_process();
process_c();
chk_summary();
}
#pragma omp parallel for
critical construct을 2군데에서 사용했지만 lock_name을 지정하지 않았기 때문에 같은 lock으로 인식하여 보호된다. [위와 같이 프로그래밍하지 않고 chk_process()함수 내부에 critical을 선언하여도 결과는 같다.]
for (i=0; i<MAX_ITERATION; i++)
{
process_a();
#pragma omp critical
chk_process();
process_b();
#pragma omp critical
chk_process();
process_c();
chk_summary();
}
그렇다면 이번에는 chk_summary()에 critical을 추가해보겠다. 하지만 chk_process()와는 상관없이 다른 락으로 보호하도록 하겠다. 이 경우에는 필수적으로 lock_name을 사용해야 한다.
#pragma omp parallel for
이제 critical의 사용방법에 대해서는 어느정도 감이 왔을 것이다. 하지만 거듭 강조하지만 왠만하면 lock은 최소한으로 사용하는 것이 좋다. 멀티 쓰레드 프로그래밍에서 lock을 통한 직렬구간을 많이 만들면 프로그래밍은 쉽지만 성능은 바닥을 치기 때문에 멀티 쓰레드 프로그래밍을하는 의미가 사라지게 된다.
for (i=0; i<MAX_ITERATION; i++)
{
process_a();
#pragma omp critical (lock1)
chk_process();
process_b();
#pragma omp critical (lock1)
chk_process();
process_c();
#pragma omp critical (lock2)
chk_summary();
}
9.2 atomic construct
#pragma omp atomic
atomic은 스칼라 변수 한개를 업데이트 한다고 했다. 너무 간단하기 때문에 간단한 예제 하나로 끝내겠다.
#pragma omp parallel
atomic에서 쓸 수 있는 표현식은 ++나 --같은 unary operation이나 "변수=값"정도의 간단한 대입식 정도이다.
...생략...;
#pragma omp atomic
n_count++;
}
10. OpenMP API
앞에서 omp_get_thread_num() 같은 openmp의 함수들을 보았다. 이번에는 주로 사용되는 함수들을 정리해서 보도록 하겠다.
* 쓰레드 풀에 관련된 함수들
void omp_set_num_threads(int num_threads); 병렬 구간에서 생성할 쓰레드 개수를 설정
int omp_get_num_threads(void); 병렬 구간에서 생성할 쓰레드 개수를 리턴
int omp_get_max_threads(void); 쓰레드 최대값 리턴
int omp_get_thread_num(void); 현재 쓰레드 번호 리턴
int omp_get_num_procs(void); 물리적 프로세서의 개수 리턴
int omp_in_parallel(void); 병렬 구간일 경우 true(0이 아닌값), 아니면 false(0)을 리턴
void omp_set_dynamic(int dynamic_threads); 생성할 쓰레드 개수를 동적으로 조정할 지 여부 (dynamic_threads가 1이면 true, 0이면 false)
int omp_get_dynamic(void); 위의 omp_set_dynamic의 설정을 리턴
아래 예제처럼 omp_set_dynamic이 설정되면 사용량에 따라서 쓰레드의 개수가 10개를 넘지 않는 범위에서 적당하게 조정된다.#include <omp.h>
예제 출처: OpenMP 2.5 Specification
int main()
{
omp_set_dynamic(1);
#pragma omp parallel num_threads(10)
{
/* do work here */
}
return 0;
}
* OpenMP에서 제공하는 lock 기능 API : 정교한 모델을 만들때 유용하므로 꼭 읽어두자.
void omp_set_nested(int nested); nested가 1이면 병렬구간의 중첩을 허용, 0이면 허용하지 않음
int omp_get_nested(void); 위의 nested 설정을 리턴
void omp_init_lock(omp_lock_t *lock); OMP의 lock을 초기화
void omp_init_nest_lock(omp_nest_lock_t *lock); 중첩 lock버전의 위와 같은 기능의 함수 (=재귀잠금이 가능한 lock)
void omp_destroy_lock(omp_lock_t *lock); OMP의 lock을 제거
void omp_destroy_nest_lock(omp_nest_lock_t *lock); nested lock버전의 위와 같은 기능의 함수
void omp_set_lock(omp_lock_t *lock); OMP의 lock을 잠금
void omp_set_nest_lock(omp_nest_lock_t *lock); nested lock버전의 위와 같은 기능의 함수
void omp_unset_lock(omp_lock_t *lock); OMP의 lock을 잠금 해제
void omp_unset_nest_lock(omp_nest_lock_t *lock); nested lock버전의 위와 같은 기능의 함수
int omp_test_lock(omp_lock_t *lock); 잠금 여부를 테스트하여 가능한 상태면 잠그고 다른 쓰레드에 의해 잠긴 상태면 false를 리턴 (=nonblocking 버전의 함수임)
int omp_test_nest_lock(omp_nest_lock_t *lock); nested lock버전의 위와 같은 기능의 함수
double omp_get_wtime(void); 병렬처리 구간에서의 수행 시간(단위: 초)
double omp_get_wtick(void); omp_get_wtime()에서 제공하는 시간 정밀도 (최소 단위 시간)
double start;
예제 출처: OpenMP 2.5 Specification
double end;
start = omp_get_wtime();
... work to be timed ...
end = omp_get_wtime();
printf("Work took %f seconds\n", end - start);
OpenMP 2.5에서 제공하는 모든 API를 다루었다. 특히 lock관련 함수는 중요하기 때문에 잘 알아두면 도움이 된다.
11. OpenMP에서 제공하는 환경변수 및 전처리기
OpenMP에서는 스케줄링, 생성할 쓰레드 개수, 동적 조정 여부, 병렬구간에서 쓰레드의 중첩 허용을 runtime시에 결정할 수 있도록 환경변수를 설정할 수 있다.
• OMP_SCHEDULE : 스케줄링 타입과 chunk 크기를 설정
• OMP_NUM_THREADS : 병렬 구간에서 생성할 쓰레드 개수
• OMP_DYNAMIC : 쓰레드 개수의 동적 조정 여부를 설정
• OMP_NESTED : 쓰레드 중첩의 허용 여부를 설정
사용예 : bash (or POSIX shell)의 명령export OMP_SCHEDULE="dynamic"
export OMP_SCHEDULE "guided,4"
export OMP_NUM_THREADS 16
export OMP_DYNAMIC true
export OMP_NESTED false
* OMP 조건부 컴파일을 위한 전처리기
#include <stdio.h>
int main()
{
# ifdef _OPENMP
printf("Compiled by an OpenMP-compliant implementation.\n");
# endif
return 0;
}
12. OpenMP vs pthread (POSIX thread)
OpenMP로 작성한 프로그램을 그대로 pthread 버전으로 바꾸면서 둘의 차이를 보도록 하겠다.
예제로 볼 것은 앞에서 numerical integration으로 pi를 계산한 프로그램을 두가지 버전으로 작성해서 비교하도록 하겠다.
우선 HOWTO #1에서 봤던 OpenMP 버전을 다시 보도록 하겠다.
예제 파일 : pi_numerical_integration.c#include <stdio.h>
OpenMP버전은 이미 설명했었기 때문에 이를 바로 Pthread 버전으로 바꾸도록 하겠다.
#include <stdlib.h>
int num_steps=1000000000; /* 10억번 : 너무 많으면 조금 줄이시길... */
int main()
{
int i;
double x, step, sum = 0.0;
step = 1.0/(double) num_steps;
#pragma omp parallel for private(x) reduction(+:sum)
for (i=0; i<num_steps; i++)
{
x = (i+0.5) * step;
sum += 4.0/(1.0 + x*x);
}
printf("PI = %.8f (sum = %.8f)\n", step*sum, sum);
return EXIT_SUCCESS;
}
pthread 버전 예제 파일 : pi_integration_pth.c
#include <stdio.h>
pthread 버전으로 바꾸면 openmp버전보다 코딩량이 훨씬 늘어난다.
#include <stdlib.h>
#include <pthread.h>
static int num_steps=1000000000;
double pi, step;
struct start_arg
{
int i_start;
int i_end;
double sum;
} start_arg[2];
void *start_func(void *arg)
{
int i;
double x, sum = 0.0;
struct start_arg *p_arg = (struct start_arg *) arg;
for (i=p_arg->i_start; i<p_arg->i_end; i++)
{
x = (i+0.5) * step;
sum += 4.0/(1.0 + x*x);
}
p_arg->sum = sum;
return NULL;
}
int main()
{
int i;
double sum;
pthread_t pt_id[2];
step = 1.0/(double) num_steps;
start_arg[0].i_start = 0;
start_arg[0].i_end = num_steps>>1;
start_arg[1].i_start = start_arg[0].i_end + 1;
start_arg[1].i_end = num_steps;
printf("%d~%d, %d~%d\n",
start_arg[0].i_start, start_arg[0].i_end ,
start_arg[1].i_start, start_arg[1].i_end );
for (i=2; i--; ) /* Create Pthread */
{
if (pthread_create(&pt_id[i], NULL, start_func, &start_arg[i]))
{
perror("pthread_create");
return 1;
}
}
for (i=2; i--; ) /* join pthread : explicit barrier */
{
if (pthread_join(pt_id[i], NULL))
{
perror("pthread_join");
return 1;
}
}
sum = start_arg[0].sum + start_arg[1].sum;
printf("PI = %.8f (sum = %.8f)\n", step*sum, sum);
return EXIT_SUCCESS;
}
POSIX thread를 사용하면 OpenMP에서 없는 explicit barrier를 넣어주어야 하므로 pthread_join()함수를 사용했으며, OpenMP에서 간단하게 reduction을 했던 것이 POSIX thread에서는 개별적인 start_arg라는 구조체를 통해서 확인했다. 이로 인해서 코딩량과 자료구조까지 신경써야 하는 불편함이 생긴다.
그러나 OpenMP가 POSIX thread보다 우월하다고 말하는 것은 아니다. 문제가 정교함을 요구하는 경우에는 오히려 OpenMP가 적합하지 않은 경우도 많기 때문이다. 실제로 조건변수를 이용한다든지 쓰레드 키를 이용한 라이브러리등을 사용하는 경우라면 POSIX thread외에는 대안이 없는 경우가 많기 때문이다. 이 글은 OpenMP를 소개하는 글이므로 OpenMP에 대해 좋은 말만 늘어놓고 있지만 필자의 말을 비판없이 받아들여서 OpenMP가 최고라는 편협한 사고에 휩싸이지는 않았으면 좋겠다.
잡설이 길었는데 마지막으로 두가지 버전의 실행 결과를 확인해보자. 첫번째 실행한 파일인 pi_integration이 OpenMP버전이고, 두번째의 pi_integration_pth가 Pthread버전이다.
$ time ./pi_integration
PI = 3.14159265 (sum = 3141592653.59036255)
real 0m3.910s
user 0m7.484s
sys 0m0.018s
$ time ./pi_integration_pth
결과를 보면 실행결과나 성능에 큰 차이가 없어 보인다. 하지만 몇몇 컴파일러에서는 특정 버전이 더 느린 경우도 있다.(이는 해당 플랫폼의 특징에서 기인한다. 표준안에는 성능에 대한 제약은 없기 때문에 몇몇 플랫폼은 OpenMP 구현시 덜 최적화 되어있는 경우도 있다.)
0~500000000, 500000001~1000000000
PI = 3.14159265 (sum = 3141592650.38979244)
real 0m4.071s
user 0m7.399s
sys 0m0.022s
13. 마치면서.
처음 시작하면서 멀티 쓰레드 프로그래밍의 필요성에 대해서 언급했었다. CPU의 개별 코어의 주파수(frequency)는 거의 한계치에 와 있기 때문에 개별 코어의 속도는 파이프라인의 증설이나 몇가지 기술로 약간의 진보밖에 이룰 수 없게 되었다. 따라서 멀티코어를 적극적으로 사용하는 기술이 뒷받침되지 않고는 프로그램의 성능을 높일 수 있는 방법은 거의 없다.(일각에서 언급되는 그래픽카드의 코어를 병렬로 이용하는 GPGPU도 같은 맥락이다.) 하지만 멀티 쓰레드 프로그래밍은 다음과 같은 난제가 있다.
첫째로 문제인 디버깅에서 언급되는 재현성은 쓰레드 프로그래밍에서 큰 난제이다. 디버깅을 위해서는 같은 조건하에서 시행하였을때 동일한 문제가 재현되어야만 버그를 찾아낼 수 있다. 그러나 멀티 쓰레드 프로그램은 각각의 쓰레드들이 같은 순서로 실행된다는 보장이 없기 때문에 버그가 발생한 순서조합이 디버깅때도 항상 발생하지 않는다. 즉 문제를 찾아내려고 할때는 오히려 제대로 작동하는 경우도 많다는 것이다.
따라서 멀티 쓰레드 프로그램을 대형 모델에 적용할 때는 투명성을 높여서 각각의 데이터나 태스크의 흐름을 모니터링할 수 있도록 만들어야 한다. 이를 위해서 여러 방법론이 나와있지만 스페셜한 케이스에는 딱 들어맞는 것은 없다. 그러므로 반복적인 프로그래밍 훈련만이 투명성을 높이고 디버깅이 쉬운 개발철학을 만들 수 있게 해준다.
둘째로 우리가 종종 사용하는 x86 인텔 호환 플랫폼은 PC환경에서 가장 많이 쓰이지만 산업체에서는 IA64, Sparc, MIPS, PPC(PowerPC) 등등의 CPU에 여러가지 OS조합의 플랫폼이 사용된다. 그러나 같은 프로그래밍을 짜도 표준안에서 언급한 semantic을 만족하면서 미묘한 차이를 보이는 경우가 많다. 특히 기능은 제대로 작동하는데 성능은 이상하게 차이나는 경우가 발생할 수 있다. 이를 해결하기 위해서는 각각의 플랫폼에 대한 이해와 하드웨어 지식이 필요한데, 한사람의 프로그래머가 모든 플랫폼에 정통할 수는 없기 때문에 적극적으로 다른 플랫폼의 전문가와 소통할 수 있는 채널이 있어야만 한다. (더 중요한 점은 다른 플랫폼의 전문가와 제대로 소통할 수 있도록 질문을 잘 하는 방법을 익히는 것이다. 간혹 질문을 잘 못하고 횡설수설하면 답변을 해주고 싶어도 못한다. 필자도 좀 횡설수설하는 스타일이라 고치려고 하는데 참 어렵다.)
하지만 이런 어려움은 점차 해소될 전망이다. 앞으로 나오는 많은 기술들과 소프트웨어 방법론들은 프로그래머가 복잡한 이론이나 방법론을 몰라도 멀티 쓰레드 프로그래밍을 쉽게 할 수 있도록 돕고 있다. 실제로 10년전과 지금은 하늘과 땅 차이로 멀티 쓰레드 프로그래밍이 쉬워졌다.(그럼에도 불구하고 아직도 멀티 쓰레드 프로그래밍은 어려운 분야이지만...)
비슷한 예를 하나 들자면 15년전쯤에 필자가 프로그래밍을 처음 접하던 시절에는 그래픽 처리를 위해 어셈블리어를 배우는 것이 유행했던 시절이 있었다. 속도와 최적화 문제에서 다른 대안이 없었기 때문이었다. 그러나 지금은 어셈블리어를 몰라도 왠만한 그래픽 최적화를 하는데 무리가 없다.(아주 가끔 어셈블러에 의지해야 하는 스페셜 케이스가 있긴하다.) 이는 시간이 지나면 좀 더 편리한 프로그래밍 환경이 만들어진다는 것을 의미한다.
그렇다면 이쯤에서 독자들은 필자에게 반문할 것이다. "멀티 쓰레드 프로그래밍이 쉬워지기를 기다리라는 말입니까?" 이에 대한 필자의 대답은 "절반은 그렇다"이다. 왜 절반만 Yes를 하는지는 그 쉬워지는 시점 때문이다. 많은 선도자들은 예측하기를 멀티 쓰레드 프로그래밍의 하드웨어적, 소프트웨어적 난제들이 해결되어 많은 부분에서 변화가 생기려면 적어도 5~10년후가 되어야 할 것이라고 한다. 그렇다면 본인이 앞으로 5~10년을 기다릴 수 있는 형편인지 아니면 당장 써야 하는지 결정해야한다. 한창 공부하는 학생이라면 더 기다리다가 공부해도 되겠지만 field에서 일하는 산업역군이라면 당장 공부하라고 말해주겠다.
XCOPY 사용 방법 (0) | 2010.01.14 |
---|---|
[펌] Tip of finding Bugs (0) | 2009.12.16 |
switch case 문안에 변수나 클래스를 초기화 하고자 할때.. (0) | 2009.11.25 |
[원문] http://northwind.springnote.com/pages/69967 northwind 님의 노트중에서 발췌
Compiler Options |
의미 |
/W4 |
Warning Level을 최대로 하여 컴파일 ( 모든 빌드 타입에 가능 ) |
/D "_DEBUG" |
Assetion, Trace 같은 디버깅용 코드가 컴파일시 포함되록 만든다. ( 디버그 빌드에서만 ) |
/GZ |
생성시에 초기화 되지 않는 변수를 특정 값으로 채워 흔히 디버그에서는 나타나지 않고 릴리즈 빌드에서 나타나는 에러를 사전에 검사할 수 있게 하여 디버그에 도움이 되게 함. ( 디버그 빌드에서만) |
/Od |
최적화하지 않는다. 코드를 디버그에 적합하게 만든다. ( 디버그 빌드에서만 ) |
/GF |
실행 파일에 들어갈 스트링이 중복될 경우 이를 제거, 공동으로 사용되는 이 스트링이 할당된 메모리를 읽기 전용으로 설정하여 우발적인 메모리 쓰임으로 부터 보호함. ( 정적 문자열.. )
char *s = "This is a character buffer"; char *t = "This is a character buffer";
위와 같은 경우 같은 스트링이므로 스트링을 서로 공유 함. ( 릴리즈 모드에서 명시적으로 사용시 ) |
/Gf |
실행파일에 들어갈 스트링을 공유하는 것은 위와 같으나 우발적인 메모리 쓰임으로 부터 보호 하지 않음. |
/ZI |
디버깅 심벌용 프로그램 데이터베이스를 만듬. 디버그로 실행시에 코드를 편집후 연속해서 디버깅이 가능하게 정보를 관리. ( 디버그 빌드에서만 ) |
/Zi |
디버깅 심벌용 프로그램 데이터베이스를 만듬. ( 릴리즈 빌드에서만 ) |
Linker Options |
의미 |
/MDd, /MLd, /MTd |
디버그 런타임 라이브러리 사용. |
/Od |
최적화하지 않는다. |
/D "_DEBUG" |
디버그용 코드가 컴파일 되게 한다. |
/ZI |
편집, 연속 디버깅이 가능하게 디버그용 데이터배이스를 만듬. |
/GZ |
디버그 빌드에서의 흔한 실수로 릴리즈에서 나타나는 에러를 디버그모드에서 검출. |
/Gm |
빌드 시간을 재빌드시에 감축시키기. |
Linker Options |
의미 |
/MD, /ML, /MT |
릴리즈 런타임 라이브러리 사용. |
/O1 or /O2 |
속도 최적화나 사이즈 작게 최적화 같은 것을 가능하게. |
/D "NDEBUG" |
디버그용 코드가 컴파일되지 않게 함. |
/GF |
중복된 문자열을 방지, 읽기 전용으로 데이터를 보호함. |
설정을 변경하면 디버깅은 잘되나 배포판을 만들 경우에는 변경된 옵션을 환원하고 빌드하자.
자주 써야 할 경우 빌드 타입을 하나 더 만들어서 사용하는 것도 한가지 방법이다.
vs 6.0 기준
vs .net 기준
Register값은 “Registers" 윈도우에서 확인이 가능하지만 단순하고 값만을 알수 있다. 이 값들을 ”Address(Watch)" 박스에서도 확인이 가능하며 여러 부가 기능과 같이 쓸수 있다.
예를 들어 EAX의 값을 확인 해볼려고 하면 Watch 항목에 “@EAX"혹은 ”@eax"와 같이 대소문자를 구분하지 않고 넣으면 이 래지스터의 값을 확인 할 수 있다.
또한 Pseudo-register"의 값또한 확인 할수 있는데. "@ERR"의 Pseudo-register 값은 매우 유용하게 사용할 수 있는데 이 값이GetLastError의 값을 나타내기 때문이다. 만약 “@ERR,hr"이라고 입력한다면 Win32의 에러코드에 해당하는 택스트를 보여 줄것이다.
Pseudo-register |
의미 |
@ERR |
GetLastError API로 알 수 있는 가장 최근에 반환된 에러 코드를 보여줌 |
@CLK |
누적시간(MicroSecond)을 보여줌. |
@TIB |
TIB의 주소를 보여줌. |
Register |
사용(용도) |
@EAX |
일반 용도, 함수의 return 값으로 사용 |
@EBX |
일반 용도 |
@ECX |
일반 용도, 오브젝트의 this 포인터로 사용. |
@EDX |
일반 용도, 64비트의 return값의 경우 상위 값의 반환에 사용. |
@ESI |
메모리 이동과 비교 연산시의 원본 메모리 |
@EDI |
메모리 이동과 비교 연산시에 대상 메모리 |
@EIP |
명령 포인터 ( 코드의 현제 위치 ) |
@ESP |
스텍 포인터 ( 스텍의 현제 위치 ) |
@EBP |
스텍 배이스 포인터 ( 현제 스텍 프레임의 바닥 ) |
@EFL |
비교나 수학 연산을 위한 플래그 비트 |
@CS |
Code segment |
@SS |
Stack segment |
@DS |
Data segment |
@ES |
Extra segment |
@FS |
Another extra segment, used to point to the TIB |
@GS |
Yet another extra segment |
Watch 윈도우는 변수의 값을 볼수 있게 해주는데, 값을 십진수나 16진수로서 확인할 수 있다. 16진수는 팝업 메뉴에서 “Hexadecimal Display"를 선택하면 볼수 있다. 이 이외에도 여러 가지 옵션을 주어서 사용할 수 있는데 이들은 Watch Window에 등록되는 변수명 뒤에 ","를 삽입하고 그뒤에 옵션을 주어 사용할 수 있다.
Symbol |
Format |
Example |
Output |
d, i |
부호있는 10진 정수 |
-42,d |
-42 |
u |
부호없는 10진 정수 |
42,u |
42 |
o |
부호없는 8진 정수 |
42,o |
052 |
x |
16진 정수 |
42,x |
0x0000002a |
X |
16진 정수 |
42,X |
0x0000002A |
h |
Short prefix for d,i,u,o,x |
42,hx |
0x002a |
f |
실수 |
1.5,f |
1.500000 |
e |
부호 있는 과학용 표기 |
1.5,e |
1.500000e+000 |
g |
Compact float |
1.5,g |
1.5 |
c |
문자 |
42,c |
'*' |
s |
ANSI 문자열 |
"bugs",s |
"bugs" |
su |
UNICODE 문자열 |
"bugs",su |
L"bugs" |
st |
기본 문자열형 ( s, su중에서 ) |
"bugs",st |
"bugs" |
hr |
HRESULT, Win32 error code |
0x06,hr |
The handle is invaid |
wm |
Wndows message number |
0x01,wm |
WM_CREATE |
[digits] |
배열 |
s,5 |
배열 5개의 항목 표시 |
Byte Pattern |
의미 |
0xCCCCCCCC |
초기화 되지 않은 stack 메모리 |
0xCDCDCDCD |
초기화 되지 않은 heap 메모리 |
0xDDDDDDDD |
힙에서 해지된 메모리 영역 |
0xFDFDFDFD |
힙에 할당된 메모리 블록 양쪽 4byte의 공간 마킹 |
0xABABABAB |
LocalAlloc()로 할당된 메모리 |
0xBAADF00D |
LocalAlloc(LMEM_FIXED, …)로 할당된 메모리 |
0xFEEEFEEE |
HeapFree()로 해지된 상태 |
가끔 오류가 발생했을 경우에 만날수 있는 magic number. ( 디버깅 모드에서만 byte pattern 으로 마킹됨. )
mfc 프로젝트에서는 DEBUG_NEW 가 기본적으로 제공되므로 메모리 릭을 검출하기가 용의하다. 하지만 일반 프로젝트에서는 추가적인 설정이 필요하다.
// CRT's memory leak detection
#if !defined(_AFXDLL)
#include <windows.h>
#include <crtdbg.h>
#if defined(DEBUG) | defined(_DEBUG)
#if !defined(DEBUG_NEW)
#define DEBUG_NEW new(_CLIENT_BLOCK, __FILE__, __LINE__)
#endif
#endif
#endif
위와 같은 코드를 기초 인클루드 파일에 추가하면 된다. ( 예를 들어 StdAfx.h 와 같은 곳에.. )
그리고 아랫 내용을 cpp 파일의 상단(인클루드 아랫 부분)에 추가하면 된다.
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
그리고
{
위와 같이 App 최초 구동시 메모리 릭 검출 디버깅 옵션을 켜준다.
그러면 디버그 모드로 실행 했을 경우 App 종료시 output 창에 메모리 릭 발생시 메모리 릭 정보가 해당 소스 파일과 라인등 정보와 함께 출력되는 것을 볼수 있을 것이다.
int stat = _controlfp(0, 0);
stat &= ~(EM_ZERODIVIDE);
_controlfp(stat, MCW_EM);
와 같이 EM_ZERODIVIDE 옵션을 추가하였다면 0으로 나눌 경우 해당 코드 부분에서 exception이 발생하므로 발생 부분을 즉시 확인할 수 있는 효과가 있다. 기타 다른 옵션은 MSDN 에서 _controlfp를 찾아서 확인하자.
|
Value |
Hex |
Signed 32-Bit Int |
Name |
-1.#QNAN |
FFFFFFFF ~ FF800001 |
-1 ~ -8388607 |
Negative NaNs |
-1.#INF |
FF800000 |
-8388608 |
-∞ |
0 |
|
|
|
0 |
|
|
|
+1.#INF |
|
|
+∞ |
+1.#QNAN |
7F800001 ~ 7FFFFFFF |
2139095041 ~ 2147483647 |
Positive NaNs |
*, 1.#QNAN 의 경우 1.#INF ( 무한대의 값 ) 으로 연산시에 발생함.
순수 가상 함수를 파괴자 등에서 호출하여 생기는 오류 검출 방법.
위의 함수를 사용하여 순수 가상 함수 호출시 임의의 오류 처리 함수를 호출하도록 하여 해당 부분을 검출해낼수 있다.
아래와 같이 설정하였다면 순수 가상 함수가 호출되는 순간 assert 가 호출되므로 해당 부분의 call-stack 을 확인해보자.
{
{
[펌]C언어: OpenMP를 이용한 멀티 쓰레드 프로그래밍 HOWTO (0) | 2009.12.23 |
---|---|
switch case 문안에 변수나 클래스를 초기화 하고자 할때.. (0) | 2009.11.25 |
YOKOGAWA PLC 통신 방법 (0) | 2009.08.28 |
• 멤버 변수
+ float x, + float y : 좌표 (x, y)
• 메소드
+ CxPoint2()
+ CxPoint2(IN float const x_, IN float const y_)
+ CxPoint2(IN CxPoint2 const &p) : 생성자. 디폴트 좌표는 (0, 0)이다.
+ float Distance(IN CxPoint2 const p2) : 현재 점과 점 p2 사이의 거리를 반환한다.
+ float Distance(IN float const x_, IN float const y_) : 현재 점과 점 (x, y) 사이의 거리를 반환한다.
• 멤버 변수
+ CxPoint2 botLeft : 좌하단 좌표
+ CxPoint2 topRight : 우상단 좌표
• 메소드
+ CxRect2()
+ CxRect2(IN float const x1_, IN float const y1_, IN float const x2_, IN float const y2_)
+ CxRect2(IN CxPoint2 const &bl, IN CxPoint2 const &tr)
+ CxRect2(IN CxRect2 const &p) : 생성자. 디폴트값은 없다.
+ float Surface() const : 사각형의 면적을 반환한다. 방향에 따라 음수가 반활 될 수도 있다.
+ CxRect2 CrossSection(IN CxRect2 const &r2) const : 현재 사각형과 사각형 r2가 겹치는 부분의 사각형을 반환한다. 없다면 CxRect2(0,0,0,0)을 반환.
+ CxPoint2 Center() const : 사각형의 중심의 좌표를 반환한다.
+ float Width() : 사각형의 가로의 길이를 반환한다.
+ float Height() : 사각형의 세로의 길이를 반환한다.
파일 입출력을 위한 클래스이다.
• 멤버 변수
# FILE *m_fp : 파일 포인터를 멤버 변수로 가진다. 디폴트값은 NULL이다.
# bool m_bCloseFile : 이 클래스에서 항상 true.
• 메소드
+ CxIOFile(IN FILE* fp = NULL) : 생성자. 파일 포인터를 인수로 넘겨받을 수 있다. 인수를 생략하면 파일 포인터는 NULL로 초기화 된다.
+ bool Open(IN const char *filename, IN const char *mode) : 파일명과 열기 모드를 지정하여 파일을 연다. 한 번 Open()한 뒤 다시 Open()하려면 먼저 Close() 메소드를 수행하여야 한다.
+ bool Close() : 파일이 열려있다면 파일을 닫는다.
+ size_t Read(IN OUT void *buffer, IN size_t size, IN size_t count) : buffer는 파일로부터 입력받은 데이터가 저장될 버퍼의 시작 주소, size는 입력 단위체의 크기, count는 입력받은 단위체의 개수이다. 실제로 입력받은 단위체의 개수를 반환한다.
+ size_t Write(IN const void *buffer, IN size_t size, IN size_t count) : buffer는 출력할 데이터의 시작 주소, size는 출력 단위체의 크기, count는 출력할 단위체의 개수이다. 실제로 출력한 단위체의 개수를 반환한다.
+ bool Seek(IN long offset, IN int origin) : 파일포인터를 (origin +offset) 위치로 이동시킨다. 성공 여부를 반환한다.
+ long Tell() : 현재 파일 포인터가 파일의 시작 위치로부터 몇 바이트 떨어져 있는지 반환한다. ( ftell() 사용 )
+ long Size() : 파일의 크기를 반환한다.
+ bool Flush() : 입출력 스트림을 비운다. 즉 파일의 읽기 쓰기 작업을 완료시킨다. ( fflush() 사용 )
+ bool Eof() : 파일 포인터가 파일의 맨 끝에 있으면 true를 반환한다.
+ long Error() : 파일을 읽을 수 있으면 0을 반환한다.
+ bool PutC(IN unsigned char c) : 파일 포인터가 가리키고 있는 곳에 한 문자를 기록한다. 성공 여부가 리턴 된다. 파일 포인터가 1증가 한다.
+ long GetC() : 파일 포인터가 가리키고 있는 곳의 한 문자를 읽어서 반환한다. 파일 포인터가 1증가 한다.
• 멤버 변수
# BYTE *m_pBuffer : 데이터가 저장될 버퍼
# DWORD m_size : 저장된 데이터의 크기.
# bool m_bFreeOnClose : Close()호출시 메모리가 해제된다면 true. GetBuffer()를 호출하면 버퍼에 대한 제어를 메소드를 호출한 쪽으로 넘기므로 메모리 해제도 그 곳에서 해야 한다.
# long m_Position : 파일 포인터의 역할.
# long m_Edge : 버퍼의 크기.
• 메소드
+ CxMemFile(IN BYTE *pBuffer = NULL, IN DWORD size = 0) : 생성자. 메모리를 미리 할당하여 인수로 넘겨 줄 수 있다. pBuffer를 넘겨주면서 size를 비워두어도 에러가 발생하지 않으므로 주의한다. ( 다형성을 이용하여 해결해도 된다 )
+ bool Close() : 파일을 닫는다. 즉 메모리를 반환한다.
+ bool Open() : 파일을 연다. 다시 열기 위해선 먼저 Close()를 사용하여야 한다.
+ BYTE* GetBuffer(IN bool bDetachBuffer = true) : 버퍼의 포인터를 반환한다. bDatachBuffer의 값이 true이면 Close()메소드가 동작하지 않게 된다.
+ size_t Read(IN OUT void *buffer, IN size_t size, IN size_t count) : buffer는 파일로부터 입력받은 데이터가 저장될 버퍼의 시작 주소, size는 입력 단위체의 크기, count는 입력받은 단위체의 개수이다. 실제로 입력받은 단위체의 개수를 반환한다.
+ size_t Write(IN const void *buffer, IN size_t size, IN size_t count) : buffer는 출력할 데이터의 시작 주소, size는 출력 단위체의 크기, count는 출력할 단위체의 개수이다. 실제로 출력한 단위체의 개수를 반환한다. 출력할 내용이 버퍼의 경계를 벗어나면 메모리 재할당이 일어난다.
+ bool Seek(IN long offset, IN int origin) : 파일포인터를 (origin +offset) 위치로 이동시킨다. 성공 여부를 반환한다.
+ long Tell() : 현재 파일 포인터가 파일의 시작 위치로부터 몇 바이트 떨어져 있는지 반환한다.
+ long Size() : 파일의 크기를 반환한다.
+ bool Flush() : 아무런 동작도 하지 않는다. ( 메모리에서는 필요 없다 )
+ bool Eof() : 파일 포인터가 파일의 맨 끝에 있으면 true를 반환한다.
+ long Error() : 파일을 읽을 수 있으면 0을 반환한다.
+ bool PutC(IN unsigned char c) : 파일 포인터가 가리키고 있는 곳에 한 문자를 기록한다. 성공 여부가 리턴 된다. 버퍼의 경계를 넘어서면 메모리 재할당이 이루어진다. 파일 포인터가 1증가 한다.
+ long GetC() : 파일 포인터가 가리키고 있는 곳의 한 문자를 읽어서 반환한다. 파일 포인터가 1증가 한다.
+ void Alloc(IN DWORD dwNewLen) : 최소 dwNewLen 바이트만큼의 메모리를 할당 한다. 이미 메모리가 할당 되어있다면 재할당이 일어 날 수 있다.
+ void Free() : Close()를 호출한다.
• 구조체
ꋺ rgb_color
* BYTE r, g, b : RGB 색상.
ꋺ tagCxImageInfo
* DWORD wEffWidth: 4의 배수로 정렬된 한 스캔 라인의 길이.
* BYTE* pImage: 이미지 데이터가 저장된 공간의 시작 주소
* CxImage* pGhost : 현재 이미지가 고스트 이미지라면 본래의 이미지를 가리킨다.
* CxImage* pParent : 현재 이미지가 레이어라면 부모가 되는 이미지를 가리킨다.
* DWORD dwType : 처음 로드한 이미지의 포맷
* char szLastError[256] : 마지막으로 발생한 에러
* long nProgress : 이미지에 대한 처리의 진행률.
* long nEscape : -1이면 이미지에 대한 처리가 강제로 종료된다.
* long nBkgndIndex
: 팔레트를 사용하는 이미지에서 투명색의 인덱스 번호. GIF, PNG, MNG에서 사용한다. -1이면 투명효과를 사용하지 않는다.
* RGBQUAD nBkgndColor : 24비트 이미지의 투명색.
* BYTE nQuality : JPG에서 이미지의 품질.
* BYTE nJpegScale : JPG 이미지를 읽어 들일 때 확대/축소 비율
* long nFrame : GIF, TIF에서 현재 이미지의 프레임 번호.
* long nNumFrames : GIF, TIF에서 전체 프레임의 개수.
* DWORD dwFrameDelay : GIF에서 현재 프레임의 딜레이.
* long xDPI : PNG의 x축 해상도.
* long yDPI : PNG의 y축 해상도.
* RECT rSelectionBox : 선택 영역.
* BYTE nAlphaMax : 불투명도 최대값.
* bool bAlphaPaletteEnabled : 알파 팔레트 사용 여부.
* bool bEnabled : 이미지의 출력 가능 여부.
* long xOffset : 이미지가 화면에 출력될 때의 시작점의 x좌표.
* long yOffset : 이미지가 화면에 출력될 때의 시작점의 y좌표.
* DWORD dwCodecOpt[CMAX_IMAGE_FORMATS] : for GIF, TIF : 0=def.1=unc,2=fax3,3=fax4,4=pack,5=jpg
* RGBQUAD last_c
: GetNearestIndex()에서 사용. 마지막으로 처리된 픽셀의 색상 정보.
* BYTE last_c_index
: GetNearestIndex()에서 사용. 마지막으로 처리된 픽셀의 색상 인덱스.
* bool last_c_isvalid
: GetNearestIndex()에서 사용. 픽셀이 하나라도 처리되었다면 true.
* long nNumLayers
: 전체 레이어의 개수.
* DWORD dwFlags
: 0x??00000 = reserved, 0x00??0000 = blend mode, 0x0000???? = layer id - user flags
ꋺ tagCxTextInfo
* TCHAR text[4096]
: 출력될 문자열.
* LOGFONT lfont
: 글꼴 정보
* COLORREF. fcolor
: 전경색.
* long align
: 멀티라인 텍스트를 위한 정렬 방식. DT_CENTER, DT_RIGHT, DT_LEFT
* BYTE opaque
: 배경을 가지면 true.
* COLORREF bcolor
: 배경색.
* float b_opacity
: 불투명도. 0.0 ~ 1.0. 디폴트는 0.
* BYTE b_outline
: 배경의 외곽선.
* BYTE b_round
: 배경의 외곽선 두께.
• 멤버 변수
# void *pDib
: 이미지 비트맵 정보의 시작 주소. ( 헤더 + 이미지 데이터 + 팔레트 )
# BITMAPINFOHEADER head
: 비트맵 이미지의 헤더
# CXIMAGEINFO info
: CxImage의 헤더
# BYTE *pSelection
: 선택된 영역. 원래 이미지와 크기가 같은 마스크.
# BYTE *pAlpha
: 알파 채널
# CxImage **pLayers
: 레이어 리스트에 대한 포인터.
• 메소드
# void AddAveragingCont(IN RGBQUAD const &color, IN float const surf, OUT float &rr, OUT float &gg, OUT float &bb, OUT float &aa)
: GetAreaColorInterpolated()에서 사용 된다.
+ void AlphaClear()
: 알파 채널 이미지의 값을 모두 0으로 만든다.
+ bool AlphaCopy(IN CxImage &from)
: 기존의 이미지 from으로부터 알파 채널 이미지를 복사해 온다.
+ void AlphaCreate()
: 알파 채널 이미지가 없다면 255로 초기화된 새로운 알파 채널 이미지를 생성한다.
+ void AlphaDelete()
: 알파 채널 이미지를 지운다. 할당된 메모리를 해제 한다.
+ bool AlphaFlip()
: 알파 채널 이미지를 상하로 뒤집는다.
+ BYTE AlphaGet(IN const long x, IN const long y)
: 알파 채널 이미지에서 지정한 좌표의 알파값을 반환한다.
+ BYTE AlphaGetMax() const
: 지정되어 있는 알파값의 최대치를 가져온다.
+ BYTE* AlphaGetPointer(IN const long x = 0, IN const long y = 0)
: 알파 채널 이미지에서 지정한 좌표의 알파값에 대한 포인터를 가져온다.
+ void AlphaInvert()
: 알파 채널 이미지의 값을 반전시킨다.
+ bool AlphaIsValid()
: 이미지가 알파 채널 이미지를 가지고 있다면 true를 반환한다.
+ bool AlphaMirror()
: 알파 채널 이미지를 좌우로 뒤집는다.
+ void AlphaPaletteClear()
: 팔레트의 알파값을 모두 0으로 만든다.
+ void AlphaPaletteEnable(IN bool enable = true)
: 팔레트의 알파값에 대한 사용 여부를 지정.
+ bool AlphaPaletteIsEnabled()
: 팔레트의 알파값을 사용할 수 있다면 true를 반환한다.
+ bool AlphaPaletteIsValid()
: 팔레트 색상 중에서 불투명한 것이 하나라도 있으면 true를 반환 한다.
+ bool AlphaPaletteSplit(OUT CxImage *dest)
: 현재 이미지의 알파값을 8비트 그레이 스캐일 이미지로 내보낸다.
+ void AlphaSet(IN const long x, IN const long y, IN const BYTE level)
: 지정한 좌표의 알파값을 level로 만든다.
+ void AlphaSet(IN BYTE level)
: 알파 채널 이미지의 모든 알파값을 level로 채운다.
+ bool AlphaSet(IN CxImage &from)
: from 이미지로부터 알파 채널 이미지를 현재 이미지로 복사해 온다.
+ void AlphaSetMax(IN BYTE nAlphaMax)
: 알파값의 최대치를 지정한다.
+ bool AlphaSplit(OUT CxImage *dest)
: 현재 이미지의 알파 채널 이미지를 8비트 그레이 스캐일 이미지로 내보낸다.
+ void AlphaStrip()
: 알파 채널 이미지와 현재 이미지를 결합하여 하나의 24비트 이미지를 만든다. 현재 이미지가 24비트이미지가 아니었다면 24비트 이미지로 변환된다.
# void Bitfield2RGB(IN BYTE *src, IN WORD redmask, IN WORD greenmask, IN WORD bluemask, IN BYTE bpp)
: 16또는 32비트 이미지가 담긴 버퍼로부터 RGB이미지를 읽어온다.
+ void BlendPalette(IN COLORREF cr, IN long perc)
: 팔레트의 모든 색상에 cr색상을 perc %만큼 섞어준다.
+ void BlendPixelColor(IN long x, IN long y, IN RGBQUAD c, IN float blend, IN bool IN bSetAlpha = false)
: 지정한 위치의 색상에 c색상을 blend만큼 섞어준다.
blend : 섞는 비율. 유효 범위 : 0.0 ~ 1.0
bSetAlpha : true이면 c의 알파값도 지정한 위치에 넣어준다.
# BYTE BlindAlphaGet(IN const long x, IN const long y)
: 지정한 위치의 알파값을 가져온다. 디버그모드에서만 좌표의 유효성을 검사한다.
# RGBQUAD BlindGetPixelColor(IN const long x, IN const long y)
: 지정한 좌표의 색상값을 반환한다. 실패하면 투명색 또는 검정색을 반환한다. 디버그모드 에서만 좌표의 유효성을 검사한다.
# BYTE BlindGetPixelIndex(IN const long x, IN const long y)
: 지정한 좌표의 팔레트 인덱스 값을 반환한다. 디버그모드 에서만 좌표의 유효성을 검사한다.
# void* BlindGetPixelPointer(IN const long x, IN const long y)
: 지정한 좌표의 픽셀 포인터를 반환한다. 24비트 이미지에서만 사용할 수 있다.
+ long Blt(IN HDC pDC, IN long x=0, IN long y=0)
: 이미지를 출력한다. CXIMAGE_SUPPORT_WINCE가 정의되어 있어야 한다.
# void blur_line (IN float *ctable, IN float *cmatrix, IN int cmatrix_length, IN BYTE *cur_col, OUT BYTE *dest_col, IN int y, IN long bytes)
: UnsharpMask()에서 사용 된다.
+ bool CircleTransform(IN int type, IN long rmax = 0, IN float Koeff = 1.0f)
: 이미지를 원에 기초하여 변환한다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
type : 변환의 종류
0 : normal FishEye.
1 : reverse FishEye
2 : 나선형
3 : 실린더 미러
4 : 욕실 유리 효과
rmax : 효과가 적용될 반지름. 0이면 이미지 전체에 적용.
Koeff : 값이 클수록 회전각이 작아진다. 값이 클수록 더 적게 회전.
+ void Clear(IN BYTE bval = 0)
: 이미지를 지정한 비트로 채운다. 팔레트 이미지라면 bval은 팔레트의 인덱스가 된다.
+ bool Colorize(IN BYTE hue, IN BYTE sat, IN float blend = 1.0f)
: 본래의 색조와 채도를 지정한 값으로 대체한다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
blend : 0 ~ 1. 0이면 효과 없음. 1이면 최대 효과.
+ bool Combine(IN CxImage *r, IN CxImage *g, IN CxImage *b,CxImage* a, IN long colorspace = 0)
: 서로 다른 8비트 채널 이미지를 합쳐서 하나의 이미지를 만든다.
colorspace : 색공간. 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ
# int CompareColors(IN const void *elem1, IN const void *elem2)
: elem1의 명도에서 elem2의 명도를 뺀 값을 반환한다.
+ bool Contour()
: 인접한 픽셀과의 색상차를 더욱 크게 한다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ void Copy(IN const CxImage &src, IN bool copypixels = true, IN bool copyselection = true, IN bool copyalpha = true)
: 기존의 이미지 src로부터 이미지를 복사해 온다.
copypixels : 이미지 데이터를 복사한다.
copyselection : 선택영역 정보를 복사한다.
copyalpha : 알파채널을 복사한다.
# void CopyInfo(IN const CxImage &src)
: 기존의 이미지 src로부터 이미지의 정보를(CXIMAGEINFO) 복사해온다.
+ HANDLE CopyToHandle()
: 현재 이미지를 클립보드로 복사한다.
+ void* Create(IN DWORD dwWidth, IN DWORD dwHeight, IN DWORD wBpp, IN DWORD imagetype = 0)
: 이미지를 초기화하거나 기존 이미지를 제거하고 새로운 이미지를 만든다. 이미지의 크기에 맞는 버퍼도 할당된다.
+ bool CreateFromArray(IN BYTE *pArray, IN DWORD dwWidth, IN DWORD dwHeight, IN DWORD dwBitsperpixel, IN DWORD dwBytesperline, IN bool bFlipImage)
: 메모리 버퍼에 저장된 이미지로부터 이미지를 생성한다.
bFlipImage : 이미지가 뒤집혀져 있다면 true를 넣어 준다.
+ bool CreateFromHANDLE(IN HANDLE hMem)
: 클립보드로부터 새로운 이미지를 생성한다. 클립보드 이미지의 포맷은 반드시 CF_DIB 이어야 한다. 즉, BITMAPINFO 구조체를 가지고 있어야 한다.
+ bool CreateFromHBITMAP(IN HBITMAP hbmp, IN HPALETTE hpal = 0)
: 비트맵 리소스를 이용하여 이미지를 생성한다. 팔레트를 지정하면 그 팔레트를 사용하는 이미지를 만들게 된다.
+ bool CreateFromHICON(IN HICON hico)
: 아이콘 리소스를 이용하여 이미지를 생성한다.
+ bool CreateFromMatrix(IN BYTE **ppMatrix, IN DWORD dwWidth, IN DWORD dwHeight, IN DWORD dwBitsperpixel, IN DWORD dwBytesperline, IN bool bFlipImage)
: 배열에 저장된 DDB이미지를 지정한 인수에 따라 DIB이미지로 변환하여 이미지를 생성한다.
dwBitsperpixel : 픽셀당 비트수. 1, 4, 8, 24, 32 중에서 한 가지가 가능하다.
dwBytesperline : 한 스캔라인당 바이트수
dwFlipImage : true이면 이미지를 뒤집어서 생성한다.
+ bool Crop(IN const RECT& rect, OUT CxImage *iDst = NULL)
: 현재 이미지에서 지정한 영역만큼을 자른 뒤 그 이미지를 현재 이미지로 대체한다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
+ bool Crop(IN long left, IN long top, IN long right, IN long bottom, OUT CxImage *iDst = NULL)
: 현재 이미지에서 지정한 영역만큼을 자른 뒤 그 이미지를 현재 이미지로 대체한다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
+ bool CropRotatedRectangle(IN long topx, IN long topy, IN long width, IN long height, IN float angle, OUT CxImage *iDst = NULL)
: 자르는 영역에 회전을 준다. 나머지는 Crop()과 동일한 기능을 수행한다.
topx : 위 쪽의 두 점 중 왼쪽 점의 x값
topy : 위 쪽의 두 점 중 왼쪽 점의 y값
width : 선택영역의 너비
height : 선택영역의 높이
angle : 사각형의 회전각. 라디안을 사용한다.
iDst : Crop()과 동일
+ CxImage(IN DWORD imagetype = 0)
: Startup()만을 호출한다.
+ CxImage(IN CxFile *stream, IN DWORD imagetype)
: CxFile 객체를 이용하여 이미지를 로드한다.
+ CxImage(IN BYTE *buffer, IN DWORD size, IN DWORD imagetype)
: 버퍼에서 이미지를 가져온다. 버퍼는 CxMemFile 객체를 이용하여 파일 형태로 취급된다.
+ CxImage(IN DWORD dwWidth, IN DWORD dwHeight, IN DWORD wBpp, IN DWORD imagetype = 0)
: 이미지의 크기와 화소당 비트수(1, 4, 8, 24)를 지정하여 생성한다.
+ CxImage(IN const CxImage &src, IN bool copypixels = true, IN bool copyselection = true, IN bool copyalpha = true)
: 기존 이미지에서 새로운 이미지를 생성한다.
copypixels : 비트맵정보를 복사한다.
copyselection : 선택 영역의 데이터를 복사한다.
copyalpha : 알파 채널을 복사한다.
+ CxImage(IN const TCHAR *filename, IN DWORD imagetype)
: 파일로부터 이미지를 로드한다.
+ CxImage(IN FILE *stream, IN DWORD imagetype)
: 파일 핸들을 이용하여 이미지를 로드한다.
+ bool Decode(IN BYTE *buffer, IN DWORD size, IN DWORD imagetype)
: 메모리 버퍼로부터 파일을 읽어 들인다. 버퍼를 CxMemFile 객체를 이용하여 파일로 취급한다.
+ bool Decode(IN CxFile *hFile, IN DWORD imagetype)
: CxFile객체로부터 이미지를 읽어 들인다. 실제로 이미지를 읽어 들이는 메소드이다.
+ bool Decode(IN FILE *hFile, IN DWORD imagetype)
: 파일 핸들을 이용하여 이미지를 로드 한다. CxIOFile 객체를 이용한다.
+ bool DecreaseBpp(IN DWORD nbit, IN bool errordiffusion, IN RGBQUAD *ppal = 0, IN DWORD clrimportant = 0)
: 픽셀당 비트수를 nbit로 감소시킨다.
errordiffusion : true이면 에러디퓨전 디더링을 이용하여 화질을 향상시킨다.
ppal : 최종 이미지에서 사용될 팔레트. 지정하지 않으면 표준 팔레트가 사용된다.
clrimportant : 최종 이미지의 biClrImportant 값을 지정. 디폴트값은 0이다.
+ bool Destroy()
: 고스트 이미지가 아니라면 현재 할당된 메모리를 모두 해제한다. 고스트 이미지는 실제 이미지 데이터를 가진 객체를 가리키고 있을 뿐이므로 메모리를 해제할 필요가 없다. 모든 메모리가 해제되었다면 true를 반환하고 고스트이미지라면 false를 반환한다.
# bool DFT(IN int dir, IN long m, IN double *x1, IN double *y1, IN double *x2, IN double *y2)
: 이산 퓨리에 변환. x와 y는 2^m 개의 점을 가진 복소수 배열.
dir : 1이면 정변환, -1이면 역변환.
+ bool Dilate(IN long Ksize = 2)
: 이미지의 밝은 영역을 확장한다. Ksize는 커널(마스크)의 사이즈. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ bool Dither(IN long method = 0)
: 지정한 방식에 따라 이미지를 흑백으로 변환한다.
0 = Floyd-Steinberg
1 = Ordered-Dithering (4x4)
2 = Burkes
3 = Stucki
4 = Jarvis-Judice-Ninke
5 = Sierra
6 = Stevenson-Arce
7 = Bayer (4x4 ordered dithering)
+ long Draw(IN HDC hdc, IN const RECT& rect, IN RECT *pClipRect = NULL, IN bool bSmooth = false)
: hdc를 이용하여 이미지를 화면에 출력한다. pClipRect를 지정하면 화면의 해당영역에만 이미지가 출력된다. 알파 채널, 알파 팔레트, 투명색, 불투명도를 지원한다.
+ long Draw(IN HDC hdc, IN long x = 0, IN long y = 0, IN long cx = -1, IN long cy = -1, IN RECT* pClipRect = 0, IN bool bSmooth = false)
: hdc를 이용하여 이미지를 화면에 출력한다. pClipRect를 지정하면 화면의 해당영역에만 이미지가 출력된다. 알파 채널, 알파 팔레트, 투명색, 불투명도를 지원한다.
+ long Draw2(IN HDC hdc, IN long x = 0, IN long y = 0, IN long cx = -1, IN long cy = -1)
: hdc를 이용하여 이미지를 화면에 출력한다. pClipRect를 지정하면 화면의 해당영역에만 이미지가 출력된다. 투명색만 지원한다.
+ long Draw2(IN HDC hdc, IN const RECT &rect)
: hdc를 이용하여 이미지를 화면에 출력한다. pClipRect를 지정하면 화면의 해당영역에만 이미지가 출력된다. 투명색만 지원한다.
+ void DrawLine(IN int StartX, IN int EndX, IN int StartY, IN int EndY, IN COLORREF cr)
: 브레즌햄 알고리즘을 이용하여 이미지에 선을 그린다.
+ void DrawLine(IN int StartX, IN int EndX, IN int StartY, IN int EndY, IN RGBQUAD color, IN bool bSetAlpha = false)
: 브레즌햄 알고리즘을 이용하여 이미지에 선을 그린다.
+ long DrawString(IN HDC hdc, IN long x, IN long y, IN const TCHAR *text, IN RGBQUAD color, IN const TCHAR *font, IN long lSize = 0, IN long lWeight = 400, IN BYTE bItalic = 0, IN BYTE bUnderline = 0, IN bool bSetAlpha = false)
: 이미지에 문자열을 출력한다.
+ long DrawStringEx(IN HDC hdc, IN long x, IN long y, IN CXTEXTINFO *pTextType, IN bool bSetAlpha = false );
: 이미지에 문자열을 출력한다.
+ bool Edge(IN long Ksize = 2)
: 픽셀간의 색상차이를 강조한다. 경계선이 나타난다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ void Enable(IN bool enable = true)
: 이미지의 출력 가능/불가능을 지정한다.
+ bool Encode(OUT CxFile *hFile, IN CxImage **pImages, IN int pagecount, IN DWORD imagetype)
: 여러 장의 이미지를 TIFF나 GIF 포맷으로 디스크에 저장한다.
pImages : 이미지 리스트
pagecount : 이미지의 개수
+ bool Encode(OUT CxFile *hFile, IN DWORD imagetype)
: 이미지를 특정 포맷(imagetype)으로 디스크에 저장한다.
+ bool Encode(OUT FILE *hFile, IN CxImage **pImages, IN int pagecount, IN DWORD imagetype)
: 여러 장의 이미지를 TIFF나 GIF 포맷으로 디스크에 저장한다.
pImages : 이미지 리스트
pagecount : 이미지의 개수
+ bool Encode(OUT BYTE * &buffer, OUT long &size, IN DWORD imagetype)
: 이미지를 특정 포맷(imagetype)으로 메모리의 버퍼에 저장한다. buffer는 반드시 NULL 이어야 한다.
+ bool Encode(OUT FILE *hFile, IN DWORD imagetype)
: 이미지를 특정 포맷(imagetype)으로 디스크에 저장한다.
+ bool Encode2RGBA(OUT BYTE * &buffer, OUT long &size)
: 이미지를 RGBA 포맷으로 변환하여 버퍼로 내보낸다.
+ bool Encode2RGBA(OUT CxFile *hFile)
: 이미지를 RGBA 포맷으로 변환하여 파일로 내보낸다. 파일은 CxMemFile, CxIOFile 타입을 사용하여야 한다.
# bool EncodeSafeCheck(IN CxFile *hFile)
: 인코딩을 위한 준비가 되었는지 검사한다. 준비가 되지 않았다면 true를 반환한다.
+ bool Erode(IN long Ksize = 2)
: 이미지의 어두운 영역을 확장시킨다. 커널의 크기를 Ksize로 지정한다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ bool Expand(IN long newx, IN long newy, IN RGBQUAD canvascolor, OUT CxImage *iDst = 0)
: 캔버스의 크기를 확장시킨다. newx와 현재 이미지의 너비 차이만큼 좌우가 확장되고 newy와 현재 이미지의 높이 차이만큼 상하가 확장된다. 본래의 이미지는 확장된 캔버스의 중앙에 위치하게 된다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
newx : 현재 이미지의 너비 + 확장할 너비
newy : 현재 이미지의 높이 + 확장할 높이
canvascolor : 확장된 공간에 채워질 색상
+ bool Expand(long left, long top, long right, long bottom, RGBQUAD canvascolor, CxImage *iDst = 0)
: 캔버스의 크기를 확장시킨다. 상하좌우의 크기를 따로 지정할 수 있다. 새로 만들어진 영역의 색깔을 canvascolor로 지정할 수 있다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
# bool FFT(IN int dir, IN int m,double *x, IN double *y)
: 빠른 퓨리에 변환. x와 y는 2^m 개의 점을 가진 복소수 배열.
dir : 1이면 정변환, -1이면 역변환.
+ bool FFT2(CxImage *srcReal, CxImage *srcImag, CxImage *dstReal, CxImage *dstImag, long direction = 1, bool bForceFFT = true, bool bMagnitude = true)
:
+ bool Filter(IN long *kernel, IN long Ksize, IN long Kfactor, IN long Koffset)
: 2차원 선형 필터를 적용한다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
kernel : 선형 필터의 마스크를 1차원 행렬로 가진다.
Ksize : 마스크의 크기. 정방행렬이므로 행의 개수와 같다.
Kfactor : 마스크의 각 요소의 절대갑의 합.
Koffset : 마스크된 결과에 더해질 차이값.
예) 라플라시안 경계선 추출 필터
long kernel[] = {-1,-1,-1,-1,8,-1,-1,-1,-1}; Ksize = 3; Kfactor = 0, Koffset = 0
+ bool Flip()
: 이미지를 상하로 뒤집는다.
+ void FreeMemory(IN void* memblock)
: 메모리를 해제한다.
+ bool Gamma(IN float gamma)
: 색상 균형을 조절한다.
gamma : 0.1 ~ 5.0
# int gen_convolve_matrix (IN float radius, IN float **cmatrix_p)
: 2-패스 가우시안 필터의 각 패스에 사용될 1차원 컨볼루션 매트릭스를 생성한다.
# float* gen_lookup_table (IN float *cmatrix, IN int cmatrix_length)
: cmatrix를 이용하여 LUT를 만든다. 만들어진 LUT의 시작 주소를 반환한다.
+ RGBQUAD GetAreaColorInterpolated(IN float const xc, IN float const yc, IN float const w, IN float const h, IN InterpolationMethod const inMethod, IN OverflowMethod const ofMethod = OM_BACKGROUND, IN RGBQUAD *const rplColor = 0);
: 지정한 영역에서 보간한 색상을 반환한다.
inMethod : 보간 방식
IM_NEAREST_NEIGHBOUR : 가장 가까운 픽셀의 값을 반환한다.
IM_BILINEAR : 이웃한 4개의 픽셀을 이용하여 보간.
IM_BICUBIC : 인접한 16개의 픽셀을 이용하여 보간.
IM_BICUBIC2 : 인접한 16개의 픽셀을 이용하여 보간.
IM_BSPLINE : 인접한 16개의 픽셀을 이용하여 보간.
IM_LANCZOS : 인접한 12*12픽셀을 이용하여 보간.
ofMethod : 좌표를 계산하는 방식
OF_REAPET : 이미지의 경계를 벗어나면 클립 되어 경계선에 놓이게 된다.
OF_WRAP : 이미지의 크기를 단위크기로 한 상대 좌표에 놓이게 된다.
OF_MIRROR : 이미지의 경계선에 대하여 반사된 위치에 놓이게 된다.
OF_COLOR : rplColor이 정의 되었다면 rplColor을 반환하고 그렇지 않으면 투명한 흰색을 반환한다.
OF_BACKGROUND : 배경색을 반환한다.
OF_TRANSPARENT : 투명색을 반환한다.
rplColor : 입력 색상. 픽셀에 대한 계산이 수행되지 않았을 때 기본적으로 반환되는 색상이다.
+ BYTE* GetBits(IN DWORD row = 0)
: 이미지에서 지정한 행의 픽셀에 대한 포인터를 얻는다.
+ WORD GetBpp() const;
: 이미지의 비트 당 픽셀의 개수를 가져온다.
+ DWORD GetClrImportant() const;
: 팔레트의 색상 중 이미지를 표현하는데 필요한 색상의 수를 가져온다. SetClrImportant()로 지정된 값이 반환된다.
+ DWORD GetCodecOption(DWORD imagetype = 0);
: 이미지의 인코딩 옵션값을 가져온다.
+ BYTE GetColorType()
: 1 : 팔레트 컬러. 2 : RGB. 3 : RGBA
+ void* GetDIB() const
: 이미지가 저장된 영역의 시작 포인터를 반환.
+ DWORD GetEffWidth() const
: 이미지의 가로 너비를 반환한다.
+ long GetEscape() const
: 탈출 코드를 가져온다.
+ DWORD GetFlags() const
: SetFlags() 참조.
+ long GetFrame() const
: 현재 선택된 프레임의 번호를 가져온다.
+ DWORD GetFrameDelay() const
: GIF 포맷에서 현재 프레임의 딜레이를 가져온다. 밀리세컨드 단위이다.
+ DWORD GetHeight() const
: 이미지의 높이를 반환한다. 세로 픽셀의 개수.
+ BYTE GetJpegQuality() const
: Jpeg 이미지의 품질값을 가져온다.
+ BYTE GetJpegScale() const
: Jpeg 이미지의 스캐일값을 가져온다.
+ const char* GetLastError()
: 마지막으로 발생한 에러의 메시지 내용을 가져온다.
+ CxImage* GetLayer(IN long position)
: 지정한 위치의 레이어가 반환된다. position값이 0보다 작다면 마지막 레이어가 반환된다.
+ BYTE GetNearestIndex(IN RGBQUAD c)
: 팔레트에서 색상 c와 가장 가까운 색상의 인덱스값을 반환한다.
+ DWORD GetNumColors() const
: 이미지에서 사용되는 색상의 수를 가져온다. 0이면 24비트 이미지.
+ long GetNumFrames() const
: 파일에 포함된 이미지의 개수를 반환한다.
+ long GetNumLayers() const
: 객체에 직접적으로 할당되어 있는 레이어의 개수를 반환한다.
+ void GetOffset(IN long *x, IN long *y)
: 이미지의 오프셋 값을 반환한다. 오프셋은 이미지가 화면에 출력될 시작 좌표이다.
+ RGBQUAD* GetPalette() const
: 팔레트의 시작 주소를 반환한다. 실패하면 NULL을 반환한다.
+ bool GetPaletteColor(IN BYTE i, OUT BYTE *r, OUT BYTE *g, OUT BYTE *b)
: 지정한 인덱스의 색상값을 전달한다. 성공하면 true를 반환한다.
+ RGBQUAD GetPaletteColor(IN BYTE idx)
: 지정한 인덱스의 색상값을 반환한다. 실패하면 검정색을 반환한다.
+ DWORD GetPaletteSize()
: 팔레트의 크기를 반환한다. 바이트 단위이다.
+ CxImage* GetParent() const
: 객체가 레이어를 포함하고 있다면 그 레이어를 가지는 부모 레이어 이미지에 대한 포인터를 반환한다.
+ RGBQUAD GetPixelColor(IN long x, IN long y, IN bool bGetAlpha = true)
: 지정한 좌표의 색상값을 반환한다. 실패하면 투명색 또는 검정색을 반환한다.
+ RGBQUAD GetPixelColorInterpolated(IN float x, IN float y, IN InterpolationMethod const inMethod = IM_BILINEAR, IN OverflowMethod const ofMethod = OM_BACKGROUND, IN RGBQUAD *const rplColor = 0);
: 픽셀의 보간된 색상을 반환한다.
inMethod : 보간 방식
IM_NEAREST_NEIGHBOUR : 가장 가까운 픽셀의 값을 반환한다.
IM_BILINEAR : 이웃한 4개의 픽셀을 이용하여 보간.
IM_BICUBIC : 인접한 16개의 픽셀을 이용하여 보간.
IM_BICUBIC2 : 인접한 16개의 픽셀을 이용하여 보간.
IM_BSPLINE : 인접한 16개의 픽셀을 이용하여 보간.
IM_LANCZOS : 인접한 12*12픽셀을 이용하여 보간.
ofMethod : 좌표를 계산하는 방식
OF_REAPET : 이미지의 경계를 벗어나면 클립 되어 경계선에 놓이게 된다.
OF_WRAP : 이미지의 크기를 단위크기로 한 상대 좌표에 놓이게 된다.
OF_MIRROR : 이미지의 경계선에 대하여 반사된 위치에 놓이게 된다.
OF_COLOR : rplColor이 정의 되었다면 rplColor을 반환하고 그렇지 않으면 투명한 흰색을 반환한다.
OF_BACKGROUND : 배경색을 반환한다.
OF_TRANSPARENT : 투명색을 반환한다.
rplColor : 입력 색상. 픽셀에 대한 계산이 수행되지 않았을 때 기본적으로 반환되는 색상이다.
+ RGBQUAD GetPixelColorWithOverflow(IN long x, IN long y, IN OverflowMethod const ofMethod = OM_BACKGROUND, IN RGBQUAD *const rplColor = 0);
: 픽셀의 좌표를 지정한 방식에 따라 다시 계산한다. 정수 좌표를 사용한다.
ofMethod : 좌표를 계산하는 방식
OF_REAPET : 이미지의 경계를 벗어나면 클립 되어 경계선에 놓이게 된다.
OF_WRAP : 이미지의 크기를 단위크기로 한 상대 좌표에 놓이게 된다.
OF_MIRROR : 이미지의 경계선에 대하여 반사된 위치에 놓이게 된다.
OF_COLOR : rplColor이 정의 되었다면 rplColor을 반환하고 그렇지 않으면 투명한 흰색을 반환한다.
OF_BACKGROUND : 배경색을 반환한다.
OF_TRANSPARENT : 투명색을 반환한다.
rplColor : 입력 색상. 픽셀에 대한 계산이 수행되지 않았을 때 기본적으로 반환되는 색상이다.
+ BYTE GetPixelGray(IN long x, IN long y)
: 지정한 좌표의 색상을 그레이 스캐일로 변환하여 반환한다.
+ BYTE GetPixelIndex(IN long x, IN long y)
: 지정한 좌표의 팔레트 인덱스 값을 반환한다.
+ long GetProgress() const
: 느린 반복 등을 관리하기 위한 것.
+ long GetSize()
: 이미지의 크기를 반환한다.
+ RGBQUAD GetTransColor()
: 투명색을 가져온다.
+ long GetTransIndex() const
: 투명색의 인덱스를 가져온다. 없다면 -1이 반환된다.
+ DWORD GetType() const
: 현재 이미지의 포맷을 반환한다.
+ const TCHAR* GetVersion()
: CxImage의 버전을 반환한다.
+ const float GetVersionNumber()
: CxImage의 버전을 실수형으로 반환한다.
+ DWORD GetWidth() const
: 이미지의 너비를 반환한다. 가로 픽셀의 개수.
+ long GetXDPI() const
: TIFF, JPEG, PNG, BMP 포맷을 위한 수평 해상도를 가져온다.
+ long GetYDPI() const
: TIFF, JPEG, PNG, BMP 포맷을 위한 수직 해상도를 가져온다.
# void Ghost(IN CxImage *from)
: from의 head, info 정보는 복사해오고 나머지 정보는 포인터만 획득한다. info.pGhost 는 from을 가리키게 된다. 기존에 할당되어 있는 메모리를 해제하지는 않고 고스트 이미지를 만들기 때문에 사용에 주의를 기울여야 하겠다. public이 아니므로 외부에서는 접근할 수 없는 메소드이다.
+ bool GrayScale()
: 이미지를 8비트 그레이 스캐일 이미지로 변환한다.
+ long Histogram(IN long *red, IN long *green = 0, IN long *blue = 0, IN long *gray = 0, IN long colorspace = 0)
: 이미지 전체에서 색상의 각 요소들의 출현 빈도를 계산한다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
colorspace : 색공간을 RGB로 변환한다.
0 : 디폴트. 변환 없음.
1 : HSL에서 RGB로 변환
2 : YUV에서 RGB로 변환
3 : YIQ에서 RGB로 변환
4 : XYZ에서 RGB로 변환
+ bool HistogramEqualize()
: 이미지에 히스토그램 평활화를 적용한다.
+ bool HistogramLog()
: 히스토그램에 로그를 취한다. 밝기 변화가 좀 더 급해진다.
+ bool HistogramNormalize()
: 휘도값에 따라 히스토그램에 스트레치를 적용한다.
+ bool HistogramRoot()
: 히스토그램에 루트를 취한다.
+ bool HistogramStretch(IN long method = 0)
: 히스토그램을 확장하여 범위가 0 ~ 255가 되게 한다.
method
0 = luminance. YUV 색공간에서 휘도(Y)성분을 사용.
1 = linked channels. 하나의 LUT를 사용.
2 = independent channels. 각 채널별로 독립적인 LUT를 사용.
+ RGBQUAD HSLtoRGB(IN RGBQUAD lHSLColor)
: HSL컬러공간에서 YUV컬러공간으로 변환한다.
+ RGBQUAD HSLtoRGB(IN COLORREF cHSLColor)
: HSL컬러공간에서 YUV컬러공간으로 변환한다.
+ void HuePalette(IN float correction = 1)
: 레인보우 팔레트를 생성한다.
# float HueToRGB(IN float n1, IN float n2, IN float hue)
: Huew 값을 RGB 색공간으로 변환한 값을 반환한다.
+ bool IncreaseBpp(DWORD nbit)
: 픽셀당 비트수를 nbit로 증가시킨다.
+ void InitTextInfo( OUT CXTEXTINFO *txt );
: txt를 초기화한다.
+ bool IsEnabled() const
: 이미지가 출력가능하면 true를 반환한다.
+ bool IsGrayScale()
: 이미지가 256컬러를 사용하고 선형 그레이 스캐일 팔레트를 가졌다면 true를 반환한다.
선형 그레이 스캐일 : 인덱스 번호와 색상의 값이 똑같다.
+ bool IsIndexed() const
: 이미지가 256컬러나 그 이하를 사용한다면 true를 반환한다.
+ bool IsInside(IN long x, IN long y)
: 지정한 좌표가 이미지 안에 있으면 true를 반환한다.
# bool IsPowerof2(IN long x)
: x가 2의 멱수이면 true를 반환한다.
+ bool IsSamePalette(IN CxImage &img, IN bool bCheckAlpha)
: img가 현재 이미지와 같은 팔레트를 가지는 지 비교한다. bCheckAlpha가 true이면 rgbReserved 필드의 값도 비교한다.
+ bool IsTransparent(long x, long y)
: 지정한 좌표의 색상이 투명색이면 true를 반환한다.
+ bool IsTransparent() const
: 이미지가 투명색을 사용한다면 true를 반환한다.
+ bool IsValid() const
: 이미지가 올바르게 초기화 되었는지 검사한다. 올바르다면 true를 반환한다.
+ bool Jitter(IN long radius)
: 이미지의 각 픽셀을 무작위로 이동시킨다. radius는 픽셀이 이동 가능한 최대 거리이다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ float KernelBessel(const float x)
+ float KernelBessel_J1(const float x)
+ float KernelBessel_Order1(float x)
+ float KernelBessel_P1(const float x)
+ float KernelBessel_Q1(const float x)
+ float KernelBlackman(const float x)
+ float KernelBox(const float x)
+ float KernelBSpline(const float x)
+ float KernelCatrom(const float x)
+ float KernelCubic(const float t)
+ float KernelGaussian(const float x)
+ float KernelGeneralizedCubic(const float t, const float a=-1)
+ float KernelHamming(const float x)
+ float KernelHermite(const float x)
+ float KernelLanczosSinc(const float t, const float r = 3)
+ float KernelLinear(const float t)
+ float KernelMitchell(const float x)
+ float KernelQuadratic(const float x)
+ float KernelSinc(const float x)
: 보간에 사용되는 커널들.
+ bool LayerCreate(IN long position = -1)
: 비어있는 새로운 레이어를 만든다. position값이 0보다 작으면 새로운 레이어를 가장 마지막 position에 위치시킨다.
+ bool LayerDelete(IN long position = -1)
: 지정한 position의 레이어를 지운다. position값이 0보다 작으면 마지막 위치의 레이이가 지워진다.
+ void LayerDeleteAll()
: 모든 레이어를 지운다.
+ bool Light(long brightness, long contrast = 0)
: 이미지의 명도와 대비를 변화시킨다.
brightness : -255 ~ 255. 음수이면 이미지를 어둡게 만든다.
contrast : -100 ~ 100.
+ bool Load(IN const TCHAR *filename, IN DWORD imagetype = 0)
: 파일로부터 이미지를 지정한 타입으로 로드 한다. 만약 타입을 지정하지 않거나 UNKNOWN으로 지정할 경우 자동으로 알맞은 형식의 타입을 찾는다. ( 모든 타입에 대해 한 번씩 시도해보는 방식 )
+ bool LoadResource(IN HRSRC hRes, IN DWORD imagetype, IN HMODULE hModule = NULL)
: 리소스로부터 이미지를 읽어 들인다.
hRes : FindResource()가 반환하는 리소스의 핸들
imagetype : 이미지 포맷. ENUM_CXIMAGE_FORMATS 참조.
hModule : 내부 리소스일 경우 디폴트 값 NULL을 사용하고 외부 리소스일 경우 LoadLibrary()가 반환하는 hinstance 이다.
+ bool Lut(IN BYTE *pLutR, IN BYTE *pLutG, IN BYTE *pLutB, IN BYTE *pLutA = 0)
: 각 채널에 대한 독립된 Lookup Table을 가진다. 원리는 Lut(IN BYTE *pLut)와 동일하다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ bool Lut(IN BYTE *pLut)
: Lookup Table을 이미지에 적용시킨다. 이미지의 i번째 픽셀의 색상값이 100이라면 pLut의 100번째 값을 새로운 색상값으로 가지게 된다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
pLut : BYTE pLut[256];
+ HBITMAP MakeBitmap(HDC hdc = NULL)
: 이미지를 비트맵 형식으로 변환하여 HBITMAP 구조체를 반환한다.
+ float Mean()
: 이미지의 명도를 반환한다. 전체 픽셀을 그레이 스캐일로 변환한 뒤 픽셀값의 평균을 반환한다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ bool Median(IN long Ksize=3)
: 중앙값 필터. 주위 픽셀의 값을 크기 순으로 정렬하였을 때 중앙에 있는 값을 현재 픽셀의 값으로 한다. Ksize는 마스크의 크기이다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ bool Mirror()
: 이미지를 좌우로 뒤집는다.
+ void Mix(IN CxImage &imgsrc2, IN ImageOpType op, IN long lXOffset = 0, IN long lYOffset = 0, IN bool bMixAlpha = false)
: 두 이미지를 섞는다.
imgsrc2 : 현재 이미지에 섞을 이미지
imageOpType : 섞는 방법
OpAdd : p + q
OpSub : p - q
OpAnd : p & q
OpXor : p ^ q
OpOr : p | q
OpMask : 검정색을(RGB(0,0,0)) 투명색으로 변환.
OpSrcCopy : 현재 이미지의 투명한 부분에 imgsrc2 이미지를 복사.
OpDstCopy : imgsrc2 이미지의 투명한 부분에 현재 이미지를 복사.
OpScreen : imgsrc2 이미지의 투명도에 따라 블렌딩 처리.
OpSrcBlend : 현재 이미지의 투명도에 따라 블렌딩 처리.
lXOffset , lYOffset : imgsrc2 이미지에서 섞게 될 부분의 좌상단 좌표
bMixAlpha : true이면 알파값도 섞는다.
+ void MixFrom(IN CxImage &imagesrc2, IN long lXOffset, IN long lYOffset)
: imagesrc2 이미지에서 투명하지 않은 픽셀을 현재 이미지에 찍는다.
lXOffset , lYOffset : imagesrc2 이미지에서 섞게 될 부분의 좌상단 좌표
+ bool Negative()
: 이미지의 색상을 반전시킨다. 선택영역이 있다면 선택영역의 색상만 반전된다.
+ bool Noise(IN long level)
: 이미지에 노이즈를 추가한다. level에 높은 값을 줄수록 노이즈가 심해진다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ CxImage& operator = (const CxImage& isrc)
: 대입 연산자 오버로딩.
+ void OverflowCoordinates(IN OUT long &x, IN OUT long &y, IN OverflowMethod const ofMethod)
: 픽셀의 좌표를 지정한 방식에 따라 다시 계산한다. 정수 좌표를 사용한다.
ofMethod : 좌표를 계산하는 방식
OM_REAPET : 이미지의 경계를 벗어나면 클립 되어 경계선에 놓이게 된다.
OM_WRAP : 이미지의 크기를 단위크기로 한 상대 좌표에 놓이게 된다.
OM_MIRROR : 이미지의 경계선에 대하여 반사된 위치에 놓이게 된다.
+ void OverflowCoordinates(IN OUT float &x, IN OUT float &y, IN OverflowMethod const ofMethod)
: 픽셀의 좌표를 지정한 방식에 따라 다시 계산한다. 실수 좌표를 사용한다. 정수 좌표를 위한 OverflowCoordinates() 참조.
+ bool QIShrink(IN long newx, IN long newy, OUT CxImage *const iDst = NULL)
: 이미지의 너비를 newx로, 높이를 newy로 축소시킨다. 확대시키지는 못한다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
+ bool RedEyeRemove()
: 적목 현상 제거. 제거가 필요한 눈 부분을 선택 영역으로 지정 하여야 한다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ bool Repair(IN float radius = 0.25f, IN long niterations = 1, IN long colorspace = 0)
: 이미지에 번짐 효과를 적용한다.
radius : 보통 0.01 ~ 0.5
niterations : 적용 횟수. 번짐을 피하려면 (radius*niterations) < 1 이 되어야 한다.
colorspace : 색공간. 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ
# bool RepairChannel(IN CxImage *ch, IN float radius)
: 하나의 색 채널에 대해 RepairChannel()이 수행된다.
+ bool Resample(IN long newx, IN long newy, IN int mode = 1, OUT CxImage* iDst = NULL)
: 이미지의 크기를 변경한다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
mode : 0은 이중선형 보간법으로 속도가 느리고 1은 가장 근접한 픽셀을 선택하는 방식으로 속도가 빠르다. 2는 bicubic 스플라인 보간법으로 품질이 좋다.
+ bool Resample2(IN long newx, IN long newy, IN InterpolationMethod const inMethod = IM_BICUBIC2, IN OverflowMethod const ofMethod = OM_REPEAT, IN CxImage *const iDst = NULL, IN bool const disableAveraging = false)
: 이미지의 크기를 변경한다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
inMethod : 보간 방식
IM_NEAREST_NEIGHBOUR : 가장 가까운 픽셀의 값을 반환한다.
IM_BILINEAR : 이웃한 4개의 픽셀을 이용하여 보간.
IM_BICUBIC : 인접한 16개의 픽셀을 이용하여 보간.
IM_BICUBIC2 : 인접한 16개의 픽셀을 이용하여 보간.
IM_BSPLINE : 인접한 16개의 픽셀을 이용하여 보간.
IM_LANCZOS : 인접한 12*12픽셀을 이용하여 보간.
ofMethod : 좌표를 계산하는 방식
OF_REAPET : 이미지의 경계를 벗어나면 클립 되어 경계선에 놓이게 된다.
OF_WRAP : 이미지의 크기를 단위크기로 한 상대 좌표에 놓이게 된다.
OF_MIRROR : 이미지의 경계선에 대하여 반사된 위치에 놓이게 된다.
OF_COLOR : rplColor이 정의 되었다면 rplColor을 반환하고 그렇지 않으면 투명한 흰색을 반환한다.
OF_BACKGROUND : 배경색을 반환한다.
OF_TRANSPARENT : 투명색을 반환한다.
+ COLORREF RGBQUADtoRGB (RGBQUAD c)
: RGBQUAD 타입 색상을 COLORREF 타입으로 변환한다.
# void RGBtoBGR(BYTE *buffer, int length)
: RGB색상에서 Red와 Blue의 위치를 서로 바꾼다.
buffer : 변환할 픽셀이 저장되어 있는 버퍼
length : 버퍼의 길이. 바이트 단위이다.
+ RGBQUAD RGBtoHSL(RGBQUAD lRGBColor)
: RGB컬러공간에서 HSL컬러공간으로 변환한다.
+ RGBQUAD RGBtoRGBQUAD(COLORREF cr)
: COLORREF 타입 색상을 RGBQUAD 타입으로 변환한다.
+ RGBQUAD RGBtoXYZ(RGBQUAD lRGBColor)
: RGB컬러공간에서 HSL컬러공간으로 변환한다.
+ RGBQUAD RGBtoYIQ(RGBQUAD lRGBColor)
: RGB컬러공간에서 XYZ컬러공간으로 변환한다.
+ RGBQUAD RGBtoYUV(RGBQUAD lRGBColor)
: RGB컬러공간에서 YUV컬러공간으로 변환한다.
+ bool Rotate(IN float angle, OUT CxImage *iDst = NULL)
: 이미지를 지정한 각도만큼 회전시킨다. 회전된 이미지가 모두 들어 갈 수 있는 크기로 이미지가 확장된다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
+ bool Rotate180(OUT CxImage *iDst = NULL)
: 이미지를 180도 회전시킨다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
+ bool Rotate2(IN float angle, IN CxImage *iDst = NULL, IN InterpolationMethod inMethod = IM_BILINEAR, IN OverflowMethod ofMethod = OM_BACKGROUND, IN RGBQUAD *replColor = 0, IN bool const optimizeRightAngles = true, IN bool const bKeepOriginalSize = false);
: 이미지를 지정한 각도만큼 회전시킨다. 회전된 이미지가 모두 들어 갈 수 있는 크기로 이미지가 확장된다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
inMethod : 보간 방식
IM_NEAREST_NEIGHBOUR : 가장 가까운 픽셀의 값을 반환한다.
IM_BILINEAR : 이웃한 4개의 픽셀을 이용하여 보간.
IM_BICUBIC : 인접한 16개의 픽셀을 이용하여 보간.
IM_BICUBIC2 : 인접한 16개의 픽셀을 이용하여 보간.
IM_BSPLINE : 인접한 16개의 픽셀을 이용하여 보간.
IM_LANCZOS : 인접한 12*12픽셀을 이용하여 보간.
ofMethod : 좌표를 계산하는 방식
OF_REAPET : 이미지의 경계를 벗어나면 클립 되어 경계선에 놓이게 된다.
OF_WRAP : 이미지의 크기를 단위크기로 한 상대 좌표에 놓이게 된다.
OF_MIRROR : 이미지의 경계선에 대하여 반사된 위치에 놓이게 된다.
OF_COLOR : rplColor이 정의 되었다면 rplColor을 반환하고 그렇지 않으면 투명한 흰색을 반환한다.
OF_BACKGROUND : 배경색을 반환한다.
OF_TRANSPARENT : 투명색을 반환한다.
replColor : 입력 색상. 픽셀에 대한 계산이 수행되지 않았을 때 기본적으로 반환되는 색상이다.
optimizeRightAngles : 90도, 180도, 270도 회전에는 더 빠른 회전 함수를 호출한다.
bKeepOriginalSize : true이면 이미지를 회전하여도 이미지의 본래 크기가 유지 된다.
+ bool RotateLeft(OUT CxImage *iDst)
: 이미지를 왼쪽으로 90도 회전시킨다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
+ bool RotateRight(OUT CxImage *iDst)
: 이미지를 오른쪽으로 90도 회전시킨다. 만약 iDst를 지정하면 현재 이미지를 대체하지 않고 iDst에 처리된 이미지를 전달한다.
+ bool Save(IN const TCHAR *filename, IN DWORD imagetype)
: 이미지를 지정한 포맷으로 디스크에 저장한다.
+ bool SelectionAddColor(IN RGBQUAD c)
: 지정한 색상의 픽셀을 선택영역에 포함시킨다.
+ bool SelectionAddEllipse(IN RECT r)
: 기존의 선택영역에 타원형의 영역을 더한다.
+ bool SelectionAddPixel(IN int x, IN int y)
: 지정한 좌표의 픽셀을 선택영역에 더한다.
+ bool SelectionAddPolygon(IN POINT *points, IN long npoints)
: 기존의 선택영역에 다각형의 영역을 더한다.
points : 다각형의 꼭지점 리스트.
npoints : 꼭지점의 개수.
+ bool SelectionAddRect(IN RECT r)
: 기존의 선택영역에 사각형의 영역을 더한다.
+ bool SelectionClear()
: 선택영역을 지운다.
+ bool SelectionCopy(IN CxImage &from)
: from 이미지로부터 선택영역을 복사해 온다.
+ bool SelectionCreate()
: 선택영역에 대한 정보를 담을 새로운 버퍼를 생성한다.
+ bool SelectionDelete()
: 선택영역에 대한 정보를 담고 있는 버퍼를 제거한다.
+ void SelectionGetBox(IN RECT &r)
: 선택영역을 모두 포함하는 가장 작은 사각형을 반환한다.
+ bool SelectionInvert()
: 선택영역을 반전시킨다.
+ bool SelectionIsInside(IN long x, IN long y)
: 지정한 좌표가 선택영역 안에 있으면 true를 반환한다.
+ bool SelectionIsValid()
: 선택영역을 위한 버퍼가 할당되어 있다면 true를 반환한다.
+ bool SelectionSplit(OUT CxImage *dest)
: 선택 영역을 8비트 그레이 스캐일 이미지로 내보낸다.
+ bool SelectionToHRGN(OUT HRGN ®ion)
: 선택영역을 HRGN 타입으로 변환시킨다.
+ void SetClrImportant(IN DWORD ncolors = 0)
: 팔레트의 색상 중 이미지를 표현하는데 필요한 색상의 수를 지정한다. 인수의 값은 2^bpp보다 작은 값이어야 하며 0또는 생략하면 모든 색상을 필요로 한다는 의미가 된다.
+ bool SetCodecOption(IN DWORD opt, IN DWORD imagetype = 0)
: GIF, TIF, JPG에 대한 인코딩 옵션을 지정한다.
GIF : 0 = LZW (디폴트), 1 = none, 2 = RLE.
TIF : 0 = 자동 (디폴트), 또는 "tiff.h"에 정의되어 있는 것들. (COMPRESSION_NONE = 1, COMPRESSION_CCITTRLE = 2, ...)
JPG : enum CODEC_OPTION ( ENCODE_BASELINE = 0x01, ENCODE_PROGRESSIVE = 0x10, ...)에 정의되어 있는 값들 중 하나.
+ void SetEscape(long i)
: 느린 반복문 등이 수행되고 있을 때 i값을 -1로 주면 강제로 루틴을 빠져 나가게 한다.
+ void SetFlags(IN DWORD flags, IN bool bLockReservedFlags)
: 나중에 사용될 것을 생각해 만들어 둔 플래그.
flags
0x??00000 = 16비트 이미지, CMYK, 멀티 레이어를 위해 예약됨.
0x00??0000 = 블렌드 모드
0x0000???? = 레이어 id 또는 사용자 플래그
bLockReservedFlags : 예약된 플래그와 블렌드 모드를 보호한다.
+ void SetFrame(long nFrame)
: 다음에 읽어 들일 프레임의 번호를 지정한다. TIFF, GIF 이미지에서 사용한다.
+ void SetFrameDelay(DWORD d)SetFrame
: GIF 포맷에서 현재 프레임의 딜레이를 지정한다. 밀리세컨드 단위이다.
+ void SetGrayPalette()
: 팔레트를 그레이 스캐일로 지정한다.
+ void SetJpegQuality(BYTE q)
: JPEG 이미지의 화질을 지정한다. 범위는 0 ~ 100 이다.
+ void SetJpegScale(BYTE q)
: JPEG 이미지를 읽어 들일 때 확대/축소 비율을 지정한다. 가능한 숫자는 1, 2, 4, 8이다.
+ void SetOffset(long x,long y)
: 화면상에 이미지가 출력될 시작 위치.
+ void SetPalette(IN RGBQUAD *pPal, IN DWORD nColors = 256)
: 팔레트의 색상을 지정한다.
+ void SetPalette(IN rgb_color *rgb, IN DWORD nColors = 256)
: 팔레트의 색상을 지정한다.
+ void SetPalette(IN DWORD n, BYTE *r, BYTE *g, BYTE *b)
: 팔레트의 색상을 지정한다.
n : 색상의 수
r : red 값이 들어 있는 버퍼
g : green 값이 들어 있는 버퍼
b : blue 값이 들어 있는 버퍼
+ void SetPaletteColor(BYTE idx, COLORREF cr)
: 팔레트의 idx 번째 색상을 cr로 지정한다.
+ void SetPaletteColor(BYTE idx, RGBQUAD cr)
: 팔레트의 idx 번째 색상을 cr로 지정한다.
+ void SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha=0)
: 팔레트의 idx 번째 색상을 RGBQUAD(r, g, b, alpha)로 지정한다.
+ void SetPixelColor(IN long x, IN long y, IN RGBQUAD c, IN bool bSetAlpha = false)
: 색상 c를 픽셀 (x, y)의 색상으로 한다. bSetAlpha가 true라면 색상 c의 알파값을 24비트 픽셀 (x, y)의 알파값으로 한다.
+ void SetPixelColor(IN long x, IN long y, IN COLORREF cr)
: 색상 cr을 픽셀 (x, y)의 색상으로 한다.
+ void SetPixelIndex(IN long x, IN long y, IN BYTE i) : i를 픽셀 (x, y)의 인덱스값으로 한다.
+ void SetProgress(long p) : 프로그래스바의 상태를 강제로 변환시킨다.
+ void SetStdPalette() : 팔레트를 표준 색상으로 채운다.
+ void SetTransColor(IN RGBQUAD rgb) : 24비트 이미지에서 투명색을 지정한다. 투명효과를 사용하려면 반드시 SetTransIndex(0)를 먼저 호출하여야 한다. 투명효과를 없애려면 SetTransIndex(-1)을 호출하면 된다.
+ void SetTransIndex(IN long idx) : 팔레트를 사용하는 BPP가 1, 4, 8인 이미지에서 투명색의 인덱스 번호를 지정한다. 투명효과를 없애려면 idx에 -1을 주면 된다.
+ void SetXDPI(IN long dpi) : TIFF, JPEG, PNG, BMP 포맷을 위한 수평 해상도를 지정한다.
+ void SetYDPI(IN long dpi) : TIFF, JPEG, PNG, BMP 포맷을 위한 수직 해상도를 지정한다.
+ bool ShiftRGB(IN long r, IN long g, IN long b) : 이미지의 모든 픽셀에 지정한 픽셀값을 더한다. 값의 범위는 -255 ~ 255이다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
+ bool Skew(IN float xgain, IN float ygain, IN long xpivot=0, IN long ypivot=0, IN bool bEnableInterpolation = false) : 이미지에 시어링을 적용한다. 선택영역이 있으면 해당 영역에만 처리가 적용된다.
xgain, ygain : 0 ~ 1. 왜곡 정도를 지정한다.
xpivot, ypivot : 왜곡의 중심을 지정한다.
bEnableInterpolation : bilinear 보간법의 적용 여부를 지정한다.
+ bool SplitCMYK(OUT CxImage *c, OUT CxImage *m, OUT CxImage *y, OUT CxImage *k) : 이미지의 CMYK 채널을 8비트 그레이 스캐일 이미지로 내보낸다.
+ bool SplitHSL(OUT CxImage *h, OUT CxImage *s, OUT CxImage *l) : 이미지의 HSL 채널을 8비트 그레이 스캐일 이미지로 내보낸다.
+ bool SplitRGB(OUT CxImage *r, OUT CxImage *g, OUT CxImage *b) : 이미지의 RGB 채널을 8비트 그레이 스캐일 이미지로 내보낸다.
+ bool SplitXYZ(OUT CxImage *x, OUT CxImage *y, OUT CxImage *z) : 이미지의 XYZ 채널을 8비트 그레이 스캐일 이미지로 내보낸다.
+ bool SplitYIQ(OUT CxImage *y, OUT CxImage *i, OUT CxImage *q) : 이미지의 YIQ 채널을 8비트 그레이 스캐일 이미지로 내보낸다.
+ bool SplitYUV(OUT CxImage *y, OUT CxImage *u, OUT CxImage *v) : 이미지의 YUV 채널을 8비트 그레이 스캐일 이미지로 내보낸다.
# void Startup(IN DWORD imagetype = 0) : 멤버 변수를 초기화 한다.
+ long Stretch(IN HDC hdc, IN const RECT &rect, IN DWORD dwRop = SRCCOPY) : 이미지를 화면에 출력한다.
+ long Stretch(HDC hdc, long xoffset, long yoffset, long xsize, long ysize, DWORD dwRop = SRCCOPY) : 이미지를 화면에 출력한다.
+ void SwapIndex(IN BYTE idx1, IN BYTE idx2) : 이미지의 팔레트에서 idx1과 idx2 인덱스의 색상을 서로 교환하고 이미지에서도 모든 idx1과 idx2값을 서로 교환한다.
+ bool Threshold(IN BYTE level) : 이미지를 흑백으로 변환한다. level 은 기준이 되는 명도값이다.
+ bool Thumbnail(IN long newx, IN long newy, IN RGBQUAD canvascolor, OUT CxImage* iDst = 0) : 지정한 크기의 썸네일 이미지를 생성한다. canvascolor로 테두리의 색을 지정한다.
+ long Tile(IN HDC hdc, IN RECT *rc) : 이미지를 바둑판식으로 출력한다. rc는 이미지를 출력할 영역.
+ bool Transfer(OUT CxImage &from) : from이미지로부터 이미지를 가져온다. from이미지는 내용은 모두 지워진다.
+ bool UnsharpMask(IN float radius = 5.0, IN float amount = 0.5, IN int threshold = 0) : 이미지를 선명하게 한다.
radius : 효과의 적용 범위.
amount : 선명함의 적용 정도.
+ RGBQUAD XYZtoRGB(IN RGBQUAD lXYZColor) : XYZ컬러공간에서 RGB컬러공간으로 변환한다.
+ RGBQUAD YIQtoRGB(IN RGBQUAD lYIQColor) : YIQ컬러공간에서 RGB컬러공간으로 변환한다.
+ RGBQUAD YUVtoRGB(IN RGBQUAD lYUVColor) : YUV컬러공간에서 RGB컬러공간으로 변환한다
[참조] ARToolkit + OpenVRML Setting (1) | 2010.04.07 |
---|---|
IplImage <-> TBitMap 상호 변환 방법 (0) | 2009.03.06 |
Halcon 사용 예제 - 팁의 일부 마크 중심에서 떨어진 값 구하기 (0) | 2009.02.25 |