【C言語】libpngのインストールと使用方法・使用例

libpngの使い方解説ページアイキャッチ

こちらでは Mac に libpng をインストールする手順と libpng を用いたプログラムの例を紹介します。

メモ

試したOSは下記の通りです。他の環境では試せていませんのでご了承ください。

  • macOS HighSierra( バージョン10.13.4)
更新情報

RGB+αの画像形式にも対応しました

ダウンロードされるフォルダ違うなどの違いがありますが、LINUX 環境でも手順は参考になると思います。

libpng とは

libpng は PNG 画像ファイルを扱うためのライブラリです。

この libpng を利用することで、C言語などのプログラムから簡単に PNG 画像を読み込んだり、PNG 画像を作成したりできるようになります。

libpng のインストール

それでは libpng のインストール方法について解説していきます。

このインストールの基本的な流れは下記になります。

  • ダウンロード
  • 設定
  • ライブラリ生成
  • インストール
  • インストールの確認

スポンサーリンク

libpng のダウンロード

まず libpng をダウンロードします。

libpng のダウンロードは下記 URL から行うことができます。

https://sourceforge.net/projects/libpng/files/

最新バージョンは下図の緑色のボタンからダウンロードできます。

2018/9/7 だと 1.6.35 が最新のようでした。

続いてターミナルでダウンロードしたファイルがあるフォルダにアクセスします。ターミナルアプリは「アプリケーション」→「ユーティリティ」にあります。


私がダウンロードしたファイルをダウンロードフォルダに保存しましたので下記コマンドでフォルダにアクセスしました。

cd /Users/[私のユーザ名]/Downloads/

続いてダウンロードした .tar.gz を下記コマンドにより展開します。「libpng-1.6.35.tar.gz」の部分はダウンロードしてきたファイル名に合わせて変更してください

tar xvzf libpng-1.6.35.tar.gz

フォルダが作成され、その中に様々なファイルが展開されるはずです。

私の場合は「libpng-1.6.35」というフォルダが作成されました。展開が完了したら、その作成したフォルダに cd コマンドで移動しましょう。

libpng の設定

続いてそのフォルダで下記コマンドを実行します。これによりあなたの PC 環境に合わせて libpng の設定が行われます。

./configure

このコマンド実行するとメッセージが表示され、1分くらいで処理が完了すると思います。

最後の方のメッセージは下記のような感じでした。良ければご参考に。

checking for size_t... yes
checking whether struct tm is in sys/time.h or time.h... time.h
checking for C/C++ restrict keyword... __restrict
checking for working strtod... yes
checking for memset... yes
checking for pow... yes
checking for clock_gettime... yes
checking for zlibVersion in -lz... yes
checking for feenableexcept in -lm... no
checking for feenableexcept... no
checking if using Solaris linker... no
checking if libraries can be versioned... no
configure: WARNING: *** You have not enabled versioned symbols.
configure: pkgconfig directory is ${libdir}/pkgconfig
configure: Extra options for compiler: 
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating libpng.pc
config.status: creating libpng-config
config.status: creating config.h
config.status: executing depfiles commands
config.status: executing libtool commands

libpng ライブラリの生成

続いて同じフォルダ内で下記 make コマンドを実行します。これにより libpng ライブラリが生成されます。

make

こちらも1分ほどで処理完了します。最後の方のメッセージはこんな感じ。

mv -f $depbase.Tpo $depbase.Po
/bin/sh ./libtool  --tag=CC   --mode=link gcc  -g -O2   -o pngimage contrib/libtests/pngimage.o libpng16.la -lz 
libtool: link: gcc -g -O2 -o .libs/pngimage contrib/libtests/pngimage.o  ./.libs/libpng16.dylib -lz
depbase=`echo contrib/tools/pngcp.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
gcc -DHAVE_CONFIG_H -I.     -g -O2 -MT contrib/tools/pngcp.o -MD -MP -MF $depbase.Tpo -c -o contrib/tools/pngcp.o contrib/tools/pngcp.c &&\
mv -f $depbase.Tpo $depbase.Po
/bin/sh ./libtool  --tag=CC   --mode=link gcc  -g -O2   -o pngcp contrib/tools/pngcp.o libpng16.la -lz 
libtool: link: gcc -g -O2 -o .libs/pngcp contrib/tools/pngcp.o  ./.libs/libpng16.dylib -lz
depbase=`echo contrib/libtests/timepng.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
gcc -DHAVE_CONFIG_H -I.     -g -O2 -MT contrib/libtests/timepng.o -MD -MP -MF $depbase.Tpo -c -o contrib/libtests/timepng.o contrib/libtests/timepng.c &&\
mv -f $depbase.Tpo $depbase.Po
/bin/sh ./libtool  --tag=CC   --mode=link gcc  -g -O2   -o timepng contrib/libtests/timepng.o libpng16.la -lz 
libtool: link: gcc -g -O2 -o .libs/timepng contrib/libtests/timepng.o  ./.libs/libpng16.dylib -lz

スポンサーリンク

libpng のインストール

次に libpng をインストールします。次のコマンドによりインストールが行われるはずです。

sudo make install

コマンドを実行するとパスワードが求められますので、管理者のパスワード(Macのパスワード)を入力してください。

管理者権限でないとファイルの編集や追加削除の権限がなくてコマンド実行しても失敗します。なので、管理者権限でインストールが行えるように、コマンドの最初に sudo を付けています。

インストールはすぐ処理が完了すると思います。最後の方のメッセージを念のため載せておきます。

./install-sh -c -d '/usr/local/share/man/man3'
 /usr/bin/install -c -m 644 libpng.3 libpngpf.3 '/usr/local/share/man/man3'
 ./install-sh -c -d '/usr/local/share/man/man5'
 /usr/bin/install -c -m 644 png.5 '/usr/local/share/man/man5'
 ./install-sh -c -d '/usr/local/include/libpng16'
 /usr/bin/install -c -m 644 pnglibconf.h '/usr/local/include/libpng16'
 ./install-sh -c -d '/usr/local/lib/pkgconfig'
 /usr/bin/install -c -m 644 libpng16.pc '/usr/local/lib/pkgconfig'
 ./install-sh -c -d '/usr/local/include/libpng16'
 /usr/bin/install -c -m 644 png.h pngconf.h '/usr/local/include/libpng16'
/Applications/Xcode.app/Contents/Developer/usr/bin/make  install-data-hook
+ cd /usr/local/include
+ for f in pnglibconf.h png.h pngconf.h
+ rm -f pnglibconf.h
+ ln -s libpng16/pnglibconf.h pnglibconf.h
+ for f in pnglibconf.h png.h pngconf.h
+ rm -f png.h
+ ln -s libpng16/png.h png.h
+ for f in pnglibconf.h png.h pngconf.h
+ rm -f pngconf.h
+ ln -s libpng16/pngconf.h pngconf.h
+ cd /usr/local/lib/pkgconfig
+ rm -f libpng.pc
+ ln -s libpng16.pc libpng.pc

インストールの確認

最後にインストールされたことを確認しておきましょう。

今まで作成したC言語のプログラムファイルをコンパイルしてやるときに、最後に -lpng をつけてからコンパイルしてみてください。下記のような感じです。

gcc japanese.c -o japanese.exe -lpng

-lpng を付けることで libpng へのリンクが行われます。これにより自分のプログラムで PNG 関連の様々な関数が使用可能になります。

エラーが表示されずコンパイルが完了すれば、libpng のインストールに成功です。

インストールがうまくできていなければ下記のようなメッセージが表示されますので再度手順を確認してみてください。

ld: library not found for -lpng
clang: error: linker command failed with exit code 1 (use -v to see invocation)

libpng を使用したPNGファイル読み込み・書き込み関数の作成

続いて、インストールした libpng を用いて PNG ファイルを読み込み・書き込みを行う関数の例を紹介していきたいと思います。

lipng が提供する関数の使い方を詳細に知りたい方はlibpngが提供する関数で紹介している libpng のマニュアルを読んで見てください。

スポンサーリンク

ヘッダーファイル

まずは libpng に関連するヘッダーをインクルードしたり、必要な構造体の定義、PNG ファイルを読み込み・書き込みする関数の定義を行うヘッダーファイルを用意します。

下記がそのヘッダーファイルの例になります。

myPng.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "png.h"

typedef struct{
  unsigned char *data;
  unsigned int width;
  unsigned int height;
  unsigned int ch;
} BITMAPDATA_t;

int pngFileReadDecode(BITMAPDATA_t *, const char*);
int pngFileEncodeWrite(BITMAPDATA_t *, const char*);
int freeBitmapData(BITMAPDATA_t *);

#define SIGNATURE_NUM 8

ポイントを説明していきます。

png.h のインクルード

libpng が提供する関数の宣言や定数等の定義は png.h で行われています。

ですので、libpng を利用する際には、この png.h のインクルードを行う必要があります。

png.hのインクルード
#include "png.h"

BITMAP 形式データ構造体の定義

また、下記では BITMAP 形式データの情報格納用構造体 BITMAPDATA_t を定義しています。

BITMAP情報格納用の構造体
typedef struct{
  unsigned char *data;
  unsigned int width;
  unsigned int height;
  unsigned int ch;
} BITMAPDATA_t;

それぞれのメンバの説明は下記のようになります。

  • data:PNG をデコードした BITMAP 形式画像データの先頭アドレス
  • width:画像の横幅
  • height:画像の高さ
  • ch:画像の色数(RGB+αの時は 4、RGBの時は 3、グレーの時は 1

BITMAP 形式画像データって何?という方は下記ページで説明していますので是非参考にしてください。

画像データの解説ページアイキャッチ画像データの構造・画素・ビットマップデータについて解説

上のページでも解説しているように data のポインタの先は下図のように各ピクセルの RGB 順にデータが並んでいます。

MEMO

RGB+α形式の場合は、各ピクセルがRGBα順にデータが並びます

ソースファイル

次は実際に libpng が提供している関数を利用して PNG ファイルを読み込んだり、PNG ファイルとして保存したりする関数を作成していきます。

myPng.c
#include "myPng.h"

int pngFileReadDecode(BITMAPDATA_t *bitmapData, const char* filename){

  FILE *fi;
  int j;
  unsigned int width, height;
  unsigned int readSize;

  png_structp png;
  png_infop info;
  png_bytepp datap;
  png_byte type;
  png_byte signature[8];

  fi = fopen(filename, "rb");
  if(fi == NULL){
    printf("%sは開けません\n", filename);
    return -1;
  }

  readSize = fread(signature, 1, SIGNATURE_NUM, fi);

  if(png_sig_cmp(signature, 0, SIGNATURE_NUM)){
    printf("png_sig_cmp error!\n");
    fclose(fi);
    return -1;
  }

  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(png == NULL){
    printf("png_create_read_struct error!\n");
    fclose(fi);
    return -1;
  }

  info = png_create_info_struct(png);
  if(info == NULL){
    printf("png_crete_info_struct error!\n");
    png_destroy_read_struct(&png, NULL, NULL);
    fclose(fi);
    return -1;
  }

  png_init_io(png, fi);
  png_set_sig_bytes(png, readSize);
  png_read_png(png, info, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_16, NULL);

  width = png_get_image_width(png, info);
  height = png_get_image_height(png, info);

  datap = png_get_rows(png, info);

  type = png_get_color_type(png, info);
  /* とりあえずRGB or RGBAだけ対応 */
  if(type != PNG_COLOR_TYPE_RGB && type != PNG_COLOR_TYPE_RGB_ALPHA){
    printf("color type is not RGB or RGBA\n");
    png_destroy_read_struct(&png, &info, NULL);
    fclose(fi);
    return -1;
  }

  bitmapData->width = width;
  bitmapData->height = height;
  if(type == PNG_COLOR_TYPE_RGB) {
    bitmapData->ch = 3;
  } else if(type == PNG_COLOR_TYPE_RGBA) {
    bitmapData->ch = 4;
  }
  printf("width = %d, height = %d, ch = %d\n", bitmapData->width, bitmapData->height, bitmapData->ch);

  bitmapData->data =
    (unsigned char*)malloc(sizeof(unsigned char) * bitmapData->width * bitmapData->height * bitmapData->ch);
  if(bitmapData->data == NULL){
    printf("data malloc error\n");
    png_destroy_read_struct(&png, &info, NULL);
    fclose(fi);
    return -1;
  }

  for(j = 0; j < bitmapData->height; j++){
    memcpy(bitmapData->data + j * bitmapData->width * bitmapData->ch, datap[j], bitmapData->width * bitmapData->ch);
  }

  png_destroy_read_struct(&png, &info, NULL);
  fclose(fi);

  return 0;
}

int pngFileEncodeWrite(BITMAPDATA_t *bitmapData, const char *filename){
  FILE *fo;
  int j;

  png_structp png;
  png_infop info;
  png_bytepp datap;
  png_byte type;

  fo = fopen(filename, "wb");
  if(fo == NULL){
    printf("%sは開けません\n", filename);
    return -1;
  }

  png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  info = png_create_info_struct(png);

  if(bitmapData->ch == 3) {
    type = PNG_COLOR_TYPE_RGB;
  } else if(bitmapData->ch == 4) {
    type = PNG_COLOR_TYPE_RGB_ALPHA;
  } else {
    printf("ch num is invalid!\n");
    png_destroy_write_struct(&png, &info);
    fclose(fo);
    return -1;
  }
  png_init_io(png, fo);
  png_set_IHDR(png, info, bitmapData->width, bitmapData->height, 8, type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

  datap = png_malloc(png, sizeof(png_bytep) * bitmapData->height);

  png_set_rows(png, info, datap);

  for(j = 0; j < bitmapData->height; j++){
    datap[j] = png_malloc(png, bitmapData->width * bitmapData->ch);
    memcpy(datap[j], bitmapData->data + j * bitmapData->width * bitmapData->ch, bitmapData->width * bitmapData->ch);
  }
  png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL);

  for(j = 0; j < bitmapData->height; j++){
    png_free(png, datap[j]);
  }
  png_free(png, datap);

  png_destroy_write_struct(&png, &info);
  fclose(fo);
  return 0;
}


int freeBitmapData(BITMAPDATA_t *bitmap){
  if(bitmap->data != NULL){
    free(bitmap->data);
    bitmap->data = NULL;
  }
  return 0;
}

特に PNG の読み込みを行う pngFileReadDecode 関数と、PNG の書き込みを行う pngFileEncodeWrite 関数の詳細を解説していきます。

PNG ファイルの読み込みを行う関数

pngFileReadDecode 関数は PNG ファイルの読み込みを行う関数になります。

pngFileReadDecode の処理の流れは下記の通りです。

  • シグネチャの読み込み
  • PNG ファイルかどうかの判断
  • 必要な構造体の生成
  • シグネチャサイズの設定
  • PNG ファイルの読み込み
  • 画像情報取得
  • BITMAP をメモリへコピー
  • 生成した構造体の削除

ここから各処理の詳細を解説していきます。

シグネチャの読み込み

下記では PNG ファイルのシグネチャ部分の読み込みを行っています。

PNG ではファイルの先頭の8バイトはシグネチャというデータであり、PNG であることを示すデータが格納されています。

なので、先頭の8バイトを調べることで、そのファイルが PNG ファイルであるかを調べることができます。

fread 関数に指定している SIGNATURE_NUMmyPng.h で定義しているシグネチャのサイズ、つまり 8 になります。

シグネチャの読み込み
  fi = fopen(filename, "rb");
  if(fi == NULL){
    printf("%sは開けません\n", filename);
    return -1;
  }

  readSize = fread(signature, 1, SIGNATURE_NUM, fi);

PNG ファイルかどうかの判断

下記では読み込むファイルが PNG かどうかの判断を行っています。

PNG でないファイルの場合は libpng でデコードできないので、PNG でない場合は関数を終了させています。

PNGかどうかの判断
  if(png_sig_cmp(signature, 0, SIGNATURE_NUM)){
    printf("png_sig_cmp error!\n");
    return -1;
  }

必要な構造体の生成

下記では png_read 構造体と png_info 構造体の生成を行っています。

この2つは PNG の読み込みやデコード処理に必要で、今後の処理は主にこの2つを用いて実行していくことになります。

必要な構造体の生成
  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  info = png_create_info_struct(png);

png_create_read_structpng_read 構造体を生成する関数で、第1引数には libpng のバージョンである PNG_LIBPNG_VER_STRING を指定します。

第2引数以降はエラーや警告時に特別な処理を行いたい場合には指定する必要があるようですが、今回は不要なので NULL にしています。

png_create_info_structpng_info 構造体を生成する関数で、引数には事前に生成した png_read 構造体を指定します。

読み込み先ファイルの設定

下記では PNG ファイルとして読み込むファイルの設定を行っています。

読み込み先ファイルの設定
  png_init_io(png, fi);

シグネチャサイズの設定

次にシグネチャサイズを下記で設定します。これはおそらく、既に読み込んだサイズを指定するための処理になると思います。

シグネチャサイズの設定
  png_set_sig_bytes(png, readSize);

PNG ファイルの読み込み

続いて PNG ファイルを下記で読み込んでいます。

PNGの読み込み
  png_read_png(png, info, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_16, NULL);

第3引数の指定により、読み込んだ PNG の画像データの変換を行うことができます。

今回は下記の2つの指定を行っています。要は各画素の輝度値を 8 ビットで扱うための指定を行っています。

  • PNG_TRANSFORM_PACKING:輝度値が 1, 2, 4 ビットのデータの場合は 8 ビットのデータに変換する
  • PNG_TRANSFORM_STRIP_16:輝度値が 16 ビットのデータの場合は 8 ビットのデータに変換する

画像情報取得

下記では読み込んだ PNG から画像データの情報を取得しています。

画像情報取得
  width = png_get_image_width(png, info);
  height = png_get_image_height(png, info);
  datap = png_get_rows(png, info);
  type = png_get_color_type(png, info);

datap には PNG を BITMAP にデコードしたデータのアドレスが格納されます(この時点でデコードが行われています)。より具体的には、各ライン(各行)のデータのアドレスへのポインタになります。

type は PNG の色の形式を表しており、このプログラムでは RGB と RGB+α のみをサポートしています。

BITMAP をメモリへコピー

下記では PNG のデコード結果である BITMAP データを事前に malloc 関数で確保したメモリへのコピーを行っています。

各ラインごとに memcpy 関数でコピーしています。

BITMAP のメモリへのコピー
  for(j = 0; j < bitmapData->height; j++){
    memcpy(bitmapData->data + j * bitmapData->width * bitmapData->ch, datap[j], bitmapData->width * bitmapData->ch);
  }

生成した構造体の削除

以上で PNG をデコードした BITMAP データが取得できたことになりますので、最後に生成した構造体を下記で削除しています。

生成した構造体の削除
  png_destroy_read_struct(&png, &info, NULL);

スポンサーリンク

PNG ファイルの書き込みを行う関数

pngFileEncodeWrite 関数は PNG ファイルの書き込み(保存)を行う関数になります。

pngFileEncodeWrite の処理の流れは下記の通りです。

  • 必要な構造体の生成
  • 書き込み先ファイルの設定
  • 色情報の設定
  • ヘッダの設定
  • 画像情報を BITMAPDATA_t へ格納
  • エンコード&ファイル書き込み
  • 生成した構造体の削除

ここから各処理の詳細を解説していきます。

必要な構造体の生成

下記では読み込み時同様に、png_write 構造体と png_info 構造体の生成を行っています。

この2つは PNG の書き込みやエンコード処理に必要で、今後の処理は主にこの2つを用いて実行していくことになります。

必要な構造体の生成
  png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  info = png_create_info_struct(png);

書き込み先ファイルの設定

続いて下記で書き込み先のファイルの設定を行っています。

書き込み先ファイルの設定
  png_init_io(png, fo);

色情報の設定

下記では作成する PNG ファイルの色情報を設定しています。

色情報の設定
  if(bitmapData->ch == 3) {
    type = PNG_COLOR_TYPE_RGB;
  } else if(bitmapData->ch == 4) {
    type = PNG_COLOR_TYPE_RGB_ALPHA;
  } else {
    printf("ch num is invalid!\n");
    return -1;
  }

エンコードする画像の情報である BITMAPDATA_t 構造体の ch に色数が格納されていますので、色数が 3 の時は RGB を、色数が 4 の時は RGB+α を表す色情報をそれぞれで設定しています。

ヘッダの設定

下記で作成する PNG のヘッダの設定を行っています。

ヘッダの設定
  png_set_IHDR(png, info, bitmapData->width, bitmapData->height, 8, type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

このヘッダには PNG の画像がどのようなものであるかを表すデータが格納されますので、png_set_IHDR の引数には、例えばその画像の幅や高さ、輝度値のビット数などを指定して実行します。

BITMAP データの設定

下記では libpng に PNG にエンコードしてもらう BITMAP データの設定を行っています。

BITMAP データの設定
  datap = png_malloc(png, sizeof(png_bytep) * bitmapData->height);

  png_set_rows(png, info, datap);

  for(j = 0; j < bitmapData->height; j++){
    datap[j] = png_malloc(png, bitmapData->width * bitmapData->ch);
    memcpy(datap[j], bitmapData->data + j * bitmapData->width * bitmapData->ch, bitmapData->width * bitmapData->ch);
  }

png_malloc 関数でエンコードしてもらいたい BITMAP データを格納するためのメモリを確保し、さらに png_set_rows でそのメモリのアドレスを設定し、最後にそのアドレスに BITMAP データをコピーしています。

エンコード&ファイル書き込み

下記で、先ほど設定したアドレスに格納された BITMAP データの PNG へのエンコードおよびファイル書き込みを行っています。

エンコード&ファイル書き込み
  png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL);

読み込み時同様に第3引数でデータの変換を行うことが可能ですが、今回はデータをそのまま書き込みするように PNG_TRANSFORM_IDENTITY を指定しています。

生成した構造体の削除

以上で PNG のエンコードおよびファイル書き込みができたことになりますので、最後に生成した構造体を下記で削除しています。

生成した構造体の削除
  png_destroy_write_struct(&png, &info, NULL);

作成した PNG 読み込み・書き込み関数の使用例

上記で作成した関数の使い方がイメージつくように使用例を書いてみました。

main.c
#include "myPng.h"

int main(int argc, char *argv[]){

  BITMAPDATA_t bitmap;
  int i, j, c;
  int ave, sum;
  char outname[256];

  FILE *fo;

  if(argc != 2){
    printf("ファイル名が指定されていません\n");
    return -1;
  }

  if(pngFileReadDecode(&bitmap, argv[1]) == -1){
    printf("pngFileReadDecode error\n");
    return -1;
  }

  printf("bitmap->data = %p\n", bitmap.data);
  printf("bitmap->width = %d\n", bitmap.width);
  printf("bitmap->height = %d\n", bitmap.height);
  printf("bitmap->ch = %d\n", bitmap.ch);

  /* グレースケールに変換 */
  for(j = 0; j < bitmap.height; j++){
    for(i = 0; i < bitmap.width; i++){
      sum = 0;
      for(c = 0; c < bitmap.ch; c++){
        sum += bitmap.data[bitmap.ch * (i + j * bitmap.width) + c];
      }
      ave = sum / bitmap.ch;
      for(c = 0; c < bitmap.ch; c++){
        bitmap.data[bitmap.ch * (i + j * bitmap.width) + c] = ave;
      }
    }
  }

  sprintf(outname, "%s", "output.PNG");

  if(pngFileEncodeWrite(&bitmap, outname) == -1){
    printf("pngFileEncodeWrite error\n");
    freeBitmapData(&bitmap);
    return -1;
  }

  freeBitmapData(&bitmap);

  return 0;
}

処理の流れ

この main 関数の処理の流れは下記の通りです。

  1. pngFileReadDecode 関数を使用して PNG ファイルの読み込みデコード
  2. 1. でデコードした BITMAP データに対して画像処理
  3. 2. 画像処理後の BITMAP データを pngFileEncodeWrite 関数を使用してエンコード & PNG ファイルへの書き込み
  4. freeBitmapData 関数でメモリ解放して終了

画像処理

2. の画像処理では、1. でデコードした画像をグレースケールに変換しています(単純に RGB の輝度値の平均値を求めているだけ)。

画像処理をいろいろ試す場合はここをいろいろ変更して試してみると良いと思います。

画像処理
  /* グレースケールに変換 */
  for(j = 0; j < bitmap.height; j++){
    for(i = 0; i < bitmap.width; i++){
      sum = 0;
      for(c = 0; c < bitmap.ch; c++){
        sum += bitmap.data[bitmap.ch * (i + j * bitmap.width) + c];
      }
      ave = sum / bitmap.ch;
      for(c = 0; c < bitmap.ch; c++){
        bitmap.data[bitmap.ch * (i + j * bitmap.width) + c] = ave;
      }
    }
  }

コンパイル

このページで紹介するソースコードでは、PNG 読み込み用・書き込み用の関数を myPng.c に作成し、それらの関数のプロトタイプ宣言をヘッダーファイルの myPng.h で行っています。

ですので、上記のソースコードで myPng.h のインクルードを行なっています。

違う名前にする場合は変更必要ですのでお気をつけください。

このページで紹介しているファイル名でソースコードファイルを作成している時、下記のコマンドでコンパイルとプログラムの実行が可能です。

gcc main.c -c
gcc myPng.c -c
gcc main.o myPng.o -o png.exe -lpng
./png.exe test.png

前にも説明していますが、重要なのはコンパイル時に -lpng を付けることです。これは libpng にリンクするためのコンパイルオプションになります。

実行結果

引数で読み込みたい PNG ファイルへのパスを指定して実行すれば、その PNG ファイルをモノクロ化した PNG ファイル output.png が出力されます。

入力した PNG と出力結果の PNG もここに表示しておきます(このファイルであれば動作確認しています)。

・入力PNG

・出力PNG

このページに載せたソースコードはあくまで一例です。

PNGファイルを読み込んでデコードするあたりや PNG ファイルをエンコードして書き込むあたりはご自身が使いやすいようにカスタマイズしてください。

libpng が提供する関数

libpng については下記にてマニュアルが公開されています。

英語ですが、ファイルの読み込み方などがかなり詳しく説明されていますので、libpng 使ってプログラミングしたい人は一読しておくと良いと思います。

http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf

注意

このページは libpng インストール方法や使用例の紹介を目的としたページであり、libpng のライセンス体系については私も詳しくないのでこのページでは言及していません

libpng を使用する方は自己責任で使用してください

例えば商用利用等を行う場合はライセンス体系についてご自分で調査してから使用の可否をご判断くださ

スポンサーリンク

まとめ

このページでは PNG の読み込み・書き込みを行うライブラリである libpng のインストール方法とその使い方について解説しました。

PNG は可逆圧縮フォーマットなので再保存しても劣化がありませんし、アルファチャンネルも使えるのでいろんな画像を扱った画像処理も可能です。

libpng は、そんな PNG を簡単に読み込み・書き込みできるライブラリですので、是非このページを参考にしてインストールしてみてください。

私のサイトでは他にも LibTIFF や libjpeg、libwebp のインストール方法や使い方についても解説していますので、他の画像フォーマットを利用したい方は是非下記のページも読んでみてください。

libtiffの使い方解説ページアイキャッチ【C言語】LibTIFFのインストールと使用方法・使用例 libjpegの使い方解説ページアイキャッチ【C言語】libjpegのインストールと使用方法・使用例 libwebpの使い方解説ページアイキャッチ【C言語】libwebpのインストールと使用方法・使用例

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です