#define _CRT_SECURE_NO_WARNINGS // fopen 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h> // fopen, fread, fseek, fprintf, fclose 함수가 선언된 헤더 파일
#include <stdlib.h> // malloc, free 함수가 선언된 헤더 파일
#pragma pack(push, 1) // 구조체를 1바이트 크기로 정렬
typedef struct _BITMAPFILEHEADER // BMP 비트맵 파일 헤더 구조체
{
unsigned short bfType; // BMP 파일 매직 넘버
unsigned int bfSize; // 파일 크기
unsigned short bfReserved1; // 예약
unsigned short bfReserved2; // 예약
unsigned int bfOffBits; // 비트맵 데이터의 시작 위치
} BITMAPFILEHEADER;
typedef struct _BITMAPINFOHEADER // BMP 비트맵 정보 헤더 구조체(DIB 헤더)
{
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 // 24비트 비트맵 이미지의 픽셀 구조체
{
unsigned char rgbtBlue; // 파랑
unsigned char rgbtGreen; // 초록
unsigned char rgbtRed; // 빨강
} RGBTRIPLE;
#pragma pack(pop)
#define PIXEL_SIZE 3 // 픽셀 한 개의 크기 3바이트(24비트)
#define PIXEL_ALIGN 4 // 픽셀 데이터 가로 한 줄은 4의 배수 크기로 저장됨
int main()
{
FILE* fpBmp; // 비트맵 파일 포인터
FILE* fpBmpResult;
BITMAPFILEHEADER fileHeader; // 비트맵 파일 헤더 구조체 변수
BITMAPINFOHEADER infoHeader; // 비트맵 정보 헤더 구조체 변수
unsigned char* image; // 픽셀 데이터 포인터
int size; // 픽셀 데이터 크기
int width, height; // 비트맵 이미지의 가로, 세로 크기
int padding; // 픽셀 데이터의 가로 크기가 4의 배수가 아닐 때 남는 공간의 크기
unsigned char password = 0x00;
fpBmp = fopen("image.bmp", "rb"); // 비트맵 파일을 바이너리 모드로 열기
if (fpBmp == NULL) // 파일 열기에 실패하면
return 0; // 프로그램 종료
// 비트맵 파일 헤더 읽기. 읽기에 실패하면 파일 포인터를 닫고 프로그램 종료
if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fpBmp) < 1)
{
fclose(fpBmp);
return 0;
}
// 매직 넘버가 MB가 맞는지 확인(2바이트 크기의 BM을 리틀 엔디언으로 읽었으므로 MB가 됨)
// 매직 넘버가 맞지 않으면 프로그램 종료
if (fileHeader.bfType != 'MB')
{
fclose(fpBmp);
return 0;
}
// 비트맵 정보 헤더 읽기. 읽기에 실패하면 파일 포인터를 닫고 프로그램 종료
if (fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, fpBmp) < 1)
{
fclose(fpBmp);
return 0;
}
// 24비트 비트맵이 아니면 프로그램 종료
if (infoHeader.biBitCount != 24)
{
fclose(fpBmp);
return 0;
}
size = infoHeader.biSizeImage; // 픽셀 데이터 크기
width = infoHeader.biWidth; // 비트맵 이미지의 가로 크기
height = infoHeader.biHeight; // 비트맵 이미지의 세로 크기
// 이미지의 가로 크기에 픽셀 크기를 곱하여 가로 한 줄의 크기를 구하고 4로 나머지를 구함
// 그리고 4에서 나머지를 빼주면 남는 공간을 구할 수 있음.
// 만약 남는 공간이 0이라면 최종 결과가 4가 되므로 여기서 다시 4로 나머지를 구함
padding = (PIXEL_ALIGN - ((width * PIXEL_SIZE) % PIXEL_ALIGN)) % PIXEL_ALIGN;
if (size == 0) // 픽셀 데이터 크기가 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;
}
fseek(fpBmp, 0, SEEK_SET);
fpBmpResult = fopen("image_result.bmp", "wb");
fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fpBmpResult);
fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, fpBmpResult);
// 픽셀 데이터는 아래 위가 뒤집혀서 저장되므로 아래쪽부터 반복
// 세로 크기만큼 반복
for (int y = height - 1; y >= 0; y--)
{
int n = 0;
// 가로 크기만큼 반복
for (int x = 0; x < width; x++)
{
// 일렬로 된 배열에 접근하기 위해 인덱스를 계산
// (x * 픽셀 크기)는 픽셀의 가로 위치
// (y * (세로 크기 * 픽셀 크기))는 픽셀이 몇 번째 줄인지 계산
// 남는 공간 * y는 줄별로 누적된 남는 공간
int index = (x * PIXEL_SIZE) + (y * (width * PIXEL_SIZE)) + (padding * y);
srand(n++);
password = rand() % 256;
((RGBTRIPLE*)&image[index])->rgbtBlue ^= password;
srand(n++);
password = rand() % 256;
((RGBTRIPLE*)&image[index])->rgbtGreen ^= password;
srand(n++);
password = rand() % 256;
((RGBTRIPLE*)&image[index])->rgbtRed ^= password;
}
}
fwrite(image, size, 1, fpBmpResult);
fclose(fpBmp);
fclose(fpBmpResult);
free(image); // 픽셀 데이터를 저장한 동적 메모리 해제
return 0;
}
변경 전
변경 후
각 픽셀에 저장된 RGB값과 0~255 난수 값이랑 XOR연산 시켜서 이미지 바꾼 코드임.
변경 된 이미지를 다시 변환하면 원래 이미지로 돌아옴.
본인 의도는 형체도 못 알아보게 바꾸는 건데 형체는 알아 볼 수 있음.
어떻게 해야 형체도 못 알아보게 만들 수 있음?
난수생성에문제있는게 아닐까 사실잘몰루
난수 값 printf로 찍어 보았는데 랜덤하게 잘 나오는 것 같았음
뭘 그렇게 꽁꽁 감추냐 하여간에 김치새끼들은 오픈을안해요 ㅉㅉ
적절한 알고리즘으로 픽셀 위치를 좀 섞어보셈