81.6 연습문제: 비트맵 파일을 아스키 아트로 변환하기
다음 소스 코드를 완성하여 24비트 비트맵 파일을 아스키 아트로 변환하는 프로그램을 만드세요.
practice_bitmap_asciiart.c
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #pragma pack(push, 1) typedef struct _BITMAPFILEHEADER { unsigned short bfType; unsigned int bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned int bfOffBits; } BITMAPFILEHEADER; typedef struct _BITMAPINFOHEADER { unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompression; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; } BITMAPINFOHEADER; typedef struct _RGBTRIPLE { unsigned char rgbtBlue; unsigned char rgbtGreen; unsigned char rgbtRed; } RGBTRIPLE; #pragma pack(pop) #define PIXEL_SIZE 3 #define PIXEL_ALIGN 4 int main() { FILE *fpBmp; FILE *fpTxt; BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; unsigned char *image; int size; int width, height; int padding; char ascii[] = { '#', '#', '@', '%', '=', '+', '*', ':', '-', '.', ' ' }; fpBmp = fopen("Peppers80x80.bmp", "rb"); if (fpBmp == NULL) return 0; if (①________________________________________________ < 1) { fclose(fpBmp); return 0; } if (②____________________________) { fclose(fpBmp); return 0; } if (fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, fpBmp) < 1) { fclose(fpBmp); return 0; } if (infoHeader.biBitCount != 24) { fclose(fpBmp); return 0; } size = infoHeader.biSizeImage; width = infoHeader.biWidth; height = infoHeader.biHeight; padding = (PIXEL_ALIGN - ((width * PIXEL_SIZE) % PIXEL_ALIGN)) % PIXEL_ALIGN; if (size == 0) { size = (width * PIXEL_SIZE + padding) * height; } image = malloc(size); fseek(fpBmp, fileHeader.bfOffBits, SEEK_SET); if (fread(image, size, 1, fpBmp) < 1) { fclose(fpBmp); return 0; } fclose(fpBmp); fpTxt = fopen("ascii.txt", "w"); if (fpTxt == NULL) { free(image); return 0; } for (int y = height - 1; y >= 0; y--) { for (int x = 0; x < width; x++) { int index = (x * PIXEL_SIZE) + (y * (width * PIXEL_SIZE)) + (padding * y); RGBTRIPLE *pixel = (RGBTRIPLE *)&image[index]; unsigned char blue = pixel->rgbtBlue; unsigned char green = pixel->rgbtGreen; unsigned char red = pixel->rgbtRed; unsigned char gray = (red + green + blue) / PIXEL_SIZE; ③_______________________________________________ fprintf(fpTxt, "%c%c", c, c); } fprintf(fpTxt, "\n"); } fclose(fpTxt); free(image); return 0; }
정답
① fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fpBmp) ② fileHeader.bfType != 'MB' ③ char c = ascii[gray * sizeof(ascii) / 256];
해설
먼저 fread 함수로 비트맵 파일 헤더를 읽은 뒤 bfType을 확인하여 'MB'가 맞는지 확인합니다. 파일에 저장된 상태는 'BM'이지만 리틀 엔디언으로 읽었으므로 'MB'가 됩니다.
RGB 값의 평균으로 구한 흑백값을 ASCII 문자 배열의 인덱스 변환하려면 흑백값에 ASCII 문자의 개수를 곱한 뒤 256으로 나눠주면 됩니다. 단, 255로 나누면 흑백값이 255일 때 ascii 배열의 인덱스를 벗어나게 되므로 주의해야 합니다.