libpng을 CMake와 Visual Studio 2015로 빌드하고 이미지 처리 예제 사용하기

빌드 전 준비 사항

libpng를 컴파일하기에 앞서, 우선 zlib이 정상적으로 빌드되어 있어야 하며, 해당 라이브러리가 개발 환경에 포함되어야 합니다. libpng는 내부적으로 zlib을 사용하여 압축 데이터를 처리하므로, 반드시 zlib의 헤더 파일과 라이브러리(.lib)가 CMake 구성 단계에서 인식될 수 있도록 설정되어야 합니다.

소스 코드 다운로드 및 구조 확인

libpng 공식 사이트(http://www.libpng.org)에서 최신 버전 정보를 확인할 수 있으며, 실제 소스 코드는 SourceForge를 통해 제공됩니다. 본 문서 기준으로 사용된 버전은 libpng 1.6.36입니다. 다운로드 후 압축을 해제하면, 루트 디렉터리에 CMakeLists.txt 파일이 존재하는 것을 확인할 수 있습니다.

CMake를 사용한 프로젝트 생성

CMake GUI를 실행하고 다음 두 경로를 지정합니다:

  • Source directory: 압축 해제한 libpng 소스 폴더
  • Build directory: 빌드 산출물이 저장될 별도의 디렉터리 (예: libpng/build)

초기 Configure 클릭 시, 사용할 컴파일러로 Visual Studio 14 2015를 선택합니다. 첫 번째 구성 후에는 다음과 같은 설치 경로를 수정하는 것이 좋습니다:

  • CMAKE_INSTALL_PREFIX: 기본값은 시스템 경로일 수 있으나, 처음에는 소스 근처에 별도 설치 디렉터리를 지정하여 출력 내용을 쉽게 검토할 수 있습니다 (예: libpng/install).

필요 시, 디버그/릴리즈 라이브러리 이름에 버전 태그가 붙는 것을 방지하려면, CMakeLists.txt 내에서 PNG_LIB_NAME 관련 설정을 수정한 후 캐시를 삭제하고 다시 구성해야 합니다.

Visual Studio 솔루션 열기 및 빌드

구성 완료 후 Generate를 클릭하면, Visual Studio 용 .sln 파일이 생성됩니다. 이후 Open Project를 통해 솔루션을 엽니다. 솔루션 탐색기에서 전체 솔루션을 빌드하면 핵심 라이브러리인 libpng.lib(릴리즈), libpngd.lib(디버그)와 함께 동적 라이브러리 libpng16.dll 등이 생성됩니다.

설치 과정 (Install)

빌드 성공 후, 솔루션 내 INSTALL이라는 이름의 특수 프로젝트가 존재합니다. 이 프로젝트를 오른쪽 클릭하여 빌드 또는 솔루션에 포함된 프로젝트만 빌드INSTALL을 선택하면, 이전에 설정한 CMAKE_INSTALL_PREFIX 경로에 다음 파일들이 복사됩니다:

  • 헤더 파일 (png.h, pngconf.h, pnglibconf.h)
  • 라이브러리 파일 (.lib)
  • DLL 파일
  • CMake 구성 파일

외부 라이브러리 경로 관리 방법

VC++ 설치 디렉터리에 설치하지 않을 경우, 다음과 같은 방법 중 하나를 선택해야 합니다:

  1. 시스템 환경 변수: 설치 경로를 PATH에 추가하여 런타임 시 DLL 탐색 가능하게 함.
  2. 프로젝트 설정: 각 Visual Studio 프로젝트의 추가 포함 디렉터리, 추가 라이브러리 디렉터리, 입력 종속성에 수동으로 경로와 라이브러리 이름 입력.
  3. CMake 기반 프로젝트: find_package(PNG REQUIRED) 사용 시, 설치 경로가 시스템 경로가 아니면 PNG_DIR 변수에 *Config.cmake 파일 위치를 명시적으로 지정하거나, CMAKE_PREFIX_PATH에 설치 루트를 포함시켜야 합니다.

간단한 PNG 이미지 생성 예제

다음은 CMake 기반 콘솔 애플리케이션에서 libpng를 사용해 10x10 픽셀 RGB 이미지를 생성하는 예제입니다.

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(CreatePngImage)

set(CMAKE_CXX_STANDARD 11)

# 소스 파일 수집
file(GLOB SOURCES "*.cpp")

# 라이브러리 링크 설정 (디버그/릴리즈 구분)
add_executable(${PROJECT_NAME} ${SOURCES})

# libpng 찾기
find_package(PNG REQUIRED)
include_directories(${PNG_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${PNG_LIBRARIES})

main.cpp

#include <png.h>
#include <cstdio>
#include <iostream>

int main() {
    const int width = 10, height = 10;
    FILE* fp = fopen("output.png", "wb");
    if (!fp) {
        std::cerr << "Failed to open file for writing.\n";
        return -1;
    }

    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!png_ptr) {
        fclose(fp);
        return -1;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_write_struct(&png_ptr, nullptr);
        fclose(fp);
        return -1;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        fclose(fp);
        return -1;
    }

    png_init_io(png_ptr, fp);

    // 이미지 정보 설정
    png_set_IHDR(
        png_ptr, info_ptr,
        width, height,
        8,                      // 비트 깊이
        PNG_COLOR_TYPE_RGB,     // 색상 유형
        PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT,
        PNG_FILTER_TYPE_DEFAULT
    );
    png_write_info(png_ptr, info_ptr);

    // 픽셀 데이터 작성
    png_bytepp row_pointers = new png_bytep[height];
    for (int y = 0; y < height; ++y) {
        row_pointers[y] = new png_byte[width * 3];
        for (int x = 0; x < width; ++x) {
            row_pointers[y][x*3 + 0] = 0xFF; // R
            row_pointers[y][x*3 + 1] = 0xCC; // G
            row_pointers[y][x*3 + 2] = 0x00; // B
        }
    }

    png_write_image(png_ptr, row_pointers);
    png_write_end(png_ptr, nullptr);

    // 리소스 해제
    for (int y = 0; y < height; ++y) {
        delete[] row_pointers[y];
    }
    delete[] row_pointers;

    png_destroy_write_struct(&png_ptr, &info_ptr);
    fclose(fp);

    std::cout << "PNG image created successfully.\n";
    return 0;
}

PNG 파일 읽기 및 RGB 데이터 추출

다음 코드는 PNG 파일을 열어 서명을 검증하고, 픽셀 데이터를 순수 RGB 바이너리 형식으로 추출하여 저장합니다.

#include <cstdio>
#include <png.h>
#include <iostream>
#include <string>
#include <sstream>

#define SIGNATURE_SIZE 4

int main() {
    FILE* fp = fopen("input.png", "rb");
    if (!fp) {
        std::cerr << "Cannot open input.png\n";
        return -1;
    }

    char sig[SIGNATURE_SIZE];
    fread(sig, 1, SIGNATURE_SIZE, fp);
    if (png_sig_cmp((png_const_bytep)sig, 0, SIGNATURE_SIZE)) {
        std::cerr << "Invalid PNG signature\n";
        fclose(fp);
        return -1;
    }

    rewind(fp);

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!png_ptr) {
        fclose(fp);
        return -1;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, nullptr, nullptr);
        fclose(fp);
        return -1;
    }

    png_init_io(png_ptr, fp);
    png_set_sig_bytes(png_ptr, SIGNATURE_SIZE);
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, nullptr);

    int width = png_get_image_width(png_ptr, info_ptr);
    int height = png_get_image_height(png_ptr, info_ptr);
    int color_type = png_get_color_type(png_ptr, info_ptr);

    int channels = (color_type == PNG_COLOR_TYPE_RGB_ALPHA) ? 4 : 3;
    png_bytepp rows = png_get_rows(png_ptr, info_ptr);

    std::ostringstream oss;
    oss << "output_" << width << "x" << height << ".rgb";
    FILE* rgb_out = fopen(oss.str().c_str(), "wb");

    if (rgb_out) {
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                fwrite(&rows[y][x * channels], 1, 3, rgb_out); // 항상 RGB 3바이트 쓰기
            }
        }
        fclose(rgb_out);
        std::cout << "RGB data saved to " << oss.str() << "\n";
    }

    png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
    fclose(fp);
    return 0;
}

디버그/릴리즈 라이브러리 혼용 주의사항

실수로 디버그 빌드에서 릴리즈용 libpng.lib를 링크하면, 런타임 시 메모리 할당 불일치로 인해 크래시가 발생할 수 있습니다. 반드시 빌드 구성에 맞는 라이브러리를 사용해야 하며, CMake에서는 find_package가 이를 자동으로 처리해주므로 권장됩니다.

태그: libpng cmake Visual Studio 2015 PNG zlib

6월 11일 17:23에 게시됨