×

[PR]この広告は3ヶ月以上更新がないため表示されています。
ホームページを更新後24時間以内に表示されなくなります。

 ホームへ 本編1  007-10(1)  本編2  007-10(2)
png.h libpng.txt  readme 訳  LISENCE 訳  TODO 訳
libpng1.2.8   libpng.txt  訳

<以下の訳を読むにあたって>
     以下の訳は筆者が個人で訳したものです。
下記に間違い、誤訳等があったとしても当方は一切責任を負えません(英語苦手なので)。
正確な情報を求める方は必ず原文をお読みください。

libpng.txt
目次 (libpng.txt は重要なのですが、長くて読みづらいので便宜を図るためにココに各項リンクの目次おいときます)
   1 I.序文    5 V.libpng の変更・カスタマイズ     9 IX.2000年問題
2 II.構造体 6 VI.ランタイム
3 III.読み込み 7 VII.MNG
4 IV.書込み 8 VIII.0.88からの変更
英文
libpng.txt - libpng の変更と使用方法の記述 libpng.txt - A description on how to use and modify libpng

 libpng バージョン 1.2.8 - 2004/12/3
 Glenn Randers-Pehrson による配信と更新
 <users.sourceforge.net 内 glennrp>
 著作 (c) 1998-2004 Glenn Randers-Pehrson
 使用と配信の状況については、png.h の著作権情報を見て下さい。

 libpng version 1.2.8 - December 3, 2004
 Updated and distributed by Glenn Randers-Pehrson
 <glennrp at users.sourceforge.net>
 Copyright (c) 1998-2004 Glenn Randers-Pehrson
 For conditions of distribution and use, see copyright
 notice in png.h.

 基本:

 libpng 1.0 beta 6  バージョン 0.96  1997/5/28
 Andreas Dilger による配信と更新
 著作 (c) 1996, 1997 Andreas Dilger

 based on:

 libpng 1.0 beta 6  version 0.96 May 28, 1997
 Updated and distributed by Andreas Dilger
 Copyright (c) 1996, 1997 Andreas Dilger

 libpng 1.0 beta 2 - バージョン 0.88   1996/1/26
 使用と配信の状況については、png.h の著作権情報を見て下さい。
 著作 (c) 1995, 1996 Guy Eric
 Schalnat, Group 42, Inc.

 libpng 1.0 beta 2 - version 0.88  January 26, 1996
 For conditions of distribution and use, see copyright
 notice in png.h. Copyright (c) 1995, 1996 Guy Eric
 Schalnat, Group 42, Inc.

 libpng FAQ の要求による 更新/加筆
 著作 (c) 1995, 1996 Frank J. T. Wojcik
 1995/12/18 & 1996/1/20

 Updated/rewritten per request in the libpng FAQ
 Copyright (c) 1995, 1996 Frank J. T. Wojcik
 December 18, 1995 & January 20, 1996

I. 序文


I. Introduction


このファイルはPNG リファレンス・ライブラリ (ご承知のlibpngです) の変更と使用方法について、あなた自身が使うために書かれています。5 節に分かれており、序文構造 体読み込み書込み変更及び設定が、いろいろな特殊なプラット フォームについて書かれています。このファイルに加え、example.c はライブラリを使うためのいい第一歩になります。
大量のコメントが書かれ、大体必要となるものはみんな含まれています。また既に libpng をインストール済みかとは思いますが、libpng のインストール方法の説明が書いてあるファイル INSTALL を見て下さい。

libpng は アプリケーション・プログラムが PNG ファイルフォーマットをサポートすることに専念するための時間と労力を減らす一手段として、PNG 仕様書の手引きとして書かれています。

This file describes how to use and modify the PNG reference library (known as libpng) for your own use.  There are five sections to this file: introduction, structures, reading, writing, and modification and configuration notes for various special platforms.  In addition to this file, example.c is a good starting point for using the library, as it is heavily commented and should include everything most people will need.  We assume that libpng is already installed; see the INSTALL file for instructions on how to install libpng.

Libpng was written as a companion to the PNG specification, as a way of reducing the amount of time and effort it takes to support the PNG file format in application programs.

PNG 仕様書 (第2版)、2003年11月、は、W3C Recommendation や ISO Standard (ISO/IEC 15948:2003 (E)) などのようなところで入手可能です。
<http://www.w3.org/TR/2003/REC-PNG-20031110/
W3C や ISO 文書には全く同じテクニカル・コンテンツ。

PNG-1.2 仕様書はこちらで入手可能です。
<http://www.libpng.org/pub/png/documents/>

The PNG-1.0 仕様書は
RFC 2083 <http://www.libpng.org/pub/png/documents/> や W3C Recommendation <http://www.w3.org/TR/REC.png.html> などのようなところで入手可能です。 加えられたチャンクは、
<http://www.libpng.org/pub/png/documents/> の特殊用途の公式チャンク文書で述べられています。

The PNG specification (second edition), November 2003, is available as a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at
<http://www.w3.org/TR/2003/REC-PNG-20031110/
The W3C and ISO documents have identical technical content.

The PNG-1.2 specification is available at
<http://www.libpng.org/pub/png/documents/>

The PNG-1.0 specification is available
as RFC 2083 <http://www.libpng.org/pub/png/documents/> and as a W3C Recommendation <http://www.w3.org/TR/REC.png.html>. Some additional chunks are described in the special-purpose public chunks documents at <http://www.libpng.org/pub/png/documents/>.


他の情報
PNGに関する事、libpng の最新バージョン、などはPNG ホームページ
<http://www.libpng.org/pub/png/> で見ることができます。

大抵の人はライブラリをそんなに変更することはないと思いますが、先進的なユーザはもっと変えたいと思うかもしれません。全て、簡単に理解できるような コードのまま、できるだけ完璧に作られるように、計画されました。 現在のところ、このライブラリは C でだけサポートしています。他言語のサポートは検討中です。

Other information
about PNG, and the latest version of libpng, can be found at the PNG home page, <http://www.libpng.org/pub/png/>.

Most users will not have to modify the library significantly; advanced users may want to modify it more.  All attempts were made to make it as complete as possible, while keeping the code easy to understand. Currently, this library only supports C.  Support for other languages is being considered.

libpng は1度に複数のセッションを処理でき、簡単に修正可能で、ほぼ全てのマシン (ANSI, K&R, 16, 32, 64ビット)に移植可能であり、簡単に使えるように、設計されました。libpng の最大の目的はできる限り PNG ファイルフォーマットが対応されるよう促進することです。いまだそういう作業が行われている(TODO ファイルを見て下さい)間は、libpng はそういったユーザのニーズの大半をカバーすべきでしょう。

Libpng has been designed to handle multiple sessions at one time, to be easily modifiable, to be portable to the vast majority of machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy to use.  The ultimate goal of libpng is to promote the acceptance of the PNG file format in whatever way possible.  While there is still work to be done (see the TODO file), libpng should cover the majority of the needs of its users.

libpng は PNG ファイルの圧縮・解凍に zlib を使います。
zlib に関するより多くの情報及び zlib の最新バージョンは zlib ホームページにあります。
<http://www.info-zip.org/pub/infozip/zlib/>.
zlib 圧縮ユーティリティはPNG ファイルよりもっと一般的な目的のためにあるユーティリティであり、また libpng が無くても使えます。詳細は zlib の配布文書を見て下さい。通常 libpng ソースファイルがあるところには zlib ソースファイルもあります。

Libpng uses zlib for its compression and decompression of PNG files.
Further information about zlib, and the latest version of zlib, can be found at the zlib home page,
<http://www.info-zip.org/pub/infozip/zlib/>.
The zlib compression utility is a general purpose utility that is useful for more than PNG files, and can be used without libpng. See the documentation delivered with zlib for more details.
You can usually find the source files for the zlib utility wherever you find the libpng source files.

libpng はスレッドセーフです。 スレッドは構造体の異なるインスタンスを使えます。各スレッドはそれぞれの png_struct 及び png_info インスタンス ひいては、それぞれで画像を保持する必要があります。
libpng は構造体の同じインスタンスを使う2スレッドに対してはそれ自身を保護しません。注: スレッドセーフはユーザが PNG_THREAD_UNSAFE_OK を定義してコンパイルしたときだけ pnggccrd.c 内に MMX アセンブラ・コードが使われるコトにより無効化されます。

Libpng is thread safe, provided the threads are using different instances of the structures.  Each thread should have its own png_struct and png_info instances, and thus its own image.
Libpng does not protect itself against two threads using the same instance of a structure.  Note: thread safety may be defeated by use of some of the MMX assembler code in pnggccrd.c, which is only compiled when the user defines PNG_THREAD_UNSAFE_OK.

II. 構造体


II. Structures


libpng には重要な2つのメインとなる構造体があります、png_struct と  png_info です。先ず、png_struct ですが、そういうつもりはないんですが内部用構造体になっており、ほとんどの部分で使います。またすべての libpng 関数の第一引数である一方で、ユーザもまた使えます。

png_info構造体は PNG ファイルの情報を扱うために設計されました。同時に、png_info のフィールドはユーザに直接アクセスさせるつもりでした。しかしこれは、ダイナミック・ロード・ライブラリを使うアプリケーションで問題を引き起こす要因 となりがちでしたし、結果としてpng_info用インターフェース関数 (png_get_*() と png_set_*() 関数)のセットが開発されました。
png_info のフィールドは古いアプリケーション用に利用可能だったりしますが、アプリケーションは可能な限り新しいインターフェースを使うことをお勧めします。

There are two main structures that are important to libpng, png_struct and png_info.  The first, png_struct, is an internal structure that will not, for the most part, be used by a user except as the first variable passed to every libpng function call.

The png_info structure is designed to provide information about the PNG file.  At one time, the fields of png_info were intended to be directly accessible to the user.  However, this tended to cause problems with applications using dynamically loaded libraries, and as a result a set of interface functions for png_info (the png_get_*() and png_set_*() functions) was developed.  The fields of png_info are still available for older applications, but it is suggested that applications use the new interfaces if at all possible.

png_struct のメンバ(png_ptr->jmpbufを除く)に直接アクセスするようなアプリケーションはライブラリが更新される度、再コンパイルしなければ なりません。また png_info に直接アクセスするようなアプリケーションは libpng バージョン 1.0.6を読み込んだりコンパイルされたとき、メンバ変数の並びが異なるため、再コンパイルしなければなりません。
バージョン 1.0.7 では、png_info 構造体のメンバはバージョン 0.97c 〜 1.0.5 にあったような古い並び順に戻りました。バージョン 2.0.0 から始めらる両構造体は隠れて見えなくなる計画で、構造体の中身はpng_get/png_set 関数を通してのみアクセス可能にする予定です。

Applications that do make direct access to the members of png_struct (except for png_ptr->jmpbuf) must be recompiled whenever the library is updated, and applications that make direct access to the members of png_info must be recompiled if they were compiled or loaded with libpng version 1.0.6, in which the members were in a different order.  In version 1.0.7, the members of the png_info structure reverted to the old order, as they were in versions 0.97c through 1.0.5.  Starting with version 2.0.0, both structures are going to be hidden, and the contents of the structures will only be accessible through the png_get/png_set functions.

png.h ヘッダファイルは libpng を使うプログラミングでは貴重なリファレンスです。とまあこんな事を書いてるうちは、libpng ヘッダファイルをインクルードしてるか確認して下さい:

#include <png.h>

The png.h header file is an invaluable reference for programming with libpng. And while I'm on the topic, make sure you include the libpng header file:

#include <png.h>

III. 読込


III. Reading


PNG ファイルをシーケンシャルに読込時に使う関数を、私たちはあなたとウォークスルー・モデルで開発していこうと思ってます。 簡潔にいうと、シンタックス及び各自の目的のためです。詳細は example.c や png.h を見て下さい。プログレッシブな読込が次の項で議題として取り上げられている間は、依然としてPNG ファイルを読込むにはこの項で論考された関数を使うことになります。


We'll now walk you through the possible functions to call when reading in a PNG file sequentially, briefly explaining the syntax and purpose of each one.  See example.c and png.h for more detail.  While progressive reading is covered in the next section, you will still need some of the functions discussed in this section to read a PNG file.

●用語の解説
ウォークスルー・モデル 【walk through model】
 プログラム開発後に、複数の人間でバグ修正や再評価、仕様変更を行う開発方法。

 <参考>
 ウォーターフォール・モデル【water fall model 】
   仕様書に基づき各工程を分割して開発を進める最も一般的・古典的な開発方法。
 スパイラル・モデル【spiral model 】
   最初に大まかな設計を決めて仮組みしてしまい、顧客などからのフィードバックを元に詳細な設計をしていく開発方法。
 RUP【Rational Unified Process 】
   ラショナル統一プロセス。開発現場で要求、分析、設計、開発、テスト、評価といった流れを繰り返す開発手法。米ラショナル社パッケージ。
 プロトタイピング 【prottyping】
    ネットゲームなどのように、まず試作品を作りユーザの反応をみながら徐々に完成させる開発手法。
 XP 【ExtermeProgramming】
   プログラマは人間であるという思想のもと開発初期からテストを繰り返す開発手法。
 クロス開発 【cross development】
   動作するシステムとは違うシステム上でソフトウェアを開発する手法。電化製品、一般ゲーム機の開発などがこれにあたる。
 MVC 【Model-View-Controller】
   処理の中核を担う「Model」、表示・出力を司る「View」、入力をを制御する「Controller」の3要素の組み合わせで実装する方式。


セットアップ

libpng に入る前に I/O の初期化を行いたいと思います。多くの課題が無いことも無いのですが、それはやりません。もちろん、自分でやろうなんて考える方もいるかと思いますが、実 際のところは、各 PNG ファイルで処理しています。libpng はPNG ファイルの読込時に、単純な確認が行えます。
使い方は、ファイルの最初の1〜8バイトを png_sig_cmp() 関数に渡します。PNG シグネチャのバイトと一致すれば 0 を返し、そうでなければ非ゼロを返します。もちろん、より多くのバイトを渡せば、確認精度は上がります。


Setup

You will want to do the I/O initialization(*) before you get into libpng, so if it doesn't work, you don't have much to undo.  Of course, you will also want to insure that you are, in fact, dealing with a PNG file.  Libpng provides a simple check to see if a file is a PNG file.
To use it, pass in the first 1 to 8 bytes of the file to the function png_sig_cmp(), and it will return 0 if the bytes match the corresponding bytes of the PNG signature, or nonzero otherwise.  Of course, the more bytes you pass in, the greater the accuracy of the prediction.


libpng で使うために開いたファイルのファイルポインタを自分で保持するなら、確実にファイルの先頭から8バイト以上読込まないようにし、さらに先頭から読みこん だバイト数を使ってpng_set_sig_bytes_read() 関数を呼ぶ必要があります。ここでは libpng はプログラムが(何も)読込めなかったかどうかだけ、チェックを行います。

※ もし標準 I/O 関数を使わないのであれば、それらをカスタム関数に置き換えることもできます。下の方の「libpng のカスタマイズ」の論考を見て下さい。


If you are intending to keep the file pointer open for use in libpng, you must ensure you don't read more than 8 bytes from the beginning of the file, and you also have to make a call to png_set_sig_bytes_read() with the number of bytes you read from the beginning.  Libpng will then only check the bytes (if any) that your program didn't read.

(*): If you are not using the standard I/O functions, you will need to replace them with custom functions.  See the discussion under Customizing libpng.


    FILE *fp = fopen(file_name, "rb");
    if (!fp)
    {
        return (ERROR);
    }
    fread(header, 1, number, fp);
    is_png = !png_sig_cmp(header, 0, number);
    if (!is_png)
    {
        return (NOT_PNG);
    }


    FILE *fp = fopen(file_name, "rb");
    if (!fp)
    {
        return (ERROR);
    }
    fread(header, 1, number, fp);
    is_png = !png_sig_cmp(header, 0, number);
    if (!is_png)
    {
        return (NOT_PNG);
    }


次に、png_struct と png_info で必要なメモリ確保と初期化です。これらの構造体サイズがダイナミックリンクライブラリのlibpng と間違いなく同じであるようにするため に、その構造体をメモリ確保及び初期化する関数があります。私たちが採択したライブラリ・バージョンでは、エラー処理関数へのポインタや、またエラー処理 関数が使う構造体へのポインタが追加され、必要に応じて(ポインタや関数は、デフォルトのハンドラを使うならNULLで大丈夫です)使うことができます。 旧・初期化関数については、下記の「libpng への変更」の項を見て下さ い。構造体メモリ確保関数は、構造体の生成に失敗したら黙ってNULLを返すので、アプリケーションはそれを確認してください。

    png_structp png_ptr = png_create_read_struct
       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
        user_error_fn, user_warning_fn);
    if (!png_ptr)
        return (ERROR);

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_read_struct(&png_ptr,
           (png_infopp)NULL, (png_infopp)NULL);
        return (ERROR);
    }

    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info)
    {
        png_destroy_read_struct(&png_ptr, &info_ptr,
          (png_infopp)NULL);
        return (ERROR);
    }


Next, png_struct and png_info need to be allocated and initialized.  In order to ensure that the size of these structures is correct even with a dynamically linked libpng, there are functions to initialize and allocate the structures.  We also pass the library version, optional pointers to error handling functions, and a pointer to a data struct for use by the error functions, if necessary (the pointer and functions can be NULL if the default error handlers are to be used).  See the section on Changes to Libpng below regarding the old initialization functions. The structure allocation functions quietly return NULL if they fail to create the structure, so your application should check for that.

    png_structp png_ptr = png_create_read_struct
       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
        user_error_fn, user_warning_fn);
    if (!png_ptr)
        return (ERROR);

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_read_struct(&png_ptr,
           (png_infopp)NULL, (png_infopp)NULL);
        return (ERROR);
    }

    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info)
    {
        png_destroy_read_struct(&png_ptr, &info_ptr,
          (png_infopp)NULL);
        return (ERROR);
    }


もし自前のメモリ確保ルーチンを使いたいのなら、 PNG_USER_MEM_SUPPORTED を define して png_create_read_struct() の代わりにpng_create_read_struct_2() を使ってください:

    png_structp png_ptr = png_create_read_struct_2
       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
        user_error_fn, user_warning_fn, (png_voidp)
        user_mem_ptr, user_malloc_fn, user_free_fn);

png_create_read_struct()に渡すエラー処理ルーチンと、png_create_struct_2() に渡すメモリ確保/解放ルーチンは、libpng 提供のエラー処理及びメモリ確保関数を使わない場合の、必要な方だけにして下さい。

libpng でエラーが発生したら、longjmp でそのルーチンに戻ることになります。なのでその場合、setjmp を呼び、自分の png_jmpbuf(png_ptr) に渡す必要があります。また異なるルーチンからファイルを読み込んだ場合、png_*() 関数呼ぶような新ルーチンに入るたび、その都度 jmpbuf 変数を更新する必要があります。

setjmp/longjmp の情報に関しては自分のコンパイラの setjmp/longjmp の文書を見て下さい。libpng のエラー処理の詳細情報は下記の「libpng のカスタマイズ」の libpng のエラー処理に関する論考を見て下さい。エラーが発生し、libpng の longjmp で自分の setjmp に制御がきたら、メモリを解放するため png_destroy_read_struct() を呼んで下さい。

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr,
           &end_info);
        fclose(fp);
        return (ERROR);
    }

もし、setjmp/longjmp の結果の複雑さから逃れたいのなら、PNG_SETJMP_NOT_SUPPORTED で libpng をコンパイルできます。この場合、エラー時には デフォルトで abort() になっている PNG_ABORT() が呼ばれることになります。


If you want to use your own memory allocation routines, define PNG_USER_MEM_SUPPORTED and use png_create_read_struct_2() instead of png_create_read_struct():

    png_structp png_ptr = png_create_read_struct_2
       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
        user_error_fn, user_warning_fn, (png_voidp)
        user_mem_ptr, user_malloc_fn, user_free_fn);

The error handling routines passed to png_create_read_struct() and the memory alloc/free routines passed to png_create_struct_2() are only necessary if you are not using the libpng supplied error handling and memory alloc/free functions.

When libpng encounters an error, it expects to longjmp back to your routine.  Therefore, you will need to call setjmp and pass your png_jmpbuf(png_ptr).  If you read the file from different routines, you will need to update the jmpbuf field every time you enter a new routine that will call a png_*() function.

See your documentation of setjmp/longjmp for your compiler for more information on setjmp/longjmp.  See the discussion on libpng error handling in the Customizing Libpng section below for more information on the libpng error handling.  If an error occurs, and libpng longjmp's back to your setjmp, you will want to call png_destroy_read_struct() to free any memory.

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr,
           &end_info);
        fclose(fp);
        return (ERROR);
    }

If you would rather avoid the complexity of setjmp/longjmp issues, you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case errors will result in a call to PNG_ABORT() which defaults to abort().


今度は入力コードのセットアップが必要です。libpng のデフォルトでは C 関数 fread() を使います。これを使う場合、有効な FILE* を png_init_io() に渡す必要があります。必ずファイルはバイナリ・モードで開いておいてください。もし、ちがう方法によるデータ読 込ハンドルを使うのなら png_init_io() 関数を呼ぶ必要は無くなりますが、かわりに、下記「libpng のカスタマイズ」の項で論考された libpng I/O 命令を実装しなければならなくなります。

    png_init_io(png_ptr, fp);

もし、前もってファイルを開いていて、頭からシグネチャを読み込んで確認してあって、PNG ファイルであることがわかっていれば、ファイルのスタートから何バイトか読み飛ばしていることを知らせる必要があります。

    png_set_sig_bytes(png_ptr, number);

Now you need to set up the input code.  The default for libpng is to use the C function fread().  If you use this, you will need to pass a valid FILE * in the function png_init_io().  Be sure that the file is opened in binary mode.  If you wish to handle reading data in another way, you need not call the png_init_io() function, but you must then implement the libpng I/O methods discussed in the Customizing Libpng section below.

    png_init_io(png_ptr, fp);

If you had previously opened the file and read any of the signature from the beginning in order to see if this was a PNG file, you need to let libpng know that there are some bytes missing from the start of the file.

    png_set_sig_bytes(png_ptr, number);


コールバック・コードのセットアップ

入力ストリーム中の不定のチャンクを処理するコールバック関数をセットアップすることもできます。が、そういう関数は自分で用意しなければなりません。

    read_chunk_callback(png_ptr ptr,
         png_unknown_chunkp chunk);
    {
       /* 自前チャンクデータを含む不定チャンク構造体: */
           png_byte name[5];
           png_byte *data;
           png_size_t size;
       /* CRC処理はすでに libpng が管理していることに
           注意して下さい。 */

       /* 自前コードはここに書いてください。
           下記のうち一つを返すようにしてください: */

       return (-n); /* チャンク・エラー有り */
       return (0); /* 判別不能 */
       return (n); /* 成功 */
    }

("read_chunk_callback" ではない、好きな自前の関数名も使えます)

次の関数を使用して、自前関数に関する情報を libpng に与えて下さい。

    png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr,
        read_chunk_callback);

これはコールバック関数だけでなく、次の取得関数のようなユーザ・ポインタにも命名できます。

    png_get_user_chunk_ptr(png_ptr);

ここで、プログレス・バーやそういったものを作れるような、各行を読込んだ後に呼ばれるコールバック関数をセットアップすることができます。 pngtest.c に実例もあるのでをそちらもご覧下さい。関数は次のように指定します。

    void read_row_callback(png_ptr ptr, png_uint_32 row,
       int pass);
    {
      /* 自分のコードはここに書いてください。 */
    }

("read_row_callback"ではない、好きな自前の関数名も使えます)

次の関数を使用して、自前関数に関する情報を libpng に与えて下さい。

    png_set_read_status_fn(png_ptr, read_row_callback);

Setting up callback code

You can set up a callback function to handle any unknown chunks in the input stream. You must supply the function

    read_chunk_callback(png_ptr ptr,
         png_unknown_chunkp chunk);
    {
       /* The unknown chunk structure contains your
          chunk data: */
           png_byte name[5];
           png_byte *data;
           png_size_t size;
       /* Note that libpng has already taken care of
          the CRC handling */

       /* put your code here.  Return one of the
          following: */

       return (-n); /* chunk had an error */
       return (0); /* did not recognize */
       return (n); /* success */
    }

(You can give your function another name that you like instead of "read_chunk_callback")

To inform libpng about your function, use

    png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr,
        read_chunk_callback);

This names not only the callback function, but also a user pointer that you can retrieve with

    png_get_user_chunk_ptr(png_ptr);

At this point, you can set up a callback function that will be called after each row has been read, which you can use to control a progress meter or the like.  It's demonstrated in pngtest.c.
You must supply a function

    void read_row_callback(png_ptr ptr, png_uint_32 row,
       int pass);
    {
      /* put your code here */
    }

(You can give it another name that you like instead of "read_row_callback")

To inform libpng about your function, use

    png_set_read_status_fn(png_ptr, read_row_callback);


横幅と高さの限界

PNG 仕様書には 2^31-1 (0x7fffffff) と同じだけの大きさの横幅と高さ、又は21.47億の行と列まで大丈夫と書いてあります。一部のとてもわずかなアプ リケーションが本当にこういった大きい画像処理を必要としていたので、私たちは大体100万くらいの行と列でテストしました。大きすぎる画像はすぐに、 png_error() が呼ばれ、拒絶されます。この制限を解除して使いたいのなら、次のように、

   png_set_user_limits(png_ptr, width_max, height_max);

と、自前の制限値をセットするか、width_max = height_max = 0x7fffffffL とまるごと有効範囲を指定することもできます。(それでもどうやっても、バッファ・オーバーフローという状況を潜在的に秘めているため、とても大きな画像 は libpng に拒否されるかもしれません)。

PNG 構造体の生成後、且つ png_read_info()、png_read_png()、 png_process_data() を呼ぶ前にこの状態にして下さい。もし適用中の制限を再びもとに戻したいなら次のようにして下さい。

   width_max = png_get_user_width_max(png_ptr);
   height_max = png_get_user_height_max(png_ptr);


Width and height limits

The PNG specification allows the width and height of an image to be as large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns. Since very few applications really need to process such large images, we have imposed an arbitrary 1-million limit on rows and columns. Larger images will be rejected immediately with a png_error() call. If you wish to override this limit, you can use

   png_set_user_limits(png_ptr, width_max, height_max);

to set your own limits, or use width_max = height_max = 0x7fffffffL to allow all valid dimensions (libpng may reject some very large images anyway because of potential buffer overflow conditions).

You should put this statement after you create the PNG structure and before calling png_read_info(), png_read_png(), or png_process_data(). If you need to retrieve the limits that are being applied, use

   width_max = png_get_user_width_max(png_ptr);
   height_max = png_get_user_height_max(png_ptr);


不定チャンク処理

今度は入力 PNG ストリーム中の不定チャンクのライブラリ処理方法をセットします。 既定のチャンクも不定のチャンクも両方読み込みます。通常の動作では既定チャンクは各種 info_ptr メンバにある情報に解析して入れ、不定チャンクは破棄します。これを変更するため、次の関数を呼びます:

    png_set_keep_unknown_chunks(png_ptr, keep,
        chunk_list, num_chunks);
    keep       - 0: 不定用のハンドルを扱いません
                 1: 保持しません
                 2: 安全な引数のみ保持
                 3: 安全でない引数でも保持
               こちらの定義を使ってください
                 PNG_HANDLE_CHUNK_AS_DEFAULT   0
                 PNG_HANDLE_CHUNK_NEVER        1
                 PNG_HANDLE_CHUNK_IF_SAFE      2
                 PNG_HANDLE_CHUNK_ALWAYS       3
    chunk_list - 影響するチャンクのリスト (1バイト文字列、
                 5バイト/チャンク、num_chunks が 0 なら
                 NULL か '\0')
    num_chunks - 影響するチャンク数、0 なら、影響する
                 チャンク全部不定チャンクです。非ゼロなら、
                 そのリスト中のチャンクにだけ影響があります。

この方法で宣言される不定のチャンクは png_unknown_chunk 構造体のリスト上に、生データのように記録されます。libpng にある通常の既定のチャンクはリストに名前が書かれますが、あとは不定チャンクとして"keep"の指示により操作されます。 png_set_keep_unknown_chunks() の連続するインスタンスにあるチャンクに名前が付けられるとき、最後のチャンクが優先されます。IHDR と IENDチャンクは chunk_list中では名付けられません; たとえそれらがあっても、libpng は通常そのまま進行します。


Unknown-chunk handling

Now you get to set the way the library processes unknown chunks in the input PNG stream. Both known and unknown chunks will be read.  Normal behavior is that known chunks will be parsed into information in various info_ptr members; unknown chunks will be discarded. To change this, you can call:

    png_set_keep_unknown_chunks(png_ptr, keep,
        chunk_list, num_chunks);
    keep       - 0: do not handle as unknown
                 1: do not keep
                 2: keep only if safe-to-copy
                 3: keep even if unsafe-to-copy
               You can use these definitions:
                 PNG_HANDLE_CHUNK_AS_DEFAULT   0
                 PNG_HANDLE_CHUNK_NEVER        1
                 PNG_HANDLE_CHUNK_IF_SAFE      2
                 PNG_HANDLE_CHUNK_ALWAYS       3
    chunk_list - list of chunks affected (a byte string,
                 five bytes per chunk, NULL or '\0' if
                 num_chunks is 0)
    num_chunks - number of chunks affected; if 0, all
                 unknown chunks are affected.  If nonzero,
                 only the chunks in the list are affected

Unknown chunks declared in this way will be saved as raw data onto a list of png_unknown_chunk structures.  If a chunk that is normally known to libpng is named in the list, it will be handled as unknown, according to the "keep" directive.  If a chunk is named in successive instances of png_set_keep_unknown_chunks(), the final instance will take precedence.  The IHDR and IEND chunks should not be named in chunk_list; if they are, libpng will process them normally anyway.


高水準読込インタフェース

現時点では、2つの進行方法があります; 高水準読込インタフェースを使う方法と、低水準読込命令を連続して使う方法です。
高水準読込インタフェースが使えるのは、(a) メモリに画像を一括して読込むときや、(b) 行いたい入力変換を下記フラグで制限するときです:

  PNG_TRANSFORM_IDENTITY   無変換
PNG_TRANSFORM_STRIP_16 16ビット・サンプル を 8ビットに減らす
PNG_TRANSFORM_STRIP_ALPHA アルファ・チャンネル破棄
PNG_TRANSFORM_PACKING 1, 2, 4 ビットサンプルをバイト単位に拡張
PNG_TRANSFORM_PACKSWAP パックト・ピクセルの順序を LSB 先頭に変更
PNG_TRANSFORM_EXPAND set_expand() 実行
PNG_TRANSFORM_INVERT_MONO モノクロ画像を反転
PNG_TRANSFORM_SHIFT sBIT深度へピクセルを正常化
PNG_TRANSFORM_BGR RGB → BGR、RGBA → BGRA の反転
PNG_TRANSFORM_SWAP_ALPHA RGBA → ARGB 又は GA → AG の反転
PNG_TRANSFORM_INVERT_ALPHA 不透過 → 透過へアルファ変更
PNG_TRANSFORM_SWAP_ENDIAN 16ビットサンプルのバイト・スワップ

(これは背景色の設定、ガンマ変換、ディザ処理、フィラーの設定を除きます)  各場合の処理を、簡単にココに示します:

    png_read_png(png_ptr, info_ptr, png_transforms, NULL)

png_transforms 引数は変換フラグ数値を論理OR演算で組み合わせた値です。この呼び出しは png_read_info() とそれに続く変換マスクをセットしたpng_read_image()、そして最後の png_read_end() までの関数呼び出しと同じです。

(この呼び出しの最後のパラメータはまだ使われません。いつか将来の入力変換で要求される変換パラメータへのポインタになります)。

png_read_png() を使うなら png_transforms を使い、png_set_transform()は呼び出してはいけません。

png_read_png() の呼出し後、画像データを取得するには

   row_pointers = png_get_rows(png_ptr, info_ptr);

のようにして、各行のピクセル・データのポインタ配列であるrow_pointersは:

   png_bytep row_pointers[height];

前もって画像サイズ及びピクセルサイズがわかるなら、次のようにpng_read_png() を呼び出す前にrow_pointersにメモリ確保できます。

   if (height > PNG_UINT_32_MAX/png_sizeof(png_byte))
      png_error (png_ptr,
         "Image is too tall to process in memory");
   if (width > PNG_UINT_32_MAX/pixel_size)
      png_error (png_ptr,
         "Image is too wide to process in memory");
   row_pointers = png_malloc(png_ptr,
      height*png_sizeof(png_bytep));
   for (int i=0; i<height, i++)
      row_pointers[i]=png_malloc(png_ptr,
         width*pixel_size);
   png_set_rows(png_ptr, info_ptr, &row_pointers);

もうひとつの方法として、自前の大きな画像ブロック・メモリを用意して、そのブロック中の適当な位置へのポインタに row_pointers[i] を定義することもできます。

もし png_set_rows() を使うのであれば、アプリケーションはrow_pointers メモリを解放する義務があります(または row_pointers[i] が分割メモリであった場合)。

またもし前もって row_pointers メモリを確保してなければ、png_read_png() が確保してくれますし、解放も png_destroy_*() を呼んだ時やってくれます。


The high-level read interface

At this point there are two ways to proceed; through the high-level read interface, or through a sequence of low-level read operations.
You can use the high-level interface if (a) you are willing to read the entire image into memory, and (b) the input transformations you want to do are limited to the following set:

  PNG_TRANSFORM_IDENTITY   No transformation
PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to 8 bits
PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel
PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit samples to bytes
PNG_TRANSFORM_PACKSWAP Change order of packed pixels to LSB first
PNG_TRANSFORM_EXPAND Perform set_expand()
PNG_TRANSFORM_INVERT_MONO Invert monochrome images
PNG_TRANSFORM_SHIFT Normalize pixels to the sBIT depth
PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA to BGRA
PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA to AG
PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity to transparency
PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples

(This excludes setting a background color, doing gamma transformation, dithering, and setting filler.)  If this is the case, simply do this:

    png_read_png(png_ptr, info_ptr, png_transforms, NULL)

where png_transforms is an integer containing the logical OR of some set of transformation flags.  This call is equivalent to png_read_info(), followed the set of transformations indicated by the transform mask, then png_read_image(), and finally png_read_end().

(The final parameter of this call is not yet used.  Someday it might point to transformation parameters required by some future input transform.)

You must use png_transforms and not call any png_set_transform() functions when you use png_read_png().

After you have called png_read_png(), you can retrieve the image data with

   row_pointers = png_get_rows(png_ptr, info_ptr);

where row_pointers is an array of pointers to the pixel data for each row:

   png_bytep row_pointers[height];

If you know your image size and pixel size ahead of time, you can allocate row_pointers prior to calling png_read_png() with

   if (height > PNG_UINT_32_MAX/png_sizeof(png_byte))
      png_error (png_ptr,
         "Image is too tall to process in memory");
   if (width > PNG_UINT_32_MAX/pixel_size)
      png_error (png_ptr,
         "Image is too wide to process in memory");
   row_pointers = png_malloc(png_ptr,
      height*png_sizeof(png_bytep));
   for (int i=0; i<height, i++)
      row_pointers[i]=png_malloc(png_ptr,
         width*pixel_size);
   png_set_rows(png_ptr, info_ptr, &row_pointers);

Alternatively you could allocate your image in one big block and define row_pointers[i] to point into the proper places in your block.

If you use png_set_rows(), the application is responsible for freeing row_pointers (and row_pointers[i], if they were separately allocated).

If you don't allocate row_pointers ahead of time, png_read_png() will do it, and it'll be free'ed when you call png_destroy_*().


低水準読込インタフェース

低水準ルートで行くのなら、実際の画像データに対応した全ファイル情報を読込む準備を行います。png_read_info() 呼び出してコレを処理します。

    png_read_info(png_ptr, info_ptr);

これは全てのチャンクを処理しようというものですが、画像データは含みません。

情報構造体クエリ

一度読込んだ info_ptr から情報を取得する関数です。画像に付いてるチャンクデータが読み込み終わる png_read_end() まで、これらの値全部は入ってないかもしれないので注意して下さい。

png_get_IHDR(png_ptr, info_ptr, &width, &height,
       &bit_depth, &color_type, &interlace_type,
       &compression_type, &filter_method);
width - 画像ピクセル横幅が入ります (2^31 まで)。
height - 画像ピクセル高さが入ります (2^31 まで)。
bit_depth - 画像のチャンネルひとつのビット深度が入ります。 (有効値は 1, 2, 4, 8, 16 及び color_type による。下記の有意ビット(sBIT) も見て下さい)。
color_type - 有効な カラー/アルファ チャンネル の表現。
PNG_COLOR_TYPE_GRAY
(ビット深度 1, 2, 4, 8, 16)
PNG_COLOR_TYPE_GRAY_ALPHA
(ビット深度 8, 16)
PNG_COLOR_TYPE_PALETTE
(ビット深度 1, 2, 4, 8)
PNG_COLOR_TYPE_RGB
(ビット深度 8, 16)
PNG_COLOR_TYPE_RGB_ALPHA
(ビット深度 8, 16)

PNG_COLOR_MASK_PALETTE
PNG_COLOR_MASK_COLOR
PNG_COLOR_MASK_ALPHA
filter_method - (PNG 1.0 で PNG_FILTER_TYPE_BASE でなければならず、MNG-1.0 データストリームに埋め込む PNG データストリームなら PNG_INTRAPIXEL_DIFFERENCING にもなり得ます。
compression_type - (PNG 1.0 で PNG_COMPRESSION_TYPE_BASE でなければなりません)
interlace_type - (PNG_INTERLACE_NONE または PNG_INTERLACE_ADAM7)
interlace_typeのいくつかないしまたは全部、それらの値に興味がないなら、 compression_type、filter_methodのそれは NULL で構いません。
channels = png_get_channels(png_ptr, info_ptr);
channels - カラータイプ情報のチャンネル値 (有効値は、1 (GRAY, PALETTE), 2 (GRAY_ALPHA), 3 (RGB), 4 (RGB_ALPHA または RGB + フィルタタイプ))
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
rowbytes - 行を保持するのに必要なバイト数。
signature = png_get_signature(png_ptr, info_ptr);
signature - ファイル(か何か)から読込んだシグネチャを保持。データはシグネチャを読込んだそのまま同じオフセットを保持します (つまりアプリケーションが libpng を開始させる前にシグネチャを4バイト読込んであれば、残った4バイトは signature[4] 〜 signature[7] に入ります(png_set_sig_bytes()を見て下さい))。
  

width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
color_type = png_get_filter_type(png_ptr, info_ptr);
filter_method = png_get_filter_type(png_ptr, info_ptr);
compression_type = png_get_compression_type(png_ptr, info_ptr);
interlace_type = png_get_interlace_type(png_ptr, info_ptr);


The low-level read interface

If you are going the low-level route, you are now ready to read all the file information up to the actual image data.  You do this with a call to png_read_info().

    png_read_info(png_ptr, info_ptr);

This will process all chunks up to but not including the image data.

Querying the info structure

Functions are used to get the information from the info_ptr once it has been read.  Note that these fields may not be completely filled in until png_read_end() has read the chunk data following the image.
png_get_IHDR(png_ptr, info_ptr, &width, &height,
       &bit_depth, &color_type, &interlace_type,
       &compression_type, &filter_method);
width - holds the width of the image in pixels (up to 2^31).
height - holds the height of the image in pixels (up to 2^31).
bit_depth - holds the bit depth of one of the image channels. (valid values are 1, 2, 4, 8, 16 and depend also on the color_type. See also significant bits (sBIT) below).
color_type - describes which color/alpha channels are present.
PNG_COLOR_TYPE_GRAY
(bit depths 1, 2, 4, 8, 16)
PNG_COLOR_TYPE_GRAY_ALPHA
(bit depths 8, 16)
PNG_COLOR_TYPE_PALETTE
(bit depths 1, 2, 4, 8)
PNG_COLOR_TYPE_RGB
(bit_depths 8, 16)
PNG_COLOR_TYPE_RGB_ALPHA
(bit_depths 8, 16)

PNG_COLOR_MASK_PALETTE
PNG_COLOR_MASK_COLOR
PNG_COLOR_MASK_ALPHA
filter_method - (must be PNG_FILTER_TYPE_BASE for PNG 1.0, and can also be PNG_INTRAPIXEL_DIFFERENCING if the PNG datastream is embedded in a MNG-1.0 datastream)
compression_type - (must be PNG_COMPRESSION_TYPE_BASE for PNG 1.0)
interlace_type - (PNG_INTERLACE_NONE or PNG_INTERLACE_ADAM7)
Any or all of interlace_type, compression_type, of filter_method can be NULL if you are not interested in their values.
channels = png_get_channels(png_ptr, info_ptr);
channels - number of channels of info for the color type (valid values are 1 (GRAY, PALETTE), 2 (GRAY_ALPHA), 3 (RGB), 4 (RGB_ALPHA or RGB + filler byte))
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
rowbytes - number of bytes needed to hold a row
signature = png_get_signature(png_ptr, info_ptr);
signature - holds the signature read from the file (if any). The data is kept in the same offset it would be if the whole signature were read (i.e. if an application had already read in 4 bytes of signature before starting libpng, the remaining 4 bytes would be in signature[4] through signature[7] (see png_set_sig_bytes())).
 

width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
color_type = png_get_filter_type(png_ptr, info_ptr);
filter_method = png_get_filter_type(png_ptr, info_ptr);
compression_type = png_get_compression_type(png_ptr, info_ptr);
interlace_type = png_get_interlace_type(png_ptr, info_ptr);


こちらもまた重要なのですが、その有効性はチャンクが読込まれているかどうかに、かかっています。png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) と png_get_<chunk>(png_ptr, info_ptr, ...) 関数は、データが読込んであれば非ゼロを返し、そうでなければゼロを返します。png_get_<chunk>へ渡す引数は、シンプルなデー タ型なら直接セットできますし、そうでない複雑な型ならば info_ptr ポインタが返されます。

png_get_PLTE(png_ptr, info_ptr, &palette,
          &num_palette);
palette - ファイル用パレット (png_color 配列)
num_palette - パレットのエントリ数
 
png_get_gAMA(png_ptr, info_ptr, &gamma);
gamma - (PNG_INFO_gAMA) に書かれたファイルのガンマ
 
png_get_sRGB(png_ptr, info_ptr, &srgb_intent);
srgb_intent - 表現意図 (PNG_INFO_sRGB)
sRGB チャンクの存在はピクセルデータがsRGB カラー空間にあることを示します。このチャンクもまた gAMA と cHRM の固有値を示唆します。
 
png_get_iCCP(png_ptr, info_ptr, &name,
     &compression_type, &profile, &proflen);
name - プロフィール名
compression - 圧縮タイプ; 常にPNG 1.0用 PNG_COMPRESSION_TYPE_BASE。
この引数が NULL なら無視。
profile - International Color Consortium (国際色協会 ICC)カラー・プロフィールデータ。 NULs (10進値0のオクテット) を含むかも。
proflen - プロフィール・データのバイト長。

png_get_sBIT(png_ptr, info_ptr, &sig_bit);
sig_bit - 与えられたカラータイプ(png_color_16)に適した、グレー、赤、緑、青のそれぞれのチャンネルの有効ビット 数(PNG_INFO_sBIT)

png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
          &trans_values);
trans - 透過パレット・エントリの配列 (PNG_INFO_tRNS)
trans_values - 非パレット画像用の単一透過色のカラーサンプル値かグレーレベル (PNG_INFO_tRNS)
num_trans - 透過エントリの数 (PNG_INFO_tRNS)

png_get_hIST(png_ptr, info_ptr, &hist);

(PNG_INFO_hIST)
hist - パレットのヒストグラム (png_uint_16の配列)

png_get_tIME(png_ptr, info_ptr, &mod_time);
mod_time - 画像の最終更新時間
(PNG_VALID_tIME)

png_get_bKGD(png_ptr, info_ptr, &background);
background - color_type に関係なく、有効な 16ビット 赤、緑、青の値の背景色 (PNG_VALID_bKGD)

num_comments = png_get_text(png_ptr, info_ptr,
               &text_ptr, &num_text);
num_comments - コメント数
text_ptr - 画像コメントを保持している png_text の配列
text_ptr[i].compression - "text" で使う圧縮タイプ


PNG_TEXT_COMPRESSION_NONE
PNG_TEXT_COMPRESSION_zTXt
PNG_ITXT_COMPRESSION_NONE
PNG_ITXT_COMPRESSION_zTXt
text_ptr[i].key - コメント用キーワード。必ず1〜79 文字。
text_ptr[i].text - カレント・キーワード用テキストコメント。空でもOK。
text_ptr[i].text_length - 展開後のテキスト文字列長
0 は iTXt 用
text_ptr[i].itxt_length - 展開後のitxt文字列長
0 は tEXt/zTXt用
text_ptr[i].lang - コメントの言語 (空文字列なら不定)。
text_ptr[i].lang_key - UTF-8 でのキーワード(空文字列なら不定)。
num_text - コメント数 (num_comments と同じ; ここが NULL なら重複回避になります)。
テキスト、言語、変換キーワードはNULL も含め、png_get_textが返した構造体は、png_set_text() に渡されるとき常にふつうのゼロ終端のC文字列になります。みな空文字列になることもありますが、決してNULLポインタにはなりません。


These are also important, but their validity depends on whether the chunk has been read.  The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the data has been read, or zero if it is missing.  The parameters to the png_get_<chunk> are set directly if they are simple data types, or a pointer into the info_ptr is returned for any complex types.

png_get_PLTE(png_ptr, info_ptr, &palette,
          &num_palette);
palette - the palette for the file (array of png_color)
num_palette - number of entries in the palette
 
png_get_gAMA(png_ptr, info_ptr, &gamma);
gamma -
the gamma the file is written at (PNG_INFO_gAMA)

png_get_sRGB(png_ptr, info_ptr, &srgb_intent);
srgb_intent -
the rendering intent (PNG_INFO_sRGB)
The presence of the sRGB chunk means that the pixel data is in the sRGB color space. This chunk also implies specific values of gAMA and cHRM.
 
png_get_iCCP(png_ptr, info_ptr, &name,
     &compression_type, &profile, &proflen);
name - The profile name.
compression -
The compression type; always PNG_COMPRESSION_TYPE_BASE for PNG 1.0. You may give NULL to this argument to ignore it.
profile -
International Color Consortium color profile data. May contain NULs.
proflen -
length of profile data in bytes.

png_get_sBIT(png_ptr, info_ptr, &sig_bit);
sig_bit -
the number of significant bits for (PNG_INFO_sBIT) each of the gray, red, green, and blue channels, whichever are appropriate for the given color type (png_color_16)

png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
          &trans_values);
trans -
array of transparent entries for palette (PNG_INFO_tRNS)
trans_values -
graylevel or color sample values of the single transparent color for non-paletted images (PNG_INFO_tRNS)
num_trans -
number of transparent entries (PNG_INFO_tRNS)

png_get_hIST(png_ptr, info_ptr, &hist);

(PNG_INFO_hIST)
hist - histogram of palette (array of png_uint_16)

png_get_tIME(png_ptr, info_ptr, &mod_time);
mod_time -
time image was last modified
(PNG_VALID_tIME)

png_get_bKGD(png_ptr, info_ptr, &background);
background -
background color (PNG_VALID_bKGD)
valid 16-bit red, green and blue values, regardless of color_type

num_comments = png_get_text(png_ptr, info_ptr,
               &text_ptr, &num_text);
num_comments - number of comments
text_ptr -
array of png_text holding image
comments
text_ptr[i].compression - type of compression used on "text"

-
PNG_TEXT_COMPRESSION_NONE
PNG_TEXT_COMPRESSION_zTXt
PNG_ITXT_COMPRESSION_NONE
PNG_ITXT_COMPRESSION_zTXt
text_ptr[i].key -
keyword for comment. Must contain
1-79 characters.
text_ptr[i].text -
text comments for current keyword. Can be empty.
text_ptr[i].text_length -
length of text string, after decompression, 0 for iTXt
text_ptr[i].itxt_length -
length of itxt string, after decompression, 0 for tEXt/zTXt
text_ptr[i].lang -
language of comment (empty string for unknown).
text_ptr[i].lang_key -
keyword in UTF-8 (empty string for unknown).
num_text -
number of comments (same as num_comments; you can put NULL here to avoid the duplication)
Note while png_set_text() will accept text, language, and translated keywords that can be NULL pointers, the structure returned by png_get_text will always contain regular zero-terminated C strings. They might be empty strings but they will never be NULL pointers.

num_spalettes = png_get_sPLT(png_ptr, info_ptr, &palette_ptr);
palette_ptr - 1つ以上のsPLTチャンクの内容を持つパレット構造体の配列を読込みます。
num_spalettes - 読込んだsPLT チャンク数。
 
png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y,
                  &unit_type);
offset_x - スクリーン左端から正値オフセット
offset_y - スクリーン上端から正値オフセット
unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
 
png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type);
res_x - ピクセル/単位 物理解像度
x 方向
res_y - ピクセル/単位 物理解像度
y 方向
unit_type - PNG_RESOLUTION_UNKNOWN,
PNG_RESOLUTION_METER

png_get_sCAL(png_ptr, info_ptr, &unit, &width, &height)
unit - 物理スケール単位 (整数)
width - 物理スケール単位でのピクセル横幅
height - 物理スケール単位でのピクセル高さ


(width は height は double型)

png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, &height)
unit - 物理スケール単位 (整数)
width - 物理スケール単位でのピクセル横幅
height - 物理スケール単位でのピクセル高さ

(width と height は"2.54"のような文字列)

num_unknown_chunks = png_get_unknown_chunks(png_ptr,
                info_ptr, &unknowns)
unknowns - 不定チャンクが入る png_unknown_chunk 構造体の配列
unknowns[i].name - 不定チャンク名
unknowns[i].data - 不定チャンクデータ
unknowns[i].size - 不定チャンクデータサイズ
unknowns[i].location - ファイル中のチャンク位置

"i"という値はPNGファイルから読み込んだりpng_set_unknown_chunks() で挿入したチャンクの順番に相当します。

pHYs チャンクのデータはいくつか簡便なな形式でも取得可能できます:

res_x = png_get_x_pixels_per_meter(png_ptr, info_ptr)
res_y = png_get_y_pixels_per_meter(png_ptr, info_ptr)
res_x_and_y = png_get_pixels_per_meter(png_ptr, info_ptr)
res_x = png_get_x_pixels_per_inch(png_ptr, info_ptr)
res_y = png_get_y_pixels_per_inch(png_ptr, info_ptr)
res_x_and_y = png_get_pixels_per_inch(png_ptr, info_ptr)
aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, info_ptr)

(データが存在しなかったり、res_x == 0; だったり、res_x_and_y == 0 で res_x != res_y だったりすると、それぞれ["不明"を示す] 0 を返します)

チャンクのデータはいくつか便利な形式で取得可能です:

x_offset = png_get_x_offset_microns(png_ptr, info_ptr);
y_offset = png_get_y_offset_microns(png_ptr, info_ptr);
x_offset = png_get_x_offset_inches(png_ptr, info_ptr);
y_offset = png_get_y_offset_inches(png_ptr, info_ptr);

(データが存在しなかったり、チャンクが存在するのに単位がピクセルだったりすると、[x も y も 0 のときの "不明"を示す] 0 をそれぞれ返します)

num_spalettes = png_get_sPLT(png_ptr, info_ptr, &palette_ptr);
palette_ptr - array of palette structures holding contents of one or more sPLT chunks read.
num_spalettes - number of sPLT chunks read.
 
png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y,
                  &unit_type);
offset_x - positive offset from the left edge of the screen
offset_y - positive offset from the top edge of the screen
unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER

png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type);
res_x - pixels/unit physical resolution in x direction
res_y - pixels/unit physical resolution in y direction
unit_type - PNG_RESOLUTION_UNKNOWN, PNG_RESOLUTION_METER

png_get_sCAL(png_ptr, info_ptr, &unit, &width, &height)
unit - physical scale units (an integer)
width - width of a pixel in physical scale units
height - height of a pixel in physical scale units


(width and height are doubles)

png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, &height)
unit - physical scale units (an integer)
width - width of a pixel in physical scale units
height - height of a pixel in physical scale units


(width and height are strings like "2.54")

num_unknown_chunks = png_get_unknown_chunks(png_ptr,
                info_ptr, &unknowns)
unknowns - array of png_unknown_chunk structures holding unknown chunks
unknowns[i].name - name of unknown chunk
unknowns[i].data - data of unknown chunk
unknowns[i].size - size of unknown chunk's data
unknowns[i].location - position of chunk in file

The value of "i" corresponds to the order in which the chunks were read from the PNG file or inserted with the png_set_unknown_chunks() function.

The data from the pHYs chunk can be retrieved in several convenient forms:

res_x = png_get_x_pixels_per_meter(png_ptr, info_ptr)
res_y = png_get_y_pixels_per_meter(png_ptr, info_ptr)
res_x_and_y = png_get_pixels_per_meter(png_ptr, info_ptr)
res_x = png_get_x_pixels_per_inch(png_ptr, info_ptr)
res_y = png_get_y_pixels_per_inch(png_ptr, info_ptr)
res_x_and_y = png_get_pixels_per_inch(png_ptr, info_ptr)
aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, info_ptr)

(Each of these returns 0 [signifying "unknown"] if the data is not present or if res_x is 0; res_x_and_y is 0 if res_x != res_y)

The data from the oFFs chunk can be retrieved in several convenient forms:

x_offset = png_get_x_offset_microns(png_ptr, info_ptr);
y_offset = png_get_y_offset_microns(png_ptr, info_ptr);
x_offset = png_get_x_offset_inches(png_ptr, info_ptr);
y_offset = png_get_y_offset_inches(png_ptr, info_ptr);

(Each of these returns 0 [signifying "unknown" if both x and y are 0] if the data is not present or if the chunk is present but the unit is the pixel)


詳細情報は、png.h にある png_info定義及びPNG仕様書のチャンク・コンテンツを見て下さい。変換のいくつか (expand, filler, gray_to_rgb, など.)のように、1行増える度その分空きメモリが必要になるものもあるのでrowbytes に気をつけてください。
下記、png_read_update_info() も見て下さい。

text_ptr と num_text に関する話。PNG はキーワード/テキストのペアの中にコメントを記憶しており、1チャンクにつき1ペアで、テキスト・チャンク数は無制限ですが、サイズは2^31バイトが 限界です。キーワードを入力している間、それらの文字使用にかかる制限要求はありません。キーワードとテキストは人間に読める(ココ重要)ようになるべく 省略をしないで書いてください。表示できない文字は使わないで下さい。詳細はPNG仕様書を見て下さい。また、キーワード取得後はテキストは必要ありませ ん。

キーワードは前後に空きがない状態で、Latin-1コードで79文字が限界ですが、キーワードは非連続的なメモリ・スペースでも可能です。またいくつ同 じキーワードがあっても構いません。text_ptr は png_text 構造体の配列で、それぞれ言語文字列へのポインタ、キーワード・ポインタ、テキスト文字列へのポインタを保持しています。テキスト文字列、言語コード、変 換キーワードは空かNULLポインタであっても構いません。キーワード/テキストのペアはもとの来た順番で配列に格納されます。しかし、テキストチャンク の一部または全部が画像データの後にあったりするので、テキストチャンクを全部読み込み、画像データの後にあるそのほかのデータまでごちゃごちゃにならな いよ うにして下さい。これについてはまた下記 png_read_end() に伴う処理の論考で再び言及します。


For more information, see the png_info definition in png.h and the PNG specification for chunk contents. Be careful with trusting rowbytes, as some of the transformations could increase the space needed to hold a row (expand, filler, gray_to_rgb, etc.).
See png_read_update_info(), below.

A quick word about text_ptr and num_text. PNG stores comments in keyword/text pairs, one pair per chunk, with no limit on the number of text chunks, and a 2^31 byte limit on their size. While there are suggested keywords, there is no requirement to restrict the use to these strings. It is strongly suggested that keywords and text be sensible to humans (that's the point), so don't use abbreviations. Non-printing symbols are not allowed. See the PNG specification for more details. There is also no requirement to have text after the keyword.

Keywords should be limited to 79 Latin-1 characters without leading or trailing spaces, but non-consecutive spaces are allowed within the keyword. It is possible to have the same keyword any number of times. The text_ptr is an array of png_text structures, each holding a pointer to a language string, a pointer to a keyword and a pointer to a text string. The text string, language code, and translated keyword may be empty or NULL pointers. The keyword/text pairs are put into the array in the order that they are received. However, some or all of the text chunks may be after the image, so, to make sure you have read all the text chunks, don't mess with these until after you read the stuff after the image. This will be mentioned again below in the discussion that goes with png_read_end().


入力変換

ヘッダ情報を読み込んだあと、ライブラリに画像の特殊変換の処理に関するセットアップを行います。各種データ変換方法はそれらが動作する順番で反映されて いきます。ここで重要なんですが、データのカラータイプやビット深度のどちらか一方または両方を変更してしまうようなものと、その他いくつかは相応のカ ラータイプやビット深度でしか動作しません。たとえそれぞれの変換から何か得られるものがあったとしても、データに有効な変換を行えるのか確かめるべきで す。例えば、グレースケール・データに赤青のスワップしても無駄になります。

背景と透過値に使う色は、画像データと同じフォーマット/ビット深度にして下さい。その色は bKGD や tRNS チャンク中の画像データと同じフォーマット/ビット深度に記憶されており、libpng が当てにしているデータです。アプリケーションが png_read_update_info() ルーチン(下記参照)を呼ん だとき、その色は画像データと同期的に維持するために変換されます。


Input transformations

After you've read the header information, you can set up the library to handle any special transformations of the image data.  The various ways to transform the data will be described in the order that they should occur.  This is important, as some of these change the color type and/or bit depth of the data, and some others only work on certain color types and bit depths.  Even though each transformation checks to see if it has data that it can do something with, you should make sure to only enable a transformation if it will be valid for the data.  For example, don't swap red and blue on grayscale data.

The colors used for the background and transparency values should be supplied in the same format/depth as the current image data.  They are stored in the same format/depth as the image data in a bKGD or tRNS chunk, so this is what libpng expects for this data.  The colors are transformed to keep in sync with the image data when an application calls the png_read_update_info() routine (see below).


ライブラリに違うフォーマットに変換するとでも伝えない限り、データは所定の行バッファにデコードされ格納されます。例えば、4ビット/ピクセル・パレッ トやグレースケール・データは、png_set_packing() が呼ばれない限りは、バイトの上位ビットの一番左の 2ピクセル/バイトを返します。
8ビットRGB データは、各RGBトリプレットの前か後かに補充バイトを挿入する png_set_filler() や png_set_add_alpha() が呼ばれない限り、RGB RGB RGB 形式で記憶されます。
16ビットRGBデータは、普通のRGB RGB トリプレットに変換を行う png_set_strip_16() や、各RRGGBBトリプレットの前か後かに補充バイトを挿入するpng_set_filler() かpng_set_add alpha() が呼ばれない限り、先頭のカラー値の最上位バイトのRRGGBB RRGGBBを返します。
同様に、8ビットまたは16ビット グレースケール・データも png_set_filler() や、 png_set_add_alpha()、や png_set_strip_16() で変更できます。

下記コードは8ビットより少ないグレースケール画像から 8ビットへ、パレット画像からRGBへ、tRNSチャンクの透過情報があるときのフル・アルファ・チャンネルへの変換を行います。複数の画像を表示するア プリケーションが同一方式で全ての画像を扱おうとするとき、2、4などのビット深度のグレースケール画像でかなり便利です。

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);

    if (color_type == PNG_COLOR_TYPE_GRAY &&
        bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);

    if (png_get_valid(png_ptr, info_ptr,
        PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);

これら3つの関数はlibpng バージョン 1.0.4で加えられた png_set_expand() の実際のエイリアスで、関数名もわかりやすく修正されています。また将来のバージョンでは、異なる動作をするかもしれません。


Data will be decoded into the supplied row buffers packed into bytes unless the library has been told to transform it into another format.
For example, 4 bit/pixel paletted or grayscale data will be returned 2 pixels/byte with the leftmost pixel in the high-order bits of the byte, unless png_set_packing() is called.
8-bit RGB data will be stored in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() is called to insert filler bytes, either before or after each RGB triplet.
16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant byte of the color value first, unless png_set_strip_16() is called to transform it to regular RGB RGB triplets, or png_set_filler() or png_set_add alpha() is called to insert filler bytes, either before or after each RRGGBB triplet.
Similarly, 8-bit or 16-bit grayscale data can be modified with png_set_filler(), png_set_add_alpha(), or png_set_strip_16().

The following code transforms grayscale images of less than 8 to 8 bits, changes paletted images to RGB, and adds a full alpha channel if there is transparency information in a tRNS chunk.  This is most useful on grayscale images with bit depths of 2 or 4 or if there is a multiple-image viewing application that wishes to treat all images in the same way.

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);

    if (color_type == PNG_COLOR_TYPE_GRAY &&
        bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);

    if (png_get_valid(png_ptr, info_ptr,
        PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);

These three functions are actually aliases for png_set_expand(), added in libpng version 1.0.4, with the function names expanded to improve code readability.  In some future version they may actually do different things.

PNG は 16 ビット/チャンネルのファイルも可能です。8ビット/チャンネルしか扱わないのなら、ピクセルを減らして8ビットにします。

    if (bit_depth == 16)
        png_set_strip_16(png_ptr);

理由としては、画像にアルファチャンネルが必要ないからとか、背景とくっつけてしまうよりむしろ削除したい、などの場合があります (ただし、その背景と結合しようとしている画像の作者の了承を確実に得てください、まあ大抵は得ていると思いますが):

    if (color_type & PNG_COLOR_MASK_ALPHA)
        png_set_strip_alpha(png_ptr);

PNGファイルにおいて、画像アルファチャンネルは不透明度を表すものです。不透明度ではなく透明度を表すアルファチャンネルが欲しいなら、読込後にアル ファチャンネル(又は tRNSチャンクデータ)を変換することができます。そのとき 0 は完全不透明で 255(8ビットやパレット画像) や65535(16ビット画像)が完全透明となります。それには次のようにします。

    png_set_invert_alpha(png_ptr);

なるべくできるだけ小さいバイトに収められている1, 2, 4の深度のパック・ピクセルを持つPNGファイルについてですが、例としては、1ビット画像の8ピクセル/バイトですが、以下のコードではピクセルの値を 修正せずに 1ピクセル/バイトに拡張しています:

    if (bit_depth < 8)
        png_set_packing(png_ptr);

1, 2, 4, 8, 16のビット深度をもつPNGファイルを扱います。画像にある全ピクセルをもう一つ上のビット深度へ「拡張」や「シフト演算」します(例:[0,31] の範囲にある 5ビット/サンプルから、[0, 255] の範囲にある 8ビット/サンプルへ)。また一方、PNG ピクセルデータは各画像の元のビット深度へもまた変換して戻せます。以下の呼び出しでは元のビット深度へピクセルを減らして戻しています:

    png_color_8p sig_bit;

    if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
        png_set_shift(png_ptr, sig_bit);

赤、緑、青の順の3色ピクセルを持つPNGファイルです。以下のコードでは青、緑、赤の順に変更しています:

    if (color_type == PNG_COLOR_TYPE_RGB ||
        color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        png_set_bgr(png_ptr);

3 や 6バイトにパックされた RGB ピクセルを使うPNGファイルです。以下のコードは4 や 8バイトのウィンドウ・システム用にその形式に拡張しています:

    if (color_type == PNG_COLOR_TYPE_RGB)
        png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE);

8か16ビットの数字の"filler"を挿入する場所は、RGB の前に挿入するか後に挿入するかで、PNG_FILLER_BEFORE か PNG_FILLER_AFTER に決まります。この変換は既にフル・アルファ・チャンネルとなっている画像に影響しません。不透明アルファチャンネルを加えるなら、filler= 0xff や 0xffff として RGBA ピクセルを生成するPNG_FILLER_AFTERを指定してください。

PNG can have files with 16 bits per channel.  If you only can handle 8 bits per channel, this will strip the pixels down to 8 bit.

    if (bit_depth == 16)
        png_set_strip_16(png_ptr);

If, for some reason, you don't need the alpha channel on an image, and you want to remove it rather than combining it with the background (but the image author certainly had in mind that you *would* combine it with the background, so that's what you should probably do):

    if (color_type & PNG_COLOR_MASK_ALPHA)
        png_set_strip_alpha(png_ptr);

In PNG files, the alpha channel in an image is the level of opacity.  If you need the alpha channel in an image to be the level of transparency instead of opacity, you can invert the alpha channel (or the tRNS chunk data) after it's read, so that 0 is fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit images) is fully transparent, with

    png_set_invert_alpha(png_ptr);

PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as they can, resulting in, for example, 8 pixels per byte for 1 bit files.  This code expands to 1 pixel per byte without changing the values of the pixels:

    if (bit_depth < 8)
        png_set_packing(png_ptr);

PNG files have possible bit depths of 1, 2, 4, 8, and 16.  All pixels stored in a PNG image have been "scaled" or "shifted" up to the next higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to 8 bits/sample in the range [0, 255]).  However, it is also possible to convert the PNG pixel data back to the original bit depth of the image. This call reduces the pixels back down to the original bit depth:

    png_color_8p sig_bit;

    if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
        png_set_shift(png_ptr, sig_bit);

PNG files store 3-color pixels in red, green, blue order.  This code changes the storage of the pixels to blue, green, red:

    if (color_type == PNG_COLOR_TYPE_RGB ||
        color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        png_set_bgr(png_ptr);

PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them into 4 or 8 bytes for windowing systems that need them in this format:

    if (color_type == PNG_COLOR_TYPE_RGB)
        png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE);

where "filler" is the 8 or 16-bit number to fill with, and the location is either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether you want the filler before the RGB or after.  This transformation does not affect images that already have full alpha channels.  To add an opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which will generate RGBA pixels.


png_set_filler() はカラータイプを変更しませんので注意してください。そういうことをするのなら、本当のアルファチャンネルを加えるには次のようにして下さい。

    if (color_type == PNG_COLOR_TYPE_RGB ||
           color_type == PNG_COLOR_TYPE_GRAY)
    png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER);

"filler"の位置には各ピクセルに割り当てるアルファ値が含まれています。この関数はlibpng-1.2.7で追加されました。

通常のPNGフォーマットRGBAでなくて、ARGBの形式のアルファチャンネル付の画像を読み込むとき:

    if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        png_set_swap_alpha(png_ptr);

使用に際し、RGBになっているグレースケール画像を使うこともあると思います。以下のコードはその変換を実行します:

    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
          png_set_gray_to_rgb(png_ptr);

反対に、RGB や RGBA 画像もグレースケール及びアルファ付グレースケールに変換できます:

    if (color_type == PNG_COLOR_TYPE_RGB ||
        color_type == PNG_COLOR_TYPE_RGB_ALPHA)
          png_set_rgb_to_gray_fixed(png_ptr, error_action,
             int red_weight, int green_weight);

    error_action = 1 : 変換時、警告・エラーメッセージ無し
error_action = 2 : 元の画像に
red != green や red != blue
といったピクセルがあるとき、
警告メッセージを出します
error_action = 3 : 元の画像に
red != green や red != blue
といったピクセルがあるとき、
エラーメッセージを出して
変換を終了します
 
red_weight: 赤成分の重み付けの値の 100000 倍
green_weight: 緑成分の重み付けの値の 100000 倍

重み付け値がマイナス値かどうかで、
標準重み付け値 (21268, 71514) が
使われるかどうかが決まります。

error_action = 1 や 2とセットすれば、画像の行を処理するごとに  png_get_rgb_to_gray_status(png_ptr) 関数であとから画像が本当にグレーになってるかどうかチェックできます。
画像がグレーを示すゼロか非グレー・ピクセルを示す 1の値のpng_byte を返します。
bKGD と sBIT データはerror_actionの設定を無視して警告もエラーメッセージも無しで、緑チャンネル・データを使用して変換されます。

red_weight+green_weight<=100000 で
グレー値が計算されます:

    int rw = red_weight * 65536;
    int gw = green_weight * 65536;
    int bw = 65536 - (rw + gw);
    gray = (rw*red + gw*green + bw*blue)/65536;

デフォルト値は Charles Poynton's Color FAQ,
<http://www.inforamp.net/~poynton/> 著作 (c) 1998-01-04 Charles Poynton <poynton at inforamp.net> で推奨されている近似値です。

    Y = 0.212671 * R + 0.715160 * G + 0.072169 * B

libpng では次のように近似します。

    Y = 0.21268 * R    + 0.7151 * G    + 0.07217 * B

整数を使えば高速になります。

    Y = (6969 * R + 23434 * G + 2365 * B)/32768

画像ガンマがわかっていれば、計算は線形カラー空間で行われます。

Note that png_set_filler() does not change the color type.  If you want to do that, you can add a true alpha channel with

    if (color_type == PNG_COLOR_TYPE_RGB ||
           color_type == PNG_COLOR_TYPE_GRAY)
    png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER);

where "filler" contains the alpha value to assign to each pixel.
This function was added in libpng-1.2.7.

If you are reading an image with an alpha channel, and you need the data as ARGB instead of the normal PNG format RGBA:

    if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        png_set_swap_alpha(png_ptr);

For some uses, you may want a grayscale image to be represented as RGB.  This code will do that conversion:

    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
          png_set_gray_to_rgb(png_ptr);

Conversely, you can convert an RGB or RGBA image to grayscale or grayscale with alpha.

    if (color_type == PNG_COLOR_TYPE_RGB ||
        color_type == PNG_COLOR_TYPE_RGB_ALPHA)
          png_set_rgb_to_gray_fixed(png_ptr, error_action,
             int red_weight, int green_weight);

    error_action = 1 : silently do the conversion
error_action = 2 : issue a warning if the original
image has any pixel where
red != green or red != blue
error_action = 3 : issue an error and abort the
conversion if the original
image has any pixel where
red != green or red != blue
   
red_weight: weight of red component times 100000
green_weight: weight of green component times 100000

If either weight is negative, default
weights (21268, 71514) are used.

If you have set error_action = 1 or 2, you can later check whether the image really was gray, after processing the image rows, with the png_get_rgb_to_gray_status(png_ptr) function.
It will return a png_byte that is zero if the image was gray or 1 if there were any non-gray pixels.  bKGD and sBIT data will be silently converted to grayscale, using the green channel data, regardless of the error_action setting.

With red_weight+green_weight<=100000,
the normalized graylevel is computed:

    int rw = red_weight * 65536;
    int gw = green_weight * 65536;
    int bw = 65536 - (rw + gw);
    gray = (rw*red + gw*green + bw*blue)/65536;

The default values approximate those recommended in the Charles Poynton's Color FAQ, <http://www.inforamp.net/~poynton/> Copyright (c) 1998-01-04 Charles Poynton <poynton at inforamp.net>

    Y = 0.212671 * R + 0.715160 * G + 0.072169 * B

Libpng approximates this with

    Y = 0.21268 * R    + 0.7151 * G    + 0.07217 * B

which can be expressed with integers as

    Y = (6969 * R + 23434 * G + 2365 * B)/32768

The calculation is done in a linear colorspace, if the image gamma is known.
Charles Poynton's Color FAQ, <http://www.inforamp.net/~poynton/>
Copyright (c) 1998-01-04 Charles Poynton <poynton at inforamp.net>
↑リンク切れしてます。
現在正しいのはhttp://www.poynton.com/ のようです(2005.7)。

もしグレースケールがあって且つ png_set_expand_depth(), png_set_expand() や、 トゥルーカラーやより高いビット深度に変換するpng_set_gray_to_rgb を使うのなら、元のファイルのビット深度で背景色をグレー値などに設定するか(need_expand = 1)、さもなくばビット深度を拡張して完全なRGBトリプレットのような背景色にしてしまうか(need_expand = 0) しなければなりません。同様にパレット画像を読み込むとき、背景色をパレット・インデックスで設定するか(need_expand = 1)、パレット内にその値があるかないかはわかりませんがRGBトリプレット値を設定しなければなりません(need_expand = 0)。

    png_color_16 my_background;
    png_color_16p image_background;

    if (png_get_bKGD(png_ptr, info_ptr, &image_background))
        png_set_background(png_ptr, image_background,
          PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
    else
        png_set_background(png_ptr, &my_background,
          PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);

png_set_background() 関数は設定された背景色に対してアルファや単純透過が画像に合成されたことを libpng に伝えます。PNGファイルが bKGD チャンクを含んでいる(PNG_INFO_bKGD が有効) なら、その色もしくはそのときの表示画面により適した色を使っても構いません (例: ウェブページ上の背景色など)。
次のガンマ空間にその色があるかないかをlibpng に伝える必要があります。ディスプレー(任意の色を使えるPNG_BACKGROUND_GAMMA_SCREEN)、ファイル(bKGDチャンクの色を 用いたPNG_BACKGROUND_GAMMA_FILE)、またそれらのガンマがあるところの値を使わない (PNG_BACKGROUND_GAMMA_UNIQUE … 一体誰がこれを使うのかはわかりませんが、一応ココに置いておきます)

If you have a grayscale and you are using png_set_expand_depth(), png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to a higher bit-depth, you must either supply the background color as a gray value at the original file bit-depth (need_expand = 1) or else supply the background color as an RGB triplet at the final, expanded bit depth (need_expand = 0).  Similarly, if you are reading a paletted image, you must either supply the background color as a palette index (need_expand = 1) or as an RGB triplet that may or may not be in the palette (need_expand = 0).

    png_color_16 my_background;
    png_color_16p image_background;

    if (png_get_bKGD(png_ptr, info_ptr, &image_background))
        png_set_background(png_ptr, image_background,
          PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
    else
        png_set_background(png_ptr, &my_background,
          PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);

The png_set_background() function tells libpng to composite images with alpha or simple transparency against the supplied background color.  If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), you may use this color, or supply another color more suitable for the current display (e.g., the background color from a web page). 
You need to tell libpng whether the color is in the gamma space of the display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file (PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't know why anyone would use this, but it's here).

ある種のシステムにおいてPNG画像を適正にディスプレー表示するには、アプリケーションがディスプレー・ガンマがあることが分かっている必要がありま す。ユーザがこれを知っていて、アプリケーションにそれをセットさせられれば理想です。ユーザに各システムで独立しているディスプレー・ガンマをセットさ せる命令の一つが願わくば正確な値であってほしい SCREEN_GAMMA や DISPLAY_GAMMA 環境変数をチェックします。

display_gamma は満足な結果を得んがための全面ガンマ補正であり、周囲の照明環境に依存することに留意して下さい。ほの暗い部屋や明るい部屋では、モニタの物理ガンマ指 数以外で補正しないことが必要です。暗い部屋には若干小さめがいいでしょう。

   double gamma, screen_gamma;

   if (/* ユーザ定義のスクリーンガンマ値 */)
   {
      screen_gamma = user_defined_screen_gamma;
   }
   /* アプリケーションが同一スクリーンガンマ値を共有する方法 */
   else if ((gamma_str = getenv("SCREEN_GAMMA"))
      != NULL)
   {
      screen_gamma = (double)atof(gamma_str);
   }
   /* もう他の値がないとき */
   else
   {
      screen_gamma = 2.2; /* 明るいオフィスや薄暗い部屋の
                     PC モニタにおける妥当値 */
      screen_gamma = 2.0; /* 暗い部屋の
                     PC モニタにおける妥当値 */
      screen_gamma = 1.7 or 1.0;  /* マッキントッシュ
                     おける妥当値 */
   }

png_set_gamma() 関数はそのデータのガンマ変換を処理します。ファイルガンマと カレントの screen_gamma を両方渡します。ファイルがガンマ値を持たないなら、自分で考えた値(いつもはPC用GIF画像の0.45455が妥当)をどうにかひとつ渡すことができ ます。ファイルガンマはスクリーンガンマから反転されたものですので注意してください。ガンマの意義と全てのアプリケーションがどうしてそれをサポートす べきなのかということに関する素晴らしき記述はPNG仕様書内のガンマの論考を見て下さい。PNGビューアがガンマ補正をサポートすることを強く推奨しま す。

   if (png_get_gAMA(png_ptr, info_ptr, &gamma))
      png_set_gamma(png_ptr, screen_gamma, gamma);
   else
      png_set_gamma(png_ptr, screen_gamma, 0.45455);

To properly display PNG images on any kind of system, the application needs to know what the display gamma is.  Ideally, the user will know this, and the application will allow them to set it.  One method of allowing the user to set the display gamma separately for each system is to check for a SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be correctly set.

Note that display_gamma is the overall gamma correction required to produce pleasing results, which depends on the lighting conditions in the surrounding environment.  In a dim or brightly lit room, no compensation other than the physical gamma exponent of the monitor is needed, while in a dark room a slightly smaller exponent is better.

   double gamma, screen_gamma;

   if (/* We have a user-defined screen
       gamma value */)
   {
      screen_gamma = user_defined_screen_gamma;
   }
   /* One way that applications can share the same
      screen gamma value */
   else if ((gamma_str = getenv("SCREEN_GAMMA"))
      != NULL)
   {
      screen_gamma = (double)atof(gamma_str);
   }
   /* If we don't have another value */
   else
   {
      screen_gamma = 2.2; /* A good guess for a
           PC monitor in a bright office or a dim room */
      screen_gamma = 2.0; /* A good guess for a
           PC monitor in a dark room */
      screen_gamma = 1.7 or 1.0;  /* A good
           guess for Mac systems */
   }

The png_set_gamma() function handles gamma transformations of the data. Pass both the file gamma and the current screen_gamma.  If the file does not have a gamma value, you can pass one anyway if you have an idea what it is (usually 0.45455 is a good guess for GIF images on PCs).  Note that file gammas are inverted from screen gammas.  See the discussions on gamma in the PNG specification for an excellent description of what gamma is, and why all applications should support it.  It is strongly recommended that PNG viewers support gamma correction.

   if (png_get_gAMA(png_ptr, info_ptr, &gamma))
      png_set_gamma(png_ptr, screen_gamma, gamma);
   else
      png_set_gamma(png_ptr, screen_gamma, 0.45455);

RGBファイルからパレットファイルに減色したり、パレットファイルがそのスクリーンにフィットするようにエントリを追加するには、 png_set_dither() を使って下さい。これは単に利用可能な近似色を見つけて、単純にディザにマッチさせるだけなので注意して下さい。これは最適化パレットを使えばか なりきれいに処理されますが、線形カラーキューブをつかうと相当汚くなります。そのときのmaximum_colorsより大きいパレットを渡せば、ファ イルはパレットの色数を減らし、maximum_colors 内に収まらせます。ヒストグラムがあるなら、パレット減色時により賢い選択をさせることができます。ヒストグラムが無ければ、いい仕事にはなりません。

   if (color_type & PNG_COLOR_MASK_COLOR)
   {
      if (png_get_valid(png_ptr, info_ptr,
         PNG_INFO_PLTE))
      {
         png_uint_16p histogram = NULL;

         png_get_hIST(png_ptr, info_ptr,
            &histogram);
         png_set_dither(png_ptr, palette, num_palette,
            max_screen_colors, histogram, 1);
      }
      else
      {
         png_color std_color_cube[MAX_SCREEN_COLORS] =
            { ... colors ... };

         png_set_dither(png_ptr, std_color_cube,
            MAX_SCREEN_COLORS, MAX_SCREEN_COLORS,
            NULL,0);
      }
   }

PNGファイルは黒がゼロ、白が1でモノクロ表示します。下記コードでこれを逆に(黒が1、白がゼロ)もできます:

   if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY)
      png_set_invert_mono(png_ptr);

この関数はグレースケール及びアルファ付グレースケール画像も反転させられます:

   if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
      png_set_invert_mono(png_ptr);

ネットワーク・バイト・オーダー(ビッグ・エンディアン、すなわち最上位ビットが先頭)での16ビットPNGファイルです。このコードは他の記憶方法(リ トル・エンディアン、すなわち最下位ビットが先頭、PCの記憶方法)に変更します:

    if (bit_depth == 16)
        png_set_swap(png_ptr);

パックト・ピクセル(1, 2, 4 ビット/ピクセル)画像を使う上でピクセル順序を変更する必要があるなら、次の関数が使えます:

    if (bit_depth < 8)
       png_set_packswap(png_ptr);


If you need to reduce an RGB file to a paletted file, or if a paletted file has more entries then will fit on your screen, png_set_dither() will do that.  Note that this is a simple match dither that merely finds the closest color available.  This should work fairly well with optimized palettes, and fairly badly with linear color cubes.  If you pass a palette that is larger then maximum_colors, the file will reduce the number of colors in the palette so it will fit into maximum_colors.  If there is a histogram, it will use it to make more intelligent choices when reducing the palette.  If there is no histogram, it may not do as good a job.

   if (color_type & PNG_COLOR_MASK_COLOR)
   {
      if (png_get_valid(png_ptr, info_ptr,
         PNG_INFO_PLTE))
      {
         png_uint_16p histogram = NULL;

         png_get_hIST(png_ptr, info_ptr,
            &histogram);
         png_set_dither(png_ptr, palette, num_palette,
            max_screen_colors, histogram, 1);
      }
      else
      {
         png_color std_color_cube[MAX_SCREEN_COLORS] =
            { ... colors ... };

         png_set_dither(png_ptr, std_color_cube,
            MAX_SCREEN_COLORS, MAX_SCREEN_COLORS,
            NULL,0);
      }
   }

PNG files describe monochrome as black being zero and white being one. The following code will reverse this (make black be one and white be zero):

   if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY)
      png_set_invert_mono(png_ptr);

This function can also be used to invert grayscale and gray-alpha images:

   if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
      png_set_invert_mono(png_ptr);

PNG files store 16 bit pixels in network byte order (big-endian, ie. most significant bits first).  This code changes the storage to the other way (little-endian, i.e. least significant bits first, the way PCs store them):

    if (bit_depth == 16)
        png_set_swap(png_ptr);

If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you need to change the order the pixels are packed into bytes, you can use:

    if (bit_depth < 8)
       png_set_packswap(png_ptr);


自分の要求に応えられる関数がなければ、結局、自前の変換関数を書くことになります。次のようにコールバックを処理して処理します:

    png_set_read_user_transform_fn(png_ptr,
       read_transform_fn);

こちらの関数も設定する必要があります。

    void read_transform_fn(png_ptr ptr, row_info_ptr
       row_info, png_bytep data)

pngtest.c の処理例を見て下さい。他の変換処理が進むたび関数が呼ばれます。

自前の関数用にユーザの構造体のポインタをセットアップすることもできます。自前の関数がチャンネル数やビット深度を変更することを、次の関数で libpng に説明することもできます:

    png_set_user_transform_info(png_ptr, user_ptr,
       user_depth, user_channels);

ユーザ・アプリケーション、非libpng、においてはユーザの構造体用に要求されるメモリの確保及び解放をする義務はユーザにあります。

png_get_user_transform_ptr() 関数経由でポインタを取得することができます。例えば:

    voidp read_user_transform_ptr =
       png_get_user_transform_ptr(png_ptr);


Finally, you can write your own transformation function if none of the existing ones meets your needs.  This is done by setting a callback with

    png_set_read_user_transform_fn(png_ptr,
       read_transform_fn);

You must supply the function

    void read_transform_fn(png_ptr ptr, row_info_ptr
       row_info, png_bytep data)

See pngtest.c for a working example.  Your function will be called after all of the other transformations have been processed.

You can also set up a pointer to a user structure for use by your callback function, and you can inform libpng that your transform function will change the number of channels or bit depth with the function

    png_set_user_transform_info(png_ptr, user_ptr,
       user_depth, user_channels);

The user's application, not libpng, is responsible for allocating and freeing any memory required for the user structure.

You can retrieve the pointer via the function png_get_user_transform_ptr().  For example:

    voidp read_user_transform_ptr =
       png_get_user_transform_ptr(png_ptr);


ハンドルに関する最後の項目はインタレースです。これは下記で詳細をカバーしていますが、インタレース画像の拡張処理をlibpng に求めるなら、ココで関数を呼ばなければなりません。

    number_of_passes = png_set_interlace_handling(png_ptr);


The last thing to handle is interlacing; this is covered in detail below, but you must call the function here if you want libpng to handle expansion of the interlaced image.

    number_of_passes = png_set_interlace_handling(png_ptr);


変換設定後、この呼び出しで要求された変換を反映したpng_info 構造体をlibpng は更新できます。これは情報構造体の rowbytes 変数を更新するのに相当便利で、画像メモリを確保するのに使えます。呼び出す前に正確なスクリーンガンマ及び背景が設定されてれば、この関数はそれを伴う パレットもまた更新します。

    png_read_update_info(png_ptr, info_ptr);

png_read_update_info() を呼んだ後、画像に必要なメモリを確保できます。行データはシンプルな画像形式に対する生バイトです。実際のメモリ確保はアプリケーション間で変わるの で、お見せできるような例はありません。もし、ひとつ大きなチャンクのメモリを確保したら、下記の関数いくつかで必要となるような、各行へのポインタの配 列を作る必要があります。


After setting the transformations, libpng can update your png_info structure to reflect any transformations you've requested with this call.  This is most useful to update the info structure's rowbytes field so you can use it to allocate your image memory.  This function will also update your palette with the correct screen_gamma and  background if these have been given with the calls above.

    png_read_update_info(png_ptr, info_ptr);

After you call png_read_update_info(), you can allocate any memory you need to hold the image.  The row data is simply raw byte data for all forms of images.  As the actual allocation varies among applications, no example will be given.  If you are allocating one large chunk, you will need to build an array of pointers to each row, as it will be needed for some of the functions below.


画像データ読込

メモリ確保後、画像データを読み込みます。一番シンプルな方法は関数を一つ呼び出すだけです。画像を全部読み込むのに十分なメモリを確保したそのとき、 png_read_image() を呼ぶと、libpng が画像データを全て読み込んで指定されたメモリに配置します。その際、各行へのポインタの配列を渡す必要があります。

この関数はインタレースを自動的に処理するので、 png_set_interlace_handling() やこの関数を複数回呼んだり、またpng_read_rows() を使うようなもろもろの必要はありません。

   png_read_image(png_ptr, row_pointers);

row_pointers があるとこ:

   png_bytep row_pointers[height];

ピクセルに使っている型のポインタか void か char ポインタです。

一度に画像全部は読み込みたくないのなら、代わりに png_read_rows() が使えます。インタレースが無ければ(interlace_type == PNG_INTERLACE_NONE をチェック)、以下のようにシンプルです:

    png_read_rows(png_ptr, row_pointers, NULL,
       number_of_rows);

row_pointers があるとこは png_read_image() 呼び出し時と同じです。

一回に一つずつしか処理しないのなら、row_pointers の配列の代わりに1つだけの row_pointerで処理できます:

    png_bytep row_pointer = row;
    png_read_row(png_ptr, row_pointer, NULL);

ファイルがインタレース(IHDR チャンクで interlace_type != 0)なら、いささか面倒です。現行(PNG 仕様書バージョン1.2)のPNG用インタレース・タイプはご周知のAdam7(interlace_type == PNG_INTERLACE_ADAM7)しかありません。このインタレースは、若干複雑な2Dインタレース・スキームで、8x8 グリッドをベースとして小さくサイズ変更された7つの画像に解体します。

libpng は画像に対しインタレースを読み出せますし、「そのまま」渡すことも可能です。読み出しには、2つ方法があります。ひとつはPNG仕様書にある方法で、ま だ読み込まれてないピクセルをカバーするように各ピクセルを拡張します("矩形"命令)。最初のパスでブロック・イメージをつくり、徐々にピクセルを読み 込みながら滑らかにしていきます。もうひとつの方法は"輝く"命令です、色を読込の開始前に初期化して、画像に残ってる部分の最後の位置にピクセルを描き ます。前者のほうがいつもきれいに見えますが、行内に追加ピクセルを置いていくことになるので、遅くなりがちです。

インタレースの細かい処理を libpng に任せないのなら、png_read_rows() を7回呼んで7つ画像を読み込んでください。各画像はそれぞれだけで画像として成り立ち、各単独画像を 8x8 グリッドで連結することができます。
(とはいえ、たとえ連結するつもりでも、libpng インタレース処理のように切り離したままのほうがいいですよ)。


Reading image data

After you've allocated memory, you can read the image data. The simplest way to do this is in one function call.  If you are allocating enough memory to hold the whole image, you can just call png_read_image() and libpng will read in all the image data and put it in the memory area supplied.  You will need to pass in an array of pointers to each row.

This function automatically handles interlacing, so you don't need to call png_set_interlace_handling() or call this function multiple times, or any of that other stuff necessary with png_read_rows().

   png_read_image(png_ptr, row_pointers);

where row_pointers is:

   png_bytep row_pointers[height];

You can point to void or char or whatever you use for pixels.

If you don't want to read in the whole image at once, you can use png_read_rows() instead.  If there is no interlacing (check interlace_type == PNG_INTERLACE_NONE), this is simple:

    png_read_rows(png_ptr, row_pointers, NULL,
       number_of_rows);

where row_pointers is the same as in the png_read_image() call.

If you are doing this just one row at a time, you can do this with a single row_pointer instead of an array of row_pointers:

    png_bytep row_pointer = row;
    png_read_row(png_ptr, row_pointer, NULL);

If the file is interlaced (interlace_type != 0 in the IHDR chunk), things get somewhat harder.  The only current (PNG Specification version 1.2) interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) is a somewhat complicated 2D interlace scheme, known as Adam7, that breaks down an image into seven smaller images of varying size, based on an 8x8 grid.

libpng can fill out those images or it can give them to you "as is". If you want them filled out, there are two ways to do that.  The one mentioned in the PNG specification is to expand each pixel to cover those pixels that have not been read yet (the "rectangle" method). This results in a blocky image for the first pass, which gradually smooths out as more pixels are read.  The other method is the "sparkle" method, where pixels are drawn only in their final locations, with the rest of the image remaining whatever colors they were initialized to before the start of the read.  The first method usually looks better, but tends to be slower, as there are more pixels to put in the rows.

If you don't want libpng to handle the interlacing details, just call png_read_rows() seven times to read in all seven images.  Each of the images is a valid image by itself, or they can all be combined on an 8x8 grid to form a single image (although if you intend to combine them you would be far better off using the libpng interlace handling).


第1パスは画像全体の横 1/8(全8列中の行0からスタート)、縦 1/8(全8行中の0行からスタート) の画像を返し、
第2パスは横 1/8(列4からスタート)、縦 1/8(また行 0 からスタート) を返します。
第3パスは横 1/4 (全4ピクセル中の列0からスタート) で縦 1/8 (全8行中の行4からスタート)、
そして第4パスは 横 1/4、縦1/4 (全4列中の列2、全4行中の行0)。
第5パスは横1/2、縦1/4(列 0 行 2からスタート)、
第6パスは横1/2、縦 1/2(列 1 行 0)。
最後の第7パスは横は元の画像と同じ、縦 1/2、スキャンラインの奇数を全て含んでいます。ふ-っ!!

The first pass will return an image 1/8 as wide as the entire image (every 8th column starting in column 0) and 1/8 as high as the original (every 8th row starting in row 0), the second will be 1/8 as wide (starting in column 4) and 1/8 as high (also starting in row 0).  The third pass will be 1/4 as wide (every 4th pixel starting in column 0) and 1/8 as high (every 8th row starting in row 4), and the fourth pass will be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, and every 4th row starting in row 0).  The fifth pass will return an image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), while the sixth pass will be 1/2 as wide and 1/2 as high as the original (starting in column 1 and row 0).  The seventh and final pass will be as wide as the original, and 1/2 as high, containing all of the odd numbered scanlines.  Phew!


libpng で画像を拡張するとき、png_start_read_image() や png_read_update_info() を呼ぶ前にこちらの関数を呼んで下さい:

    if (interlace_type == PNG_INTERLACE_ADAM7)
        number_of_passes
           = png_set_interlace_handling(png_ptr);

これは必要なパス数を返します。現在のところは7ですが、将来違うインタレースタイプが加えられ、変更されるかもしれません。この関数はたとえファイルが 非インタレースでも、呼ぶことができますが、返り値は1パスです。

各パスの後に画像を画面表示しないなら、輝くエフェクトでも使いながら、画像が全部読み込まれるまで待つことになります。このエフェクトは早く、そしてど の命令でも最終結果は全く同じでです。もし各パスの後に画像を画面表示するつもりがあるなら「矩形」エフェクトの方が一般的にはいいものとして考えられて います。

「輝く」エフェクトを使うなら、普通に png_read_rows() を第3引数をNULLにして呼ぶだけです。各呼び出しの間に行データを変更せずに、画像を number_of_passes 回通ったか確認してください。そのデータではないデータは位置を変更することができます。前のパスが有効であるデータだと仮定して、各パスはそのパスに割 り当てられたピクセルだけ書き込むことができます。

    png_read_rows(png_ptr, row_pointers, NULL,
       number_of_rows);

前者のエフェクト(矩形)を使うなら、第3引数に行バッファを渡し、第2引数をNULLにすること以外は同じ処理をします。

    png_read_rows(png_ptr, NULL, row_pointers,
       number_of_rows);

If you want libpng to expand the images, call this before calling png_start_read_image() or png_read_update_info():

    if (interlace_type == PNG_INTERLACE_ADAM7)
        number_of_passes
           = png_set_interlace_handling(png_ptr);

This will return the number of passes needed.  Currently, this is seven, but may change if another interlace type is added. This function can be called even if the file is not interlaced, where it will return one pass.

If you are not going to display the image after each pass, but are going to wait until the entire image is read in, use the sparkle effect.  This effect is faster and the end result of either method is exactly the same.  If you are planning on displaying the image after each pass, the "rectangle" effect is generally considered the better looking one.

If you only want the "sparkle" effect, just call png_read_rows() as normal, with the third parameter NULL.  Make sure you make pass over the image number_of_passes times, and you don't change the data in the rows between calls.  You can change the locations of the data, just not the data.  Each pass only writes the pixels appropriate for that pass, and assumes the data from previous passes is still valid.

    png_read_rows(png_ptr, row_pointers, NULL,
       number_of_rows);

If you only want the first effect (the rectangles), do the same as before except pass the row buffer in the third parameter, and leave the second parameter NULL.

    png_read_rows(png_ptr, NULL, row_pointers,
       number_of_rows);

シーケンシャル読込の完了

高・低水準インタフェースどちらにしても画像の読込完了後に、ファイルの読込完了処理を行います。画像データの前か後かで記憶されたコメントと時間に興味 があり、画像の前後に分かれていたものを保持したいならpng_info 構造体を分けて引数として渡して下さい。興味がないなら引数はNULLで構いません。

   png_read_end(png_ptr, end_info);

処理時、以下のようにlibpng で確保したメモリを解放することもできます:

   png_destroy_read_struct(&png_ptr, &info_ptr,
       &end_info);


下記関数で、libpng で確保されたメモリ・ポインタの info_ptr メンバを個別に解放することもできます:

    png_free_data(png_ptr, info_ptr, mask, seq)
    mask - 解放されるデータのID、mask は論理OR演算で
           以下の一つ以上を選択
             PNG_FREE_PLTE, PNG_FREE_TRNS,
             PNG_FREE_HIST, PNG_FREE_ICCP,
             PNG_FREE_PCAL, PNG_FREE_ROWS,
             PNG_FREE_SCAL, PNG_FREE_SPLT,
             PNG_FREE_TEXT, PNG_FREE_UNKN,
           または単純に PNG_FREE_ALL
    seq  - 解放されるアイテムのシーケンス・ナンバー
           (-1 なら全アイテム)

この関数は関連メモリがすでに解放済みであったり、メモリが確保されていなくても、libpng でなくユーザによって確保されたものであっても、あるいはそうでなくても、安全に呼ばれるはずです。選択されたデータタイプがひとつだけなら"seq"引 数は無視されます、例えば PLTEなどの、可能なものです。"seq"が-1でなくて、mask にデータタイプIDで複数のアイテムが指定されたとき、例えば text や sPLTなど、"seq"をnとすれば構造体にある第nアイテムが解放されます。

デフォルトの動作ではlibpng 内部でメモリ確保されたデータを解放するだけです。これは変更することができるので、libpng はデータを解放しないようにしたり、png_malloc() や png_zalloc() などでユーザによってメモリ確保されたデータ及び png_set_*() を経由して渡されたデータを解放したりするようにできます。次のようにします:

    png_data_freer(png_ptr, info_ptr, freer, mask)
    mask   - png_free_data() 同様に選択して
                       反映させるデータ要素ID
    freer  - PNG_DESTROY_WILL_FREE_DATA
               PNG_SET_WILL_FREE_DATA
               PNG_USER_WILL_FREE_DATA
               のうちひとつ

この関数は既にメモリ確保済みのデータにのみ反映されます。ユーザやpng_set_*() 関数に与えられて存在するデータのメモリ解放義務があるかないかを決めたりするために、png_set_*() 関数を呼ぶ前で且つPNGデータ読込後であるときにこの関数を呼ぶことができます。また再度 png_set_*() 関数後にユーザや png_destroy_*()関数がデータを解放するのかどうかを決めるためにも呼ぶことができます。libpng がメモリ確保したデータについてユーザに義務があるとき、アプリケーションはメモリ解放するのにpng_free()を使わなければなりません。ユーザが 確保したメモリのデータの解放義務をlibpng に譲渡するには、ユーザはメモリ確保時にpng_malloc() や png_zalloc() を使わなければなりません。

Finishing a sequential read

After you are finished reading the image through either the high- or low-level interfaces, you can finish reading the file.  If you are interested in comments or time, which may be stored either before or after the image data, you should pass the separate png_info struct if you want to keep the comments from before and after the image separate.  If you are not interested, you can pass NULL.

   png_read_end(png_ptr, end_info);

When you are done, you can free all memory allocated by libpng like this:

   png_destroy_read_struct(&png_ptr, &info_ptr,
       &end_info);

It is also possible to individually free the info_ptr members that point to libpng-allocated storage with the following function:

    png_free_data(png_ptr, info_ptr, mask, seq)
    mask - identifies data to be freed, a mask
           containing the logical OR of one or
           more of
             PNG_FREE_PLTE, PNG_FREE_TRNS,
             PNG_FREE_HIST, PNG_FREE_ICCP,
             PNG_FREE_PCAL, PNG_FREE_ROWS,
             PNG_FREE_SCAL, PNG_FREE_SPLT,
             PNG_FREE_TEXT, PNG_FREE_UNKN,
           or simply PNG_FREE_ALL
    seq  - sequence number of item to be freed
           (-1 for all items)

This function may be safely called when the relevant storage has already been freed, or has not yet been allocated, or was allocated by the user and not by libpng,  and will in those cases do nothing.  The "seq" parameter is ignored if only one item of the selected data type, such as PLTE, is allowed.  If "seq" is not -1, and multiple items are allowed for the data type identified in the mask, such as text or sPLT, only the n'th item in the structure is freed, where n is "seq".

The default behavior is only to free data that was allocated internally by libpng.  This can be changed, so that libpng will not free the data, or so that it will free data that was allocated by the user with png_malloc() or png_zalloc() and passed in via a png_set_*() function, with

    png_data_freer(png_ptr, info_ptr, freer, mask)
    mask   - which data elements are affected
             same choices as in png_free_data()
    freer  - one of
               PNG_DESTROY_WILL_FREE_DATA
               PNG_SET_WILL_FREE_DATA
               PNG_USER_WILL_FREE_DATA

This function only affects data that has already been allocated. You can call this function after reading the PNG data but before calling any png_set_*() functions, to control whether the user or the png_set_*() function is responsible for freeing any existing data that might be present, and again after the png_set_*() functions to control whether the user or png_destroy_*() is supposed to free the data.  When the user assumes responsibility for libpng-allocated data, the application must use png_free() to free it, and when the user transfers responsibility to libpng for data that the user has allocated, the user must have used png_malloc() or png_zalloc() to allocate it.

単独ブロック中の row_pointers にメモリを確保したのなら、上記の高水準読込インタフェースの記述で推奨されるように、png_set_rows や png_read_destroy 関数のためにメモリ解放義務を譲渡してはいけません。なぜなら row_pointers[i]で個別にまた解放されるからです。

もし、text_ptr.text、text_ptr.lang、text_ptr.translated_keyword のメモリを別々に確保したのなら、libpng に text_ptr のメモリ解放義務は譲渡されません。なぜなら、libpng が png_text 構造体を完成させようとするとき、それらに key メンバを結合して、png_free_data() は text_ptr.key だけ解放します。同様に、text_ptr のメモリ解放義務をlibpng から自分のアプリケーションに譲渡するとき、アプリケーションは別々にそれらのメンバを解放してはいけません。

png_free_data() 関数は、メモリ解放用"valid"フラグをオフにします。libpng でなくアプリケーションによってメモリ解放されるようにチャンクのフラグをオフにする必要があります。次の関数が使えます:

    png_set_invalid(png_ptr, info_ptr, mask);
    mask - 無効にするチャンクID、
           論理OR演算1つ以上選択
             PNG_INFO_gAMA, PNG_INFO_sBIT,
             PNG_INFO_cHRM, PNG_INFO_PLTE,
             PNG_INFO_tRNS, PNG_INFO_bKGD,
             PNG_INFO_hIST, PNG_INFO_pHYs,
             PNG_INFO_oFFs, PNG_INFO_tIME,
             PNG_INFO_pCAL, PNG_INFO_sRGB,
             PNG_INFO_iCCP, PNG_INFO_sPLT,
             PNG_INFO_sCAL, PNG_INFO_IDAT

PNG画像のよりコンパクトな読込例については、example.c ファイルを見て下さい。

If you allocated your row_pointers in a single block, as suggested above in the description of the high level read interface, you must not transfer responsibility for freeing it to the png_set_rows or png_read_destroy function, because they would also try to free the individual row_pointers[i].

If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword separately, do not transfer responsibility for freeing text_ptr to libpng, because when libpng fills a png_text structure it combines these members with the key member, and png_free_data() will free only text_ptr.key.  Similarly, if you transfer responsibility for free'ing text_ptr from libpng to your application, your application must not separately free those members.

The png_free_data() function will turn off the "valid" flag for anything it frees.  If you need to turn the flag off for a chunk that was freed by your application instead of by libpng, you can use

    png_set_invalid(png_ptr, info_ptr, mask);
    mask - identifies the chunks to be made invalid,
           containing the logical OR of one or
           more of
             PNG_INFO_gAMA, PNG_INFO_sBIT,
             PNG_INFO_cHRM, PNG_INFO_PLTE,
             PNG_INFO_tRNS, PNG_INFO_bKGD,
             PNG_INFO_hIST, PNG_INFO_pHYs,
             PNG_INFO_oFFs, PNG_INFO_tIME,
             PNG_INFO_pCAL, PNG_INFO_sRGB,
             PNG_INFO_iCCP, PNG_INFO_sPLT,
             PNG_INFO_sCAL, PNG_INFO_IDAT

For a more compact example of reading a PNG image, see the file example.c.


プログレッシブPNGファイル読込

プログレッシブ読込は、若干 非プログレッシブ読込と異なります。 png_read_info(), png_read_rows(), png_read_end() を呼び出す代わりに、情報、行、画像の終わりの部分を持っているときにコールバック関数をpng_process_data() に呼び出させます。png_set_progressive_read_fn() にコールバック関数をセットアップします。ライブラリに png_process_data() でデータを設定しているので、 libpng の入出力関数の心配することはありません。上記PNGファイルの読込の項で、もう読み込みはできたかと思いますので、ここで相違部分のハイライトをお見せ します(とはいえ、一応一通りのコードをお見せするつもりです)。

Reading PNG files progressively

The progressive reader is slightly different then the non-progressive reader.  Instead of calling png_read_info(), png_read_rows(), and png_read_end(), you make one call to png_process_data(), which calls callbacks when it has the info, a row, or the end of the image.  You set up these callbacks with png_set_progressive_read_fn().  You don't have to worry about the input/output functions of libpng, as you are giving the library the data directly in png_process_data().  I will assume that you have read the section on reading PNG files above, so I will only highlight the differences (although I will show all of the code).


png_structp png_ptr;
png_infop info_ptr;

 /*  アプリケーションによるプログレシッブ読込の
     初期化方法の部分的サンプル・コード。 */
 int
 initialize_png_reader()
 {
    png_ptr = png_create_read_struct
        (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
         user_error_fn, user_warning_fn);
    if (!png_ptr)
        return (ERROR);
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
           (png_infopp)NULL);
        return (ERROR);
    }

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr,
           (png_infopp)NULL);
        return (ERROR);
    }
/* 新しいものがひとつあります。ヘッダ情報が有効なら、各行を完成させるときや、画像が終わると きに呼ばれる関数を設定することができます。関数を全く使わないなら、NULL 引数を設定できます。たとえ3つ関数がNULLでも、png_set_progressive_read_fn() は呼んでください。user_ptr (関数を呼んだときに void ポインタにキャストします)でどんな構造体も扱えますし、次の関数を使うコールバック関数の内側からのポインタを取得できます。

   png_get_progressive_ptr(png_ptr);

この関数はvoid ポインタを返すので、適切にキャストして下さい。
     */
    png_set_progressive_read_fn(png_ptr, (void *)user_ptr,
        info_callback, row_callback, end_callback);

    return 0;
 }

 /* データ・ブロックを取得するのに使う断片コード */
 int
 process_data(png_bytep buffer, png_uint_32 length)
 {
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr,
           (png_infopp)NULL);
        return (ERROR);
    }

/* こちらもまた新しいものがひとつあります。単純にファイル・ストリームからデータ・チャンクを 取得します(もちろん順番に)。セグメント・メモリ・モデル・マシン上では、64K より大きなものは使えません。ライブラリは4Kサイズでもうまく実行するように見えます。とはいえ、必要量にはそれでは少なすぎます (1バイトのチャンクがあるとしても、256バイトより小さいものはテストしません)。この関数が返るとき、全部処理が終わってなくてもコールバックで生 成された何行かを表示したいこともあるでしょう。
     */
    png_process_data(png_ptr, info_ptr, buffer, length);
    return 0;
 }
/* ヘッダが全部読み込んであって、十分なデータが提供されているとき、この(上記の png_set_progressive_read_fn() でセットされた)関数が呼ばれます。
 */
 void
 info_callback(png_structp png_ptr, png_infop info)
 {
/* ここで何かセットアップするのなら、「PNGファイル読込」の項で 書かれた変換の設定を含みます。ここではただ、セットされる全変換の後にpng_start_read_image() か png_read_update_info() を呼んで下さい(たとえ何もセットしないにしても)。png_process_data() が返る前に行の取得を始めて構いませんが、ここは準備のラストチャンスです。
     */
 }

/* この関数は各行の画像データを完成させるのに呼ばれます。 */
  void
 row_callback(png_structp png_ptr, png_bytep new_row,
    png_uint_32 row_num, int pass)
 {
/* インタレース画像で、インタレース・ハンドラがオンなら、この関数が各パスの行ごとに呼ばれます。いくつかの行は前のパ スからは変更されません。変更されない行は、new_row 変数がNULLです。行とパスは順番に呼ばれるので、row_num と pass 変数は本当は必要ありませんが、みなさんのゆとりを作るため、私はそれらを設定してます。

インタレース画像の非NULLの行について、現在の行とその前の行を引数にする png_progressive_combine_row()を呼ばなければなりません。コードを簡易なものにしたいなら、関数に渡す引数を、NULL行 (すぐ返ってきます)や、非インタレース画像(memcpyされるだけです)も可能です。以下のようにすべてのケースにおいて処理できます:
     */

        png_progressive_combine_row(png_ptr, old_row,
          new_row);

/* 現在の行の前に表示された old_row の位置です。最初のパス(本当に pass == 0)は完全に前の行をカバーするのでその行については初期化されてなくてもいいことに注意してください。最初のパスの後(及びインタレース画像用だけ)は 現在の行を渡さなければなりず、関数が前の行と新行を結合します。
     */
 }

 void
 end_callback(png_structp png_ptr, png_infop info)
 {
/* この関数は、画像の後の各チャンク(IENDを含め、且つIEND次第)を含め画像を全部読み込んだ後に呼ばれます。 ヘッダにあるのがいつも同じ情報チャンクでも、コメントや時間データといったいくつかのデータが追加されているはずです。

ここでは多くを行うのはよくないので、画像終端のフラグをセットしてください。
     */
 }



png_structp png_ptr;
png_infop info_ptr;

 /*  An example code fragment of how you would
     initialize the progressive reader in your
     application. */
 int
 initialize_png_reader()
 {
    png_ptr = png_create_read_struct
        (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
         user_error_fn, user_warning_fn);
    if (!png_ptr)
        return (ERROR);
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
           (png_infopp)NULL);
        return (ERROR);
    }

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr,
           (png_infopp)NULL);
        return (ERROR);
    }
/* This one's new. You can provide functions to be called when the header info is valid, when each row is completed, and when the image is finished. If you aren't using all functions, you can specify NULL parameters. Even when all three functions are NULL, you need to call png_set_progressive_read_fn(). You can use any struct as the user_ptr (cast to a void pointer for the function call), and retrieve the pointer from inside the callbacks using the function

   png_get_progressive_ptr(png_ptr);

which will return a void pointer, which you have to cast appropriately.
     */
    png_set_progressive_read_fn(png_ptr, (void *)user_ptr,
        info_callback, row_callback, end_callback);

    return 0;
 }

 /* A code fragment that you call as you receive blocks
   of data */
 int
 process_data(png_bytep buffer, png_uint_32 length)
 {
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr,
           (png_infopp)NULL);
        return (ERROR);
    }

/* This one's new also. Simply give it a chunk of data from the file stream (in order, of course). On machines with segmented memory models machines, don't give it any more than 64K. The library seems to run fine with sizes of 4K. Although you can give it much less if necessary (I assume you can give it chunks of 1 byte, I haven't tried less then 256 bytes yet). When this function returns, you may want to display any rows that were generated in the row callback if you don't already do so there.
     */
    png_process_data(png_ptr, info_ptr, buffer, length);
    return 0;
 }
/* This function is called (as set by png_set_progressive_read_fn() above) when enough data has been supplied so all of the header has been read.
 */
 void
 info_callback(png_structp png_ptr, png_infop info)
 {
/* Do any setup here, including setting any of the transformations mentioned in the Reading PNG files section. For now, you _must_ call either png_start_read_image() or png_read_update_info() after all the transformations are set (even if you don't set any). You may start getting rows before png_process_data() returns, so this is your last chance to prepare for that.
     */
 }

/* This function is called when each row of image
data is complete */
  void
 row_callback(png_structp png_ptr, png_bytep new_row,
    png_uint_32 row_num, int pass)
 {
/* If the image is interlaced, and you turned on the interlace handler, this function will be called for every row in every pass. Some of these rows will not be changed from the previous pass. When the row is not changed, the new_row variable will be NULL. The rows and passes are called in order, so you don't really need the row_num and pass, but I'm supplying them because it may make your life easier.

For the non-NULL rows of interlaced images, you must call png_progressive_combine_row() passing in the row and the old row. You can call this function for NULL rows (it will just return) and for non-interlaced images (it just does the memcpy for you) if it will make the code easier. Thus, you can just do this for all cases:
     */

        png_progressive_combine_row(png_ptr, old_row,
          new_row);

/* where old_row is what was displayed for previously for the row. Note that the first pass (pass == 0, really) will completely cover the old row, so the rows do not have to be initialized. After the first pass (and only for interlaced images), you will have to pass the current row, and the function will combine the old row and the new row.
     */
 }

 void
 end_callback(png_structp png_ptr, png_infop info)
 {
/* This function is called after the whole image has been read, including any chunks after the image (up to and including the IEND). You will usually have the same info chunk as you had in the header, although some data may have been added to the comments and time fields.

Most people won't do much here, perhaps setting a flag that marks the image as finished.
     */
 }



IV. 書込み


IV. Writing


ほとんど読込と一緒です。しかし、重要なことはまた一通りここで繰り返しますので、書込みを理解するのに上記の読 込の項をしきりに読み返すことはありません。


Much of this is very similar to reading.  However, everything of importance is repeated here, so you won't have to constantly look back up in the reading section to understand writing.


セットアップ

libpng に入る前に、I/O の初期化を行いますが、何も動作しなくてもやり直すことはありません。もし標準 I/O 関数を使わないのであれば、カスタム書込み関数に置き換えてください。下記「libpng のカスタマイズ」の論考を見て下さい。

    FILE *fp = fopen(file_name, "wb");
    if (!fp)
    {
       return (ERROR);
    }

次に、png_struct と png_info のメモリ確保と初期化を行います。両方とも比較的大きなものになるので、予備のスタック・スペースでもない限り、スタックに積むのはちょっと嫌かもしれま せん。無論、返り値がNULLであるかのチェックは行うと思います。また読込も含めて、自前の読込構造体及び書込み構造体両方に"png_ptr"という 名前は使いたくないでしょう; なので"read_ptr" や "write_ptr"といったような、好きな名前を付けられます。pngtest.c に例があるので見て下さい。

    png_structp png_ptr = png_create_write_struct
       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
        user_error_fn, user_warning_fn);
    if (!png_ptr)
       return (ERROR);

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
       png_destroy_write_struct(&png_ptr,
         (png_infopp)NULL);
       return (ERROR);
    }

自前のメモリ確保ルーチンを使いたいなら、PNG_USER_MEM_SUPPORTED をdefineして、png_create_write_struct() の代わりに png_create_write_struct_2() を使って下さい:

    png_structp png_ptr = png_create_write_struct_2
       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
        user_error_fn, user_warning_fn, (png_voidp)
        user_mem_ptr, user_malloc_fn, user_free_fn);

これらの構造体の用意ができたら、エラー処理のセットアップです。libpng がエラーに出くわしたら longjmp() でそちらで呼び出したルーチンに戻ります。それなので setjmp() を呼んでから png_jmpbuf(png_ptr) に渡して下さい。また違うルーチンでファイルに書込みを行うなら、毎回 setjmp/longjmp の入り口を png_*() 関数を呼ぶ新ルーチンに、png_jmpbuf(png_ptr) で更新してください。setjmp/longjmp の追加情報については、自分のコンパイラの setjmp/longjmp の文書を見て下さい。libpng エラー処理に関する追加情報については、下記「libpng のカスタマイズ」の 項のlibpng エラー処理の論考を見て下さい。

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

setjmp/longjmp の生む煩雑さからわざわざ避けようとしなくても、libpng をPNG_SETJMP_NOT_SUPPORTED でコンパイルすることもできます。その場合のエラーは abort() がデフォルトに設定されているPNG_ABORT()を呼ぶことになります。


Setup

You will want to do the I/O initialization before you get into libpng, so if it doesn't work, you don't have anything to undo. If you are not using the standard I/O functions, you will need to replace them with custom writing functions.  See the discussion under Customizing libpng.

    FILE *fp = fopen(file_name, "wb");
    if (!fp)
    {
       return (ERROR);
    }

Next, png_struct and png_info need to be allocated and initialized. As these can be both relatively large, you may not want to store these on the stack, unless you have stack space to spare.  Of course, you will want to check if they return NULL.  If you are also reading, you won't want to name your read structure and your write structure both "png_ptr"; you can call them anything you like, such as "read_ptr" and "write_ptr".  Look at pngtest.c, for example.

    png_structp png_ptr = png_create_write_struct
       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
        user_error_fn, user_warning_fn);
    if (!png_ptr)
       return (ERROR);

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
       png_destroy_write_struct(&png_ptr,
         (png_infopp)NULL);
       return (ERROR);
    }

If you want to use your own memory allocation routines,
define PNG_USER_MEM_SUPPORTED and use
png_create_write_struct_2() instead of png_create_write_struct():

    png_structp png_ptr = png_create_write_struct_2
       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
        user_error_fn, user_warning_fn, (png_voidp)
        user_mem_ptr, user_malloc_fn, user_free_fn);

After you have these structures, you will need to set up the error handling.  When libpng encounters an error, it expects to longjmp() back to your routine.  Therefore, you will need to call setjmp() and pass the png_jmpbuf(png_ptr).  If you write the file from different routines, you will need to update the png_jmpbuf(png_ptr) every time you enter a new routine that will call a png_*() function.  See your documentation of setjmp/longjmp for your compiler for more information on setjmp/longjmp.  See the discussion on libpng error handling in the Customizing Libpng section below for more information on the libpng error handling.

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

If you would rather avoid the complexity of setjmp/longjmp issues, you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case errors will result in a call to PNG_ABORT() which defaults to abort().


さて今度は、出力コードのセットアップです。デフォルトのlibpng ではC関数のfwrite() を使います。これを使うなら、有効な FILE * を関数 png_init_io() に渡して下さい。必ずファイルはバイナリモードで開いてください。また、違う方法でデータの書込み処理を行いたいのなら、下記「libpng のカスタマイズ」の項のlibpng I/O 処理の論考を見て下さい。

    png_init_io(png_ptr, fp);


Now you need to set up the output code.  The default for libpng is to use the C function fwrite().  If you use this, you will need to pass a valid FILE * in the function png_init_io().  Be sure that the file is opened in binary mode.  Again, if you wish to handle writing data in another way, see the discussion on libpng I/O handling in the Customizing Libpng section below.

    png_init_io(png_ptr, fp);


書込みコールバック

ここでは、プログレス・バーの表示などができるように、各行の書込み後に呼ばれるコールバック関数のセットアップを行います。このデモンストレーションが pngtest.c にあります。以下のように関数を設定しなければなりません:

    void write_row_callback(png_ptr, png_uint_32 row,
       int pass);
    {
      /* 自分のコードをココに書く */
    }


("write_row_callback"でなくて、何か違う好きな名前でも構いません)

libpng に自分の関数の情報を与えてください。やり方:

    png_set_write_status_fn(png_ptr, write_row_callback);

Write callbacks

At this point, you can set up a callback function that will be called after each row has been written, which you can use to control a progress meter or the like.  It's demonstrated in pngtest.c. You must supply a function

    void write_row_callback(png_ptr, png_uint_32 row,
       int pass);
    {
      /* put your code here */
    }

(You can give it another name that you like instead of "write_row_callback")

To inform libpng about your function, use

    png_set_write_status_fn(png_ptr, write_row_callback);

ライブラリが行う圧縮方法に対する変更オプションがあります。下記関数は主にテスト用ですが、多少の圧縮率を諦めることで超高速にPNGファイルを書込ん だり、低速高レベルな書込みで最大限の圧縮したり、一部のケースにおいて有用なものになります。このエリアで特別必要なものが無ければ、全くこの関数を呼 ばないで、適度な速度/圧縮率で、ライブラリに処理を行わせます。png_set_filter() へ渡す第2引数は、フィルタ命令ですが、有効な値は 0 だけです(1999.6月のPNG仕様書バージョン1.2より)が、あるいは 64 (MNG に適応するようなPNGデータストリームを書き込むなら)のときもあります。第3引数は各スキャンラインでチェックされるフィルタ・タイプ(複数可)を示 すフラグです。詳細はPNG仕様書のフィルタタイプの仕様を見て下さい。


    /* フィルタリングのオン・オフや、詳細フィルタの選択、
       又はその両方。単独でのPNG_FILTER_VALUE_NAMEでも
       論理OR演算を使ってPNG_FILTER_NAMEマスクを
       一つ以上使うこともできます */
    png_set_filter(png_ptr, 0,
       PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
       PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
       PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
       PNG_FILTER_AVE   | PNG_FILTER_VALUE_AVE  |
       PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
       PNG_ALL_FILTERS);

もしアプリケーションが
圧縮の途中で特殊なフィルタを使い始めたり、また使うのを止めたりしたいなら、全フィルタ(後で必要になる場合に備えて前の行のピクセルを記憶しておきま す)で始めて、圧縮開始後にその時々で加えたり削除したりします。

MNG データストリームに組み込まれるようなPNGデータストリームを書込むなら、第2引数は 0 か 64 になり得ます。

png_set_compression_*() 関数はzlib 圧縮ライブラリへのインタフェースですが、動作に関して相当分かってないかぎり、たいてい無視されます。唯一、一般的に役立つ呼び出しは、zlib の画像データの圧縮を行うのに消費する時間を、変更する関数の png_set_compression_level()です。圧縮レベルの詳細については、圧縮ライブラリ(zlib 配布ファイルの zlib.h と algorithm.txt)を見て下さい。

    /* zlib 圧縮レベルをセット */
    png_set_compression_level(png_ptr,
        Z_BEST_COMPRESSION);

    /* 他の zlib 引数をセット */
    png_set_compression_mem_level(png_ptr, 8);
    png_set_compression_strategy(png_ptr,
        Z_DEFAULT_STRATEGY);
    png_set_compression_window_bits(png_ptr, 15);
    png_set_compression_method(png_ptr, 8);
    png_set_compression_buffer_size(png_ptr, 8192)

extern PNG_EXPORT(void,png_set_zbuf_size)

You now have the option of modifying how the compression library will run.  The following functions are mainly for testing, but may be useful in some cases, like if you need to write PNG files extremely fast and are willing to give up some compression, or if you want to get the maximum possible compression at the expense of slower writing.  If you have no special needs in this area, let the library do what it wants by not calling this function at all, as it has been tuned to deliver a good speed/compression ratio. The second parameter to png_set_filter() is the filter method, for which the only valid values are 0 (as of the July 1999 PNG specification, version 1.2) or 64 (if you are writing a PNG datastream that is to be embedded in a MNG datastream).  The third parameter is a flag that indicates which filter type(s) are to be tested for each scanline.  See the PNG specification for details on the specific filter types.


    /* turn on or off filtering, and/or choose
       specific filters.  You can use either a single
       PNG_FILTER_VALUE_NAME or the logical OR of one
       or more PNG_FILTER_NAME masks. */
    png_set_filter(png_ptr, 0,
       PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
       PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
       PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
       PNG_FILTER_AVE   | PNG_FILTER_VALUE_AVE  |
       PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
       PNG_ALL_FILTERS);

If an application
wants to start and stop using particular filters during compression, it should start out with all of the filters (to ensure that the previous row of pixels will be stored in case it's needed later), and then add and remove them after the start of compression.

If you are writing a PNG datastream that is to be embedded in a MNG datastream, the second parameter can be either 0 or 64.

The png_set_compression_*() functions interface to the zlib compression library, and should mostly be ignored unless you really know what you are doing.  The only generally useful call is png_set_compression_level() which changes how much time zlib spends on trying to compress the image data.  See the Compression Library (zlib.h and algorithm.txt, distributed with zlib) for details on the compression levels.

    /* set the zlib compression level */
    png_set_compression_level(png_ptr,
        Z_BEST_COMPRESSION);

    /* set other zlib parameters */
    png_set_compression_mem_level(png_ptr, 8);
    png_set_compression_strategy(png_ptr,
        Z_DEFAULT_STRATEGY);
    png_set_compression_window_bits(png_ptr, 15);
    png_set_compression_method(png_ptr, 8);
    png_set_compression_buffer_size(png_ptr, 8192)

extern PNG_EXPORT(void,png_set_zbuf_size)

出力情報の中身の設定

今度は、実際の画像の前の部分に書込みを行いますが png_info 構造体のデータをすべて入力しておく必要があります。画像の後でも書込みが可能なのはテキストチャンクや時間チャンク(何れもPNG仕様書1.2と同様) だけですので注意して下さい。それに関する追加情報についてはpng_write_end() と 最新の PNG 仕様書 を見て下さい。画像データの前に書込みを行いたいのなら、今この瞬間に構造体を完成させ、有効なデータを与えて下さい。画像データの後まで待つのなら png_write_end()までその構造体を完成させることはありません。png_info 内にある全変数とそれらのデータ型については、png.h を見て下さい。変数に入ってるものの説明についてはPNG仕様書を見て下さい。

png_info のさらに重要な部分いくつかです:

    png_set_IHDR(png_ptr, info_ptr, width, height,
       bit_depth, color_type, interlace_type,
       compression_type, filter_method)
    width          - 画像ピクセル横幅が入ります (2^31まで)
    height         - 画像ピクセル高さが入ります (2^31まで)
    bit_depth      - ビット深度。画像チャンネルのうち
                     ひとつが入ります。
                     (有効な値は 1, 2, 4, 8, 16 で
                     color_type にもまた依存します。
                     下記の有意ビット(sBIT)も見て
                     下さい)。
    color_type     - 与えられたカラー/アルファチャンネルの
                     描写。
                     PNG_COLOR_TYPE_GRAY
                        (ビット深度 1, 2, 4, 8, 16)
                     PNG_COLOR_TYPE_GRAY_ALPHA
                        (ビット深度 8, 16)
                     PNG_COLOR_TYPE_PALETTE
                        (ビット深度 1, 2, 4, 8)
                     PNG_COLOR_TYPE_RGB
                        (ビット深度 8, 16)
                     PNG_COLOR_TYPE_RGB_ALPHA
                        (ビット深度 8, 16)

                     PNG_COLOR_MASK_PALETTE
                     PNG_COLOR_MASK_COLOR
                     PNG_COLOR_MASK_ALPHA

    interlace_type - PNG_INTERLACE_NONE か
                     PNG_INTERLACE_ADAM7
    compression_type - (PNG_COMPRESSION_TYPE_DEFAULTで
                     なければなりません)
    filter_method  - (PNG_FILTER_TYPE_DEFAULTで
                     なければなりませんが、または
                     MNG データストリームに組み込まれるような、
                     PNGを書き込むなら
                     PNG_INTRAPIXEL_DIFFERENCING
                     にもできます)

    png_set_PLTE(png_ptr, info_ptr, palette,
       num_palette);
    palette        - ファイル用パレット
                     (png_color の配列)
    num_palette    - パレットのエントリ数

    png_set_gAMA(png_ptr, info_ptr, gamma);
    gamma          - (PNG_INFO_gAMA) で生成される
                     画像のガンマ

    png_set_sRGB(png_ptr, info_ptr, srgb_intent);
    srgb_intent    - 表現仕様(PNG_INFO_sRGB)
                     sRGB チャンクの存在はピクセルデータが
                     sRGBカラー空間にあることを意味します。
                     チャンクは gAMA と cHRM の仕様値 にも
                     暗に関連します。
                     表現意図は International
                     Color Consortium
                    (http://www.color.org)
                     で定義されたCSS-1 特性です。
                     PNG_sRGB_INTENT_SATURATION,
                     PNG_sRGB_INTENT_PERCEPTUAL,
                     PNG_sRGB_INTENT_ABSOLUTE
                     PNG_sRGB_INTENT_RELATIVE.
                     のうち値をひとつとります。


Setting the contents of info for output

You now need to fill in the png_info structure with all the data you wish to write before the actual image.  Note that the only thing you are allowed to write after the image is the text chunks and the time chunk (as of PNG Specification 1.2, anyway).  See png_write_end() and the latest PNG specification for more information on that.  If you wish to write them before the image, fill them in now, and flag that data as being valid.  If you want to wait until after the data, don't fill them until png_write_end().  For all the fields in png_info and their data types, see png.h.  For explanations of what the fields contain, see the PNG specification.

Some of the more important parts of the png_info are:

    png_set_IHDR(png_ptr, info_ptr, width, height,
       bit_depth, color_type, interlace_type,
       compression_type, filter_method)
    width          - holds the width of the image
                     in pixels (up to 2^31).
    height         - holds the height of the image
                     in pixels (up to 2^31).
    bit_depth      - holds the bit depth of one of the
                     image channels.
                     (valid values are 1, 2, 4, 8, 16
                     and depend also on the
                     color_type.  See also significant
                     bits (sBIT) below).
    color_type     - describes which color/alpha
                     channels are present.
                     PNG_COLOR_TYPE_GRAY
                        (bit depths 1, 2, 4, 8, 16)
                     PNG_COLOR_TYPE_GRAY_ALPHA
                        (bit depths 8, 16)
                     PNG_COLOR_TYPE_PALETTE
                        (bit depths 1, 2, 4, 8)
                     PNG_COLOR_TYPE_RGB
                        (bit_depths 8, 16)
                     PNG_COLOR_TYPE_RGB_ALPHA
                        (bit_depths 8, 16)

                     PNG_COLOR_MASK_PALETTE
                     PNG_COLOR_MASK_COLOR
                     PNG_COLOR_MASK_ALPHA

    interlace_type - PNG_INTERLACE_NONE or
                     PNG_INTERLACE_ADAM7
    compression_type - (must be
                     PNG_COMPRESSION_TYPE_DEFAULT)
    filter_method  - (must be PNG_FILTER_TYPE_DEFAULT
                     or, if you are writing a PNG to
                     be embedded in a MNG datastream,
                     can also be
                     PNG_INTRAPIXEL_DIFFERENCING)

    png_set_PLTE(png_ptr, info_ptr, palette,
       num_palette);
    palette        - the palette for the file
                     (array of png_color)
    num_palette    - number of entries in the palette

    png_set_gAMA(png_ptr, info_ptr, gamma);
    gamma          - the gamma the image was created
                     at (PNG_INFO_gAMA)

    png_set_sRGB(png_ptr, info_ptr, srgb_intent);
    srgb_intent    - the rendering intent
                     (PNG_INFO_sRGB) The presence of
                     the sRGB chunk means that the pixel
                     data is in the sRGB color space.
                     This chunk also implies specific
                     values of gAMA and cHRM.  Rendering
                     intent is the CSS-1 property that
                     has been defined by the International
                     Color Consortium
                     (http://www.color.org).
                     It can be one of
                     PNG_sRGB_INTENT_SATURATION,
                     PNG_sRGB_INTENT_PERCEPTUAL,
                     PNG_sRGB_INTENT_ABSOLUTE, or
                     PNG_sRGB_INTENT_RELATIVE.

●用語解説
ICC(International Color Consortium)
いろいろなデバイスや環境などに対応したカラー国際基準を設定(Profile Format)したり推奨したりする団体。

    png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr,
       srgb_intent);
    srgb_intent    - 表現仕様(PNG_INFO_sRGB)
                     sRGB チャンクの存在はピクセルデータが
                     sRGBカラー空間にあることを意味します。
                     この関数は書込み済みのsRGB と一貫した
                     仕様値の gAMA と cHRM チャンクにもまた
                     起因します。

    png_set_iCCP(png_ptr, info_ptr, name, compression_type,
                      profile, proflen);
    name            - プロフィール名
    compression     - 圧縮タイプ; いつもPNG 1.0用の
                      PNG_COMPRESSION_TYPE_BASE です。
                      引数にNULLを与えれば無視されます。
    profile         - International Color Consortium カラー
                      プロフィールデータです。NULs を含む
                      かもしれません。
    proflen         - プロフィールデータのバイト長です。

    png_set_sBIT(png_ptr, info_ptr, sig_bit);
    sig_bit        - 与えられたカラータイプ(png_color_16)に
                     適していようといまいと
                     グレー、赤、緑、青チャンネルの
                     (PNG_INFO_sBIT)用の有意ビットの数です。

    png_set_tRNS(png_ptr, info_ptr, trans, num_trans,
       trans_values);
    trans          - パレット(PNG_INFO_tRNS)用
                     透過エントリの配列
    trans_values   - 非パレット画像(PNG_INFO_tRNS)用
                     の単一の透過色のグレースケールや
                     カラー・サンプル値
    num_trans      - 透過エントリの数
                     (PNG_INFO_tRNS)

    png_set_hIST(png_ptr, info_ptr, hist);
                    (PNG_INFO_hIST)
    hist           - パレットのヒストグラム(png_uint_16
                     の配列)

    png_set_tIME(png_ptr, info_ptr, mod_time);
    mod_time       - 画像の最終更新時間
                     (PNG_VALID_tIME)

    png_set_bKGD(png_ptr, info_ptr, background);
    background     - 背景色 (PNG_VALID_bKGD)

    png_set_text(png_ptr, info_ptr, text_ptr, num_text);
    text_ptr       - 画像のコメントを保持している png_text
                     の配列
    text_ptr[i].compression - "text" で使う圧縮タイプ
                          PNG_TEXT_COMPRESSION_NONE
                           PNG_TEXT_COMPRESSION_zTXt
                           PNG_ITXT_COMPRESSION_NONE
                           PNG_ITXT_COMPRESSION_zTXt
    text_ptr[i].key   - コメント用キーワード。
                 1〜79 文字に含まれねばなりません。
    text_ptr[i].text  - カレント・キーワード用テキスト・コメント。
                         NULL や空でもかまいません。
    text_ptr[i].text_length - 解凍後のテキストの文字列長。
                          0 は iTXt用。
    text_ptr[i].itxt_length - 解凍後の itxt 文字列長。
                          0 は tEXt/zTXt用。
    text_ptr[i].lang  - 言語コメント(NULL や
                         空は不定用)。
    text_ptr[i].translated_keyword  - UTF-8 でのキーワード
                         (NULL や 空は不定用).
    num_text       - コメント数

    png_set_sPLT(png_ptr, info_ptr, &palette_ptr,
       num_spalettes);
    palette_ptr    - 情報構造体内のパレットの
                     リストへ加えられる
                     png_sPLT_struct 構造体の配列。
    num_spalettes  - 加えられるパレット構造体の数。

    png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y,
        unit_type);
    offset_x  - スクリーンの左端からの
                     正数オフセット
    offset_y  - スクリーンの上端からの
                     正数オフセット
    unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER

    png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
        unit_type);
    res_x       - ピクセル/単位 のX方向への
                  物理解像度
    res_y       - ピクセル/単位 のY方向への
                  物理解像度
    unit_type   - PNG_RESOLUTION_UNKNOWN,
                  PNG_RESOLUTION_METER

    png_set_sCAL(png_ptr, info_ptr, unit, width, height)
    unit        - 物理スケール単位 (整数)
    width       - 物理スケール単位でのピクセル横幅
    height      - 物理スケール単位でのピクセル高さ
                  (横幅と高さは double型)

    png_set_sCAL_s(png_ptr, info_ptr, unit, width, height)
    unit        - 物理スケール単位 (整数)
    width       - 物理スケール単位でのピクセル横幅
    height      - 物理スケール単位でのピクセル高さ
                 (横幅と高さは"2.54"のような文字列)


    png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr,
       srgb_intent);
    srgb_intent    - the rendering intent
                     (PNG_INFO_sRGB) The presence of the
                     sRGB chunk means that the pixel
                     data is in the sRGB color space.
                     This function also causes gAMA and
                     cHRM chunks with the specific values
                     that are consistent with sRGB to be
                     written.

    png_set_iCCP(png_ptr, info_ptr, name, compression_type,
                      profile, proflen);
    name            - The profile name.
    compression     - The compression type; always
                      PNG_COMPRESSION_TYPE_BASE for PNG 1.0.
                      You may give NULL to this argument to
                      ignore it.
    profile         - International Color Consortium color
                      profile data. May contain NULs.
    proflen         - length of profile data in bytes.

    png_set_sBIT(png_ptr, info_ptr, sig_bit);
    sig_bit        - the number of significant bits for
                     (PNG_INFO_sBIT) each of the gray, red,
                     green, and blue channels, whichever are
                     appropriate for the given color type
                     (png_color_16)

    png_set_tRNS(png_ptr, info_ptr, trans, num_trans,
       trans_values);
    trans          - array of transparent entries for
                     palette (PNG_INFO_tRNS)
    trans_values   - graylevel or color sample values of
                     the single transparent color for
                     non-paletted images (PNG_INFO_tRNS)
    num_trans      - number of transparent entries
                     (PNG_INFO_tRNS)

    png_set_hIST(png_ptr, info_ptr, hist);
                    (PNG_INFO_hIST)
    hist           - histogram of palette (array of
                     png_uint_16)

    png_set_tIME(png_ptr, info_ptr, mod_time);
    mod_time       - time image was last modified
                     (PNG_VALID_tIME)

    png_set_bKGD(png_ptr, info_ptr, background);
    background     - background color (PNG_VALID_bKGD)

    png_set_text(png_ptr, info_ptr, text_ptr, num_text);
    text_ptr       - array of png_text holding image
                     comments
    text_ptr[i].compression - type of compression used
                 on "text" PNG_TEXT_COMPRESSION_NONE
                           PNG_TEXT_COMPRESSION_zTXt
                           PNG_ITXT_COMPRESSION_NONE
                           PNG_ITXT_COMPRESSION_zTXt
    text_ptr[i].key   - keyword for comment.  Must contain
                 1-79 characters.
    text_ptr[i].text  - text comments for current
                         keyword.  Can be NULL or empty.
    text_ptr[i].text_length - length of text string,
                 after decompression, 0 for iTXt
    text_ptr[i].itxt_length - length of itxt string,
                 after decompression, 0 for tEXt/zTXt
    text_ptr[i].lang  - language of comment (NULL or
                         empty for unknown).
    text_ptr[i].translated_keyword  - keyword in UTF-8 (NULL
                         or empty for unknown).
    num_text       - number of comments

    png_set_sPLT(png_ptr, info_ptr, &palette_ptr,
       num_spalettes);
    palette_ptr    - array of png_sPLT_struct structures
                     to be added to the list of palettes
                     in the info structure.
    num_spalettes  - number of palette structures to be
                     added.

    png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y,
        unit_type);
    offset_x  - positive offset from the left
                     edge of the screen
    offset_y  - positive offset from the top
                     edge of the screen
    unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER

    png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
        unit_type);
    res_x       - pixels/unit physical resolution
                  in x direction
    res_y       - pixels/unit physical resolution
                  in y direction
    unit_type   - PNG_RESOLUTION_UNKNOWN,
                  PNG_RESOLUTION_METER

    png_set_sCAL(png_ptr, info_ptr, unit, width, height)
    unit        - physical scale units (an integer)
    width       - width of a pixel in physical scale units
    height      - height of a pixel in physical scale units
                  (width and height are doubles)

    png_set_sCAL_s(png_ptr, info_ptr, unit, width, height)
    unit        - physical scale units (an integer)
    width       - width of a pixel in physical scale units
    height      - height of a pixel in physical scale units
                 (width and height are strings like "2.54")


    png_set_unknown_chunks(png_ptr, info_ptr, &unknowns,
       num_unknowns)
    unknowns          - 不定チャンクを保持している
                        png_unknown_chunk 構造体の配列
    unknowns[i].name  - 不定チャンク名
    unknowns[i].data  - 不定チャンクデータ
    unknowns[i].size  - 不定チャンクデータサイズ
    unknowns[i].location - ファイルにチャンクを書込む位置
                           0: チャンクを書込みません
                           PNG_HAVE_IHDR: PLTEの前
                           PNG_HAVE_PLTE: IDATの前
                           PNG_AFTER_IDAT: IDATの後

"location"メンバは既に出力ファイルに書込み済みの部分と自動的に一致します。pngtest.c で示している実例のようにpng_set_unknown_chunks() を呼んだ後に変更することができます。それぞれの"locations" の中は、チャンクは構造体(そうです、入力ファイルから読み込むか、png_set_unknown_chunks で定義されたチャンクの順 序を示すところの "i"の値です)内の位置が一致するようにシーケンスされます。


    png_set_unknown_chunks(png_ptr, info_ptr, &unknowns,
       num_unknowns)
    unknowns          - array of png_unknown_chunk
                        structures holding unknown chunks
    unknowns[i].name  - name of unknown chunk
    unknowns[i].data  - data of unknown chunk
    unknowns[i].size  - size of unknown chunk's data
    unknowns[i].location - position to write chunk in file
                           0: do not write chunk
                           PNG_HAVE_IHDR: before PLTE
                           PNG_HAVE_PLTE: before IDAT
                           PNG_AFTER_IDAT: after IDAT

The "location" member is set automatically according to what part of the output file has already been written. You can change its value after calling png_set_unknown_chunks() as demonstrated in pngtest.c.  Within each of the "locations", the chunks are sequenced according to their position in the structure (that is, the value of "i", which is the order in which the chunk was either read from the input file or defined with png_set_unknown_chunks).


text と num_text に関する話。text はpng_text 構造体の配列です。num_text は配列内の有効な構造体数です。各png_text 構造体は言語コード、キーワード、テキスト値、圧縮タイプを保持します。

圧縮タイプの有効値は画像データの圧縮と同じ数値です。現在のところ、有効な数値はゼロだけです。しかし、常に圧縮される画像データとは違い、圧縮か非圧 縮かは text に記憶することができます。従ってtext の圧縮を望まないのなら圧縮タイプにPNG_TEXT_COMPRESSION_NONE.をセットして下さい。なぜなら 言語コードや変換されたキーワードがまだ書き出されてないのにPNG_TEXT_COMPRESSION_NONE や PNG_TEXT_COMPRESSION_zTXt を指定しても、tEXt と zTXt チャンクは言語変数を持てないので。

text も 1000 バイトくらいまでは、圧縮する価値がありません。text がファイルに書き出された後、圧縮タイプはPNG_TEXT_COMPRESSION_NONE_WR や PNG_TEXT_COMPRESSION_zTXt_WR にセットされるので、最後(この場合、同じ構造体で png_write_end() を呼んでいます)まで2度と書き出されません。

PNG仕様書によって与えられたキーワード:


Title 短い(1行) タイトルか
画像のキャプション

Author 画像の作者名

Description 画像に関する記述 (長くても可)

Copyright 著作権表示

Creation Time 画像の最初の作成時間
(通常 RFC 1123 フォーマットです、下記参照)

Software 画像作成に使用したソフトウェア

Disclaimer 法的放棄声明

Warning 中身の特性に関する警告

Source 画像作成に使用したデバイス

Comment 雑多コメント;他の画像形式への変換


A quick word about text and num_text.  text is an array of png_text structures.  num_text is the number of valid structures in the array. Each png_text structure holds a language code, a keyword, a text value, and a compression type.

The compression types have the same valid numbers as the compression types of the image data.  Currently, the only valid number is zero. However, you can store text either compressed or uncompressed, unlike images, which always have to be compressed.  So if you don't want the text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. Because tEXt and zTXt chunks don't have a language field, if you specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt any language code or translated keyword will not be written out.

Until text gets around 1000 bytes, it is not worth compressing it. After the text has been written out to the file, the compression type is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, so that it isn't written out again at the end (in case you are calling png_write_end() with the same struct.

The keywords that are given in the PNG Specification are:


Title Short (one line) title or
caption for image

Author Name of image's creator

Description Description of image (possibly long)

Copyright Copyright notice

Creation Time Time of original image creation
(usually RFC 1123 format, see below)

Software Software used to create the image

Disclaimer Legal disclaimer

Warning Warning of nature of content

Source Device used to create the image

Comment Miscellaneous comment; conversion
from other image format


キーワードとテキストのペアは次のように処理されます。キーワードには関連したコメントが短く簡潔に書かれます。PNG仕様書に書かれたいくつかの典型的 なキーワードは、そのまま提言されています。ファイルにキーワードを繰り返し使うこともできます。画像の前にも後にもそれぞれ書き込むことができます。例 えば、画像データの前に画像の効果の記述を書き込むことがあるかと思いますが、後々の免責条項まではちょっと間があり、ビューアはモデム接続をやり直し て、画像の表示を始める前に免責条項を待たないことになりますが、それで構いません。最後に、キーワードは必ず全文を入れるようにして、省略はしないで下 さい。キーワードとテキストはISO 8859-1 (Latin-1) 文字でNUL や制御文字や他の印字不能文字を含まない標準 ASCII の上位集合がセットされています。うまく読みやすいコメントを書くには、基本 ASCII に忠実にすることで、IBM-PC 文字セットのようなマシン特有の拡張文字セットを使うことは避けることです。キーワードは必ず与えられなければなりませんが、非圧縮ペアに限ってはテキス ト文字列を省くことができます。圧縮ペアはテキスト文字列も持たなければならず、テキスト文字列だけはどうにか圧縮したとしても、あんまり圧縮の意味がな いと思います。


The keyword-text pairs work like this.  Keywords should be short simple descriptions of what the comment is about.  Some typical keywords are found in the PNG specification, as is some recommendations on keywords.  You can repeat keywords in a file.  You can even write some text before the image and some after.  For example, you may want to put a description of the image before the image, but leave the disclaimer until after, so viewers working over modem connections don't have to wait for the disclaimer to go over the modem before they start seeing the image.  Finally, keywords should be full words, not abbreviations.  Keywords and text are in the ISO 8859-1 (Latin-1) character set (a superset of regular ASCII) and can not contain NUL characters, and should not contain control or other unprintable characters.  To make the comments widely readable, stick with basic ASCII, and avoid machine specific character set extensions like the IBM-PC character set.  The keyword must be present, but you can leave off the text string on non-compressed pairs. Compressed pairs must have a text string, as only the text string is compressed anyway, so the compression would be meaningless.

PNGはpng_time 構造体を使った時間変更をサポートします。2つの変換ルーチンがあり、time_t 構造体用のpng_convert_from_time_t() と tm 構造体用のpng_convert_from_struct_tm() です。time_t 構造体のルーチンは gmtime() 関数を使います。これらどちらかを使わなくても構いませんが、png_time 構造体に直接書き込みたいなら、できればローカル時間は使わずにグリニッジ標準時 (GMT) を使ってください。年の数字は全表示(例: 98ではなく 1998、… PNG は 2000 年問題準拠です!)で、月は1からスタートすることに留意して下さい。

オリジナル画像作成時の時間を記憶したいなら、"Creation Time"キーワードのプレーン tEXt チャンクを使って下さい。これが必要なのはPNG画像において"creation time"が若干はっきりしないからで、PNGファイルであるかどうか、その時間その画像に作成されたのは非PNGフォーマット、スキャンされた画像であ る静止画像、ことによれば対象自身によります。マシンが日付を解析しやすいように、"Creation Time"の tEXt チャンクには RFC 1123フォーマットの日付(例: "22 May 1997 18:07:10 GMT")を使うことが推奨されますが、これについては要求はされません。tIME チャンクとは違って、"Creation Time" tEXt チャンクは ソフトウェアによって自動的に変更されるとは考えられていません。RFC 1123フォーマットの日付を使いやすいように、PNG 時間からRFC 1123形式の文字列への変換を行う関数 png_convert_to_rfc1123(png_timep) があります。


PNG supports modification time via the png_time structure.  Two conversion routines are provided, png_convert_from_time_t() for time_t and png_convert_from_struct_tm() for struct tm.  The time_t routine uses gmtime().  You don't have to use either of these, but if you wish to fill in the png_time structure directly, you should provide the time in universal time (GMT) if possible instead of your local time.  Note that the year number is the full year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and that months start with 1.

If you want to store the time of the original image creation, you should use a plain tEXt chunk with the "Creation Time" keyword.  This is necessary because the "creation time" of a PNG image is somewhat vague, depending on whether you mean the PNG file, the time the image was created in a non-PNG format, a still photo from which the image was scanned, or possibly the subject matter itself.  In order to facilitate machine-readable dates, it is recommended that the "Creation Time" tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), although this isn't a requirement.  Unlike the tIME chunk, the "Creation Time" tEXt chunk is not expected to be automatically changed by the software.  To facilitate the use of RFC 1123 dates, a function png_convert_to_rfc1123(png_timep) is provided to convert from PNG time to an RFC 1123 format string.


不定チャンクの書込み

書込み用チャンクにのキューに追加するのにpng_set_unknown_chunks 関数が使えます。チャンクに名前を付けて、生データ、サイズ; それに入ってる全部のデータをセットします。次の下記 png_write_info_before_PLTE 関数や、png_write_info関数、png_write_end function 関数でチャンクは書き込まれます。いくつかのチャンクは、情報構造体の不定チャンク・リストに前もって読み込まれ、またPNG仕様書の順序付けルールに 沿ったシーケンスで書き出されます。


Writing unknown chunks

You can use the png_set_unknown_chunks function to queue up chunks for writing.  You give it a chunk name, raw data, and a size; that's all there is to it.  The chunks will be written by the next following png_write_info_before_PLTE, png_write_info, or png_write_end function. Any chunks previously read into the info structure's unknown-chunk list will also be written out in a sequence that satisfies the PNG specification's ordering rules.

高水準書込みインタフェース

現時点では、2種類の書込み進行方法があります; 高水準書込みインタフェースを介するものと、低水準書込み命令を連続して使うものです。画像データに情報構造体があれば、高水準書込みインタフェースを使 うことができます。全ての定義済みの変換が許可され、下記マスクが使えます。


PNG_TRANSFORM_IDENTITY 無変換
PNG_TRANSFORM_PACKING 1, 2 4 ビット・パック・サンプル
PNG_TRANSFORM_PACKSWAP パックト・ピクセルの順序をLSBを先頭に変更
PNG_TRANSFORM_INVERT_MONO モノクロ画像反転
PNG_TRANSFORM_SHIFT 通常ピクセルを sBIT 深度へ
PNG_TRANSFORM_BGR RGB → BGR、 RGBA → BGRA の変換
PNG_TRANSFORM_SWAP_ALPHA RGBA → ARGB または GA → AG
PNG_TRANSFORM_INVERT_ALPHA アルファを不透明から透明へ変更
PNG_TRANSFORM_SWAP_ENDIAN 16ビットサンプルのバイト・スワップ
PNG_TRANSFORM_STRIP_FILLER 補充バイトの削除

情報構造体にある画像データが有効なら(情報構造体にある画像データを書き込むのに png_set_rows() が使えます)、次のようにシンプルに処理します:

    png_write_png(png_ptr, info_ptr, png_transforms, NULL)

png_transforms のところには変換フラグの論理ORのセットを入れた整数が入ります。この呼び出しは、下記の変換マスクで指定された変換セットを使った png_write_info()、それからpng_write_image()と、最後のpng_write_end() へ続く呼び出しと同等です。

(この呼び出しの最後の引数は、まだ使えません。いつか将来的に何かの出力変換を要求する変換へのポインタ引数になる予定です。)

png_write_png() を使うなら、必ずpng_transforms 引数を使い、どの png_set_transform() 関数も使ってはいけません。


The high-level write interface

At this point there are two ways to proceed; through the high-level write interface, or through a sequence of low-level write operations. You can use the high-level interface if your image data is present in the info structure.  All defined output transformations are permitted, enabled by the following masks.


PNG_TRANSFORM_IDENTITY No transformation
PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples
PNG_TRANSFORM_PACKSWAP Change order of packed pixels to LSB first
PNG_TRANSFORM_INVERT_MONO Invert monochrome images
PNG_TRANSFORM_SHIFT Normalize pixels to the sBIT depth
PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA to BGRA
PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA to AG
PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity to transparency
PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples
PNG_TRANSFORM_STRIP_FILLER Strip out filler bytes.

If you have valid image data in the info structure (you can use png_set_rows() to put image data in the info structure), simply do this:

    png_write_png(png_ptr, info_ptr, png_transforms, NULL)

where png_transforms is an integer containing the logical OR of some set of transformation flags.  This call is equivalent to png_write_info(), followed the set of transformations indicated by the transform mask, then png_write_image(), and finally png_write_end().

(The final parameter of this call is not yet used.  Someday it might point to transformation parameters required by some future output transform.)

You must use png_transforms and not call any png_set_transform() functions when you use png_write_png().


低水準書込みインタフェース

上記の代わりに低水準ルートで行くのなら、実際の画像のファイル情報を今この瞬間に書き込めるようにして置いてください。png_write_info () で処理を行います。

    png_write_info(png_ptr, info_ptr);

行うなら png_write_info() の前に処理を行った方がいい変換がひとつあるので気をつけて下さい。PNGファイルにおいて、画像のアルファチャンネルは不透明度です。データ上透明度と して扱いたいなら、書き込む前に反転することができます。0 が完全透明で255(8ビットなどパレット画像)や65535(16ビット画像)が完全不透明です。次のようにします。

    png_set_invert_alpha(png_ptr);

これは他の変換の行った後ではなく、png_write_info() の前に出てこなければなりません。なぜならパレット画像のケースではtRNS チャンクが書き込まれる前にtRNS チャンク・データは反転されてなければならないからです。パレット画像でないなら、tRNS データ(この場合透過値として指定された1色に相当します)は変更されなくても構いませんし、png_write_info() を呼んだ後にこの変換を安全に処理することができます。


The low-level write interface

If you are going the low-level route instead, you are now ready to write all the file information up to the actual image data.  You do this with a call to png_write_info().

    png_write_info(png_ptr, info_ptr);

Note that there is one transformation you may need to do before png_write_info().  In PNG files, the alpha channel in an image is the level of opacity.  If your data is supplied as a level of transparency, you can invert the alpha channel before you write it, so that 0 is fully transparent and 255 (in 8-bit or paletted images) or 65535 (in 16-bit images) is fully opaque, with

    png_set_invert_alpha(png_ptr);

This must appear before png_write_info() instead of later with the other transformations because in the case of paletted images the tRNS chunk data has to be inverted before the tRNS chunk is written.  If your image is not a paletted image, the tRNS data (which in such cases represents a single color to be rendered as transparent) won't need to be changed, and you can safely do this transformation after your png_write_info() call.


PLTE が与えられたときのPLTE チャンクの前に出てくるプライベート・チャンクを書き込みたいなら、2ステップでPNG 情報を書き込み、それらの間に自分自身のチャンクをコード挿入することができます:

    png_write_info_before_PLTE(png_ptr, info_ptr);
    png_set_unknown_chunks(png_ptr, info_ptr, ...);
    png_write_info(png_ptr, info_ptr);


If you need to write a private chunk that you want to appear before the PLTE chunk when PLTE is present, you can write the PNG info in two steps, and insert code to write your own chunk between them:

    png_write_info_before_PLTE(png_ptr, info_ptr);
    png_set_unknown_chunks(png_ptr, info_ptr, ...);
    png_write_info(png_ptr, info_ptr);

(出力変換設定)

ファイル情報を書き込んだ後、画像データに特殊な変換処理を行うライブラリをセットアップすることができます。各種のデータ変換方法はそれらが生じた順序 で反映されていきます。カラータイプまたはビットとビット深度、またはその両方を変更するような一部の変換のように、重要なものもあります。それぞれの変 換は、処理の行えるデータを持っているかきちんとチェックするので、データが有効であるかどうか変換が可能であるかどうかだけ確かめて下さい。例えば、グ レースケールデータで赤と青を入れ替えるようなことはしないで下さい。

PNGファイルは3、6バイトにパックされたRGB ピクセルを扱います。このコードは入力データの4、8バイト/ピクセルを3、6バイトにピクセルダウンする(または2、4のグレースケール+フィラー・ データから1、2のバイト/ピクセルに減らします)ようにライブラリに、伝えます。

    png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);

0 のところは使われません。その次のPNG_FILLER_BEFORE の位置には、 ピクセル中のフィラーバイトが XRGB か RGBX かでPNG_FILLER_BEFORE や PNG_FILLER_AFTER になります。




After you've written the file information, you can set up the library to handle any special transformations of the image data.  The various ways to transform the data will be described in the order that they should occur.  This is important, as some of these change the color type and/or bit depth of the data, and some others only work on certain color types and bit depths.  Even though each transformation checks to see if it has data that it can do something with, you should make sure to only enable a transformation if it will be valid for the data.  For example, don't swap red and blue on grayscale data.

PNG files store RGB pixels packed into 3 or 6 bytes.  This code tells the library to strip input data that has 4 or 8 bytes per pixel down to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 bytes per pixel).

    png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);

where the 0 is unused, and the location is either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel is stored XRGB or RGBX.


PNGファイルは1、2、4のビット深度のピクセルを、結果的にできるだけ小さくなるように、バイトにパックします。例えば、1ビットなら1バイトに8ピ クセルが入ります。1ピクセル1バイトにデータを指定するなら、1つのバイトに正確にピクセルをパックする、以下のコードを使って下さい:

    png_set_packing(png_ptr);

PNGファイルは1, 2, 4, 8, 16の可能なビット深度へ減らすことができます。もしデータが違うビット深度にあれば、ファイルに sBIT チャンクを書き込むこともできますし、望むならデコーダは元のデータを元の値にリカバーすることもできます。

    /* 画像データの本当のビット深度をセットします */
    if (color_type & PNG_COLOR_MASK_COLOR)
    {
        sig_bit.red = true_bit_depth;
        sig_bit.green = true_bit_depth;
        sig_bit.blue = true_bit_depth;
    }
    else
    {
        sig_bit.gray = true_bit_depth;
    }
    if (color_type & PNG_COLOR_MASK_ALPHA)
    {
        sig_bit.alpha = true_bit_depth;
    }

    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

PNGにサポートされるビット深度でなく、他の違うビット深度(例: 0〜7の範囲にある4ビット用の3ビット・データ)の行バッファにデータが記憶されるようなら、これはPNGに要求されるままの正確なビット深度であるよ うに見えるように値をスケール化します。

    png_set_shift(png_ptr, &sig_bit);


PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as they can, resulting in, for example, 8 pixels per byte for 1 bit files. If the data is supplied at 1 pixel per byte, use this code, which will correctly pack the pixels into a single byte:

    png_set_packing(png_ptr);

PNG files reduce possible bit depths to 1, 2, 4, 8, and 16.  If your data is of another bit depth, you can write an sBIT chunk into the file so that decoders can recover the original data if desired.

    /* Set the true bit depth of the image data */
    if (color_type & PNG_COLOR_MASK_COLOR)
    {
        sig_bit.red = true_bit_depth;
        sig_bit.green = true_bit_depth;
        sig_bit.blue = true_bit_depth;
    }
    else
    {
        sig_bit.gray = true_bit_depth;
    }
    if (color_type & PNG_COLOR_MASK_ALPHA)
    {
        sig_bit.alpha = true_bit_depth;
    }

    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

If the data is stored in the row buffer in a bit depth other than one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), this will scale the values to appear to be the correct bit depth as is required by PNG.

    png_set_shift(png_ptr, &sig_bit);


PNGファイルはネットワーク・バイト・オーダー(ビッグ・エンディアン、つまり最上位ビットが先頭)で16ビット・ピクセルを扱います。以下のコードで は別の方法(リトル・エンディアン、つまり最下位ビットが先頭、PCのメモリと同じ)を使っています:

    if (bit_depth > 8)
       png_set_swap(png_ptr);

パック式ピクセル画像(1, 2, 4 ビット/ピクセル)を使っているときの、バイトにパックされたピクセルの順序を変更するためのその方法:

    if (bit_depth < 8)
       png_set_packswap(png_ptr);

赤、緑、青の3色ピクセルを使うPNGファイルです。以下のコードは、青、緑、赤の順に指定して使うものです:

    png_set_bgr(png_ptr);

黒はゼロ、白を1として扱うモノクロ画像のPNGファイルです。以下のコードは、ここに予約済みの値(黒は1、白をゼロとして)を指定するピクセルを使っ たものです:

    png_set_invert_mono(png_ptr);

最後に、自分で使いたい関数がもし無いようなら、自前の変換関数を使った書込みもできます。以下ではコールバックを設定して処理しています:

    png_set_write_user_transform_fn(png_ptr,
       write_transform_fn);

そして自前の関数を設定しなければなりません:

    void write_transform_fn(png_ptr ptr, row_info_ptr
       row_info, png_bytep data)

処理の例についてはpngtest.c を見て下さい。自前関数は他のどの変換が行われるより前に呼ばれます。

自前コールバック関数で使うためのユーザの構造体のポインタをセットアップできます。

    png_set_user_transform_info(png_ptr, user_ptr, 0, 0);

この関数の user_channels と user_depth 引数は、書き込み時無視されます; ご覧の通りゼロにセットして下さい。

png_get_user_transform_ptr() 関数を経由してポインタを取得できます。
例えば:

    voidp write_user_transform_ptr =
       png_get_user_transform_ptr(png_ptr);

libpng は一定の行数を書き込んだ後に自動かマニュアルかどちらかの方法で未処理の出力を、フラッシュすることができます。出力ストリームを一遍にフラッシュしま す:

    png_write_flush(png_ptr);

libpng は一定のスキャンラインを書き込んだ後に、定期的に出力ストリームをフラッシュします:

    png_set_flush(png_ptr, nrows);

行と行の間は一番最後の png_write_flush() の呼び出しからか、それが全く呼ばれてないなら画像の一番最初の行からの距離になることに注意して下さい。50行書き込んで png_set_flush 25 なら、25行書き込む前に png_write_flush()を呼んでしまわない限り、それ以降25行ずつ次のスキャンラインで出力をフラッシュします。n行が小さすぎるとき(横 幅640ピクセルのRGB画像で大体10行より小さいとき)、画像の圧縮率は著しく減少します(とは言ってもリアル・タイム・アプリケーションには向いて いますが)。フラッシュはめったに行われませんが、フラッシュされないものに比べて画像全体の数パーセントの圧縮効率の低下を招くだけでしょう。


PNG files store 16 bit pixels in network byte order (big-endian, ie. most significant bits first).  This code would be used if they are supplied the other way (little-endian, i.e. least significant bits first, the way PCs store them):

    if (bit_depth > 8)
       png_set_swap(png_ptr);

If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you need to change the order the pixels are packed into bytes, you can use:

    if (bit_depth < 8)
       png_set_packswap(png_ptr);

PNG files store 3 color pixels in red, green, blue order.  This code would be used if they are supplied as blue, green, red:

    png_set_bgr(png_ptr);

PNG files describe monochrome as black being zero and white being one. This code would be used if the pixels are supplied with this reversed (black being one and white being zero):

    png_set_invert_mono(png_ptr);

Finally, you can write your own transformation function if none of the existing ones meets your needs.  This is done by setting a callback with

    png_set_write_user_transform_fn(png_ptr,
       write_transform_fn);

You must supply the function

    void write_transform_fn(png_ptr ptr, row_info_ptr
       row_info, png_bytep data)

See pngtest.c for a working example.  Your function will be called before any of the other transformations are processed.

You can also set up a pointer to a user structure for use by your callback function.

    png_set_user_transform_info(png_ptr, user_ptr, 0, 0);

The user_channels and user_depth parameters of this function are ignored when writing; you can set them to zero as shown.

You can retrieve the pointer via the function png_get_user_transform_ptr().
For example:

    voidp write_user_transform_ptr =
       png_get_user_transform_ptr(png_ptr);

It is possible to have libpng flush any pending output, either manually, or automatically after a certain number of lines have been written.  To flush the output stream a single time call:

    png_write_flush(png_ptr);

and to have libpng flush the output stream periodically after a certain number of scanlines have been written, call:

    png_set_flush(png_ptr, nrows);

Note that the distance between rows is from the last time png_write_flush() was called, or the first row of the image if it has never been called. So if you write 50 lines, and then png_set_flush 25, it will flush the output on the next scanline, and every 25 lines thereafter, unless png_write_flush() is called before 25 more lines have been written. If nrows is too small (less than about 10 lines for a 640 pixel wide RGB image) the image compression may decrease noticeably (although this may be acceptable for real-time applications).  Infrequent flushing will only degrade the compression performance by a few percent over images that do not use flushing.


画像データの書込み

こちらは変換用についてです。ええ、画像データを書込みます。これの一番シンプルな方法ではひとつ関数を呼ぶだけで済みます。メモリ上に画像が全部あれ ば、まさにpng_write_image() を呼び出すだけでlibpng が画像データを書き込みます。各行のポインタの配列を渡して下さい。関数が自動的にインタレース処理を行うので、 png_set_interlace_handling() やこの関数を複数回呼んだりする必要はありませんし、png_write_rows() を使った何か他に必要な作業もありません。

    png_write_image(png_ptr, row_pointers);

row_pointers の引数部分は:

    png_byte *row_pointers[height];

void ポインタか charポインタ、またはユーザ指定のピクセルポインタです。

いっぺんに画像全部は書き込まないのであれば、代わりに png_write_rows() を使って下さい。ファイルをインタレースしないなら、もう単純に:

    png_write_rows(png_ptr, row_pointers,
       number_of_rows);

row_pointers は png_write_image() 関数と同じです。

1回1行ずつ書込んで行くなら、row_pointer の配列ではなく row_pointer 1個だけでも処理できます:

    png_bytep row_pointer = row;

    png_write_row(png_ptr, row_pointer);

ファイルをインタレース化するなら、処理はより複雑になるのでうまいこと対応して下さい。現在のところ(1999.6月現在、PNG仕様書バージョン 1.2のように)、PNGファイルに定義されたインタレース・スキームは、画像を7つの小さな画像に分解する"Adam7"インタレーススキームだけで す。libpng にこれらの組み立てをさせるか、自分でそれを行うことになります。自分でこれらの組み立てを行うなら、ピクセル書込みに関する詳細はPNG仕様書を見て下 さい。


Writing the image data

That's it for the transformations.  Now you can write the image data. The simplest way to do this is in one function call.  If you have the whole image in memory, you can just call png_write_image() and libpng will write the image.  You will need to pass in an array of pointers to each row.  This function automatically handles interlacing, so you don't need to call png_set_interlace_handling() or call this function multiple times, or any of that other stuff necessary with png_write_rows().

    png_write_image(png_ptr, row_pointers);

where row_pointers is:

    png_byte *row_pointers[height];

You can point to void or char or whatever you use for pixels.

If you don't want to write the whole image at once, you can use png_write_rows() instead.  If the file is not interlaced, this is simple:

    png_write_rows(png_ptr, row_pointers,
       number_of_rows);

row_pointers is the same as in the png_write_image() call.

If you are just writing one row at a time, you can do this with a single row_pointer instead of an array of row_pointers:

    png_bytep row_pointer = row;

    png_write_row(png_ptr, row_pointer);

When the file is interlaced, things can get a good deal more complicated.  The only currently (as of the PNG Specification version 1.2, dated July 1999) defined interlacing scheme for PNG files is the "Adam7" interlace scheme, that breaks down an image into seven smaller images of varying size.  libpng will build these images for you, or you can do them yourself.  If you want to build them yourself, see the PNG specification for details of which pixels to write when.


インタレースの細かい処理をやりたくないなら、7つの小画像を書き込むために正確な回数分、png_set_interlace_handling() を使って png_write_rows() を呼んでください。

libpng に小画像の組み立てをさせたいなら行の書込みを始める前にこちらを呼んでください:

    number_of_passes =
       png_set_interlace_handling(png_ptr);

必要なパス数が返ります。現在のところ7ですが将来違うインタレース・タイプが加えられ変更されるかもしれません。

そして、画像はnumber_of_passes 回で完全に書き込まれます。

    png_write_rows(png_ptr, row_pointers,
       number_of_rows);

行が一部使われなかったり、すぐ関数が返ってきてしまったりするときは、PNG仕様書にあるインタレース関連の記述を読みたくなるかもしれませんが、実際 に使える行だけは更新してください。


If you don't want libpng to handle the interlacing details, just use png_set_interlace_handling() and call png_write_rows() the correct number of times to write all seven sub-images.

If you want libpng to build the sub-images, call this before you start writing any rows:

    number_of_passes =
       png_set_interlace_handling(png_ptr);

This will return the number of passes needed.  Currently, this is seven, but may change if another interlace type is added.

Then write the complete image number_of_passes times.

    png_write_rows(png_ptr, row_pointers,
       number_of_rows);

As some of these rows are not used, and thus return immediately, you may want to read about interlacing in the PNG specification, and only update the rows that are actually used.


シーケンシャル書込みの終了

画像の書込みが終わったら、ファイルの書込み終了処理を行います。コメントや時間の追加書込みに興味があれば、適切に情報を満たしたpng_info ポインタを渡して下さい。興味がなければNULLで構いません。

    png_write_end(png_ptr, info_ptr);

これが終わったら、以下のようにlibpng で使ったメモリを全て解放します:

    png_destroy_write_struct(&png_ptr, &info_ptr);

下記関数で、libpng が確保したメモリ・ポインタであるinfo_ptr メンバを個別に解放することも可能です:

    png_free_data(png_ptr, info_ptr, mask, seq)
    mask  - 解放するデータの識別マスク
              PNG_FREE_PLTE, PNG_FREE_TRNS,
              PNG_FREE_HIST, PNG_FREE_ICCP,
              PNG_FREE_PCAL, PNG_FREE_ROWS,
              PNG_FREE_SCAL, PNG_FREE_SPLT,
              PNG_FREE_TEXT, PNG_FREE_UNKN,
              のうちひとつ以上論理OR演算で組み合わせるか
              または単純に PNG_FREE_ALL
    seq   - 解放されるアイテムのシーケンス番号
            (-1 なら全アイテム)

この関数は関連メモリが既に解放済みであっても、まだメモリ確保されていなくても、libpng でなくユーザによってメモリ確保されていたのだとしても、安全に呼ばれるはずで、また仮にそういった場合にはなにも処理はされません。選択されたデータタ イプの項目が、例えばPLTEのように一つだけでそれが可能なら、"seq" 引数は無視されます。"seq"が-1でないなら、例えば text や sPLT といった複数のアイテムがマスクに指定されたデータ・タイプとして認識されます。また構造体にある第n アイテムだけ解放するときは"seq"に n を入れて下さい。

Finishing a sequential write

After you are finished writing the image, you should finish writing the file.  If you are interested in writing comments or time, you should pass an appropriately filled png_info pointer.  If you are not interested, you can pass NULL.

    png_write_end(png_ptr, info_ptr);

When you are done, you can free all memory used by libpng like this:

    png_destroy_write_struct(&png_ptr, &info_ptr);

It is also possible to individually free the info_ptr members that point to libpng-allocated storage with the following function:

    png_free_data(png_ptr, info_ptr, mask, seq)
    mask  - identifies data to be freed, a mask
            containing the logical OR of one or
            more of
              PNG_FREE_PLTE, PNG_FREE_TRNS,
              PNG_FREE_HIST, PNG_FREE_ICCP,
              PNG_FREE_PCAL, PNG_FREE_ROWS,
              PNG_FREE_SCAL, PNG_FREE_SPLT,
              PNG_FREE_TEXT, PNG_FREE_UNKN,
            or simply PNG_FREE_ALL
    seq   - sequence number of item to be freed
            (-1 for all items)

This function may be safely called when the relevant storage has already been freed, or has not yet been allocated, or was allocated by the user  and not by libpng,  and will in those cases do nothing.  The "seq" parameter is ignored if only one item of the selected data type, such as PLTE, is allowed.  If "seq" is not -1, and multiple items are allowed for the data type identified in the mask, such as text or sPLT, only the n'th item in the structure is freed, where n is "seq".


libpng にpng_set_*で渡すパレットのようなデータ・メモリを確保するのなら、png_destroy_write_struct()が呼ばれるその前 に、メモリを解放してはいけません。

デフォルトの動作ではlibpng 内部で確保されたメモリを解放するだけです。これは変更可能で、libpng がデータを解放しないようにも、ユーザがpng_malloc() や png_zalloc() で確保したメモリ確保してpng_set_*() 関数経由で渡したデータまで解放するようにもできます。次のようにします。

    png_data_freer(png_ptr, info_ptr, freer, mask)
    mask   - png_free_data()と同じように
                データ要素を選択
    freer  - PNG_DESTROY_WILL_FREE_DATA
               PNG_SET_WILL_FREE_DATA
               PNG_USER_WILL_FREE_DATA
               のうちひとつ

例えば、一部のデータの解放義務を、読込構造体から書込み構造体に移譲するには、次の関数が使えます。

    png_data_freer(read_ptr, read_info_ptr,
       PNG_USER_WILL_FREE_DATA,
       PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)
    png_data_freer(write_ptr, write_info_ptr,
       PNG_DESTROY_WILL_FREE_DATA,
       PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)

これにより簡単に、解放義務をユーザに再移譲できますが、後ですぐにまたwrite_destroy にもう一回再移譲されます。この処理で、安全に読込構造体が破棄され、書込み構造体にある PLTE、tRNS、hIST データは使い続けられます。

この関数は既にメモリ確保済みのデータにのみ影響します。ユーザだろうと png_destroy_*() であろうとデータを解放する関数を制御する png_set_*() 関数の呼び出し前後に、この関数を呼ぶことができます。ユーザにlibpng がメモリ確保したデータの解放義務があるとすると、アプリケーションは解放にpng_free() を使わなければなりません。ユーザが自分でメモリ確保したデータのメモリ解放義務をlibpng に移譲するのなら、ユーザはメモリ確保時に png_malloc() か png_zalloc() を使わなければなりません。

text_ptr.text、text_ptr.lang、text_ptr.translated_keyword のメモリを別々に確保すると、text_ptr のメモリ解放義務は libpng に移譲されません。なぜなら、libpng がpng_text 構造体をセットするとき、key メンバとこれらのメンバを結合され、そして png_free_data() はtext_ptr.keyだけ解放します。同様に、text_ptr のメモリ解放義務をlibpng から 自分のアプリケーションに移譲するとき、アプリケーションは別々にこれらのメンバを解放してはいけません。PNGの画像の書込みのもっとコンパクトな例に ついては、example.c ファイルを見て下さい。


If you allocated data such as a palette that you passed in to libpng with png_set_*, you must not free it until just before the call to png_destroy_write_struct().

The default behavior is only to free data that was allocated internally by libpng.  This can be changed, so that libpng will not free the data, or so that it will free data that was allocated by the user with png_malloc() or png_zalloc() and passed in via a png_set_*() function, with

    png_data_freer(png_ptr, info_ptr, freer, mask)
    mask   - which data elements are affected
             same choices as in png_free_data()
    freer  - one of
               PNG_DESTROY_WILL_FREE_DATA
               PNG_SET_WILL_FREE_DATA
               PNG_USER_WILL_FREE_DATA

For example, to transfer responsibility for some data from a read structure to a write structure, you could use

    png_data_freer(read_ptr, read_info_ptr,
       PNG_USER_WILL_FREE_DATA,
       PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)
    png_data_freer(write_ptr, write_info_ptr,
       PNG_DESTROY_WILL_FREE_DATA,
       PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)

thereby briefly reassigning responsibility for freeing to the user but immediately afterwards reassigning it once more to the write_destroy function.  Having done this, it would then be safe to destroy the read structure and continue to use the PLTE, tRNS, and hIST data in the write structure.

This function only affects data that has already been allocated. You can call this function before calling after the png_set_*() functions to control whether the user or png_destroy_*() is supposed to free the data. When the user assumes responsibility for libpng-allocated data, the application must use png_free() to free it, and when the user transfers responsibility to libpng for data that the user has allocated, the user must have used png_malloc() or png_zalloc() to allocate it.

If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword separately, do not transfer responsibility for freeing text_ptr to libpng, because when libpng fills a png_text structure it combines these members with the key member, and png_free_data() will free only text_ptr.key.  Similarly, if you transfer responsibility for free'ing text_ptr from libpng to your application, your application must not separately free those members. For a more compact example of writing a PNG image, see the file example.c.


V. libpng の変更/カスタマイズ:


V. Modifying/Customizing libpng:


ここに3つ論題があります。
1つ目はメモリ確保、入出力、エラー処理といった標準の動作の処理方法の変更です。
2つ目は新しく加えられたチャンク、新しく加えられた変換、libpng の処理方法の変更といったもう少し複雑な動作を扱います。両者ともコンパイル時間を発行します; そう、一般的にコードが書かれた時間に決定され、ユーザがそれらを変更する必要性は滅多にありません。
3つ目はランタイムの発行です: それの調整や、コンピュータ意義的ルーチンのさらなるバージョン変更とのその相互間の選択; 具体的に言えば、アセンブリ言語(ひいてはコンパイラ及びプラットフォーム開発)の最適化バージョン。


There are three issues here.
The first is changing how libpng does standard things like memory allocation, input/output, and error handling.
The second deals with more complicated things like adding new chunks, adding new transformations, and generally changing how libpng works. Both of those are compile-time issues; that is, they are generally determined at the time the code is written, and there is rarely a need to provide the user with a means of changing them. 
The third is a run-time issue:  choosing between and/or tuning one or more alternate versions of computationally intensive routines; specifically, optimized assembly-language (and therefore compiler- and platform-dependent) versions.


メモリ操作、入出力、エラー処理

libpng にあるメモリ操作、入出力、エラー処理を全てユーザ設定のコールバックにできます。デフォルト・ルーチンはそれぞれ pngmem.c、pngrio.c、 pngwio.c、 pngerror.c にあります。これらの関数を変更するには、それぞれに適当なpng_set_*_fn() 関数を呼んで下さい。

メモリ確保解放はpng_malloc() と png_free() 関数を通して処理されます。これらは、現行では標準C関数そのものが呼ばれます。もしポインタが一度に64K以上アクセスできなければ、zlib.h にMAXSEG_64Kをセットして下さい。プラットフォーム上でメモリ操作を行う命令がアプリケーション間で変更されることはあまりないと思われるの で、これらの関数はコンパイル時に変更されなければなりません。好んでメモリ確保と解放に異なる命令を使うなら、上記のように登録済みの自前の関数 png_create_read_struct_2() や png_create_write_struct_2() を使うことができます。
これらの関数は次の関数で取得することができるvoid ポインタも提供します。

    mem_ptr=png_get_mem_ptr(png_ptr);

メモリ関数の交換は下記のようにプロトタイプを持たなければなりません:

    png_voidp malloc_fn(png_structp png_ptr,
       png_size_t size);
    void free_fn(png_structp png_ptr, png_voidp ptr);

自前のmalloc_fn() 関数は失敗したらNULLを返さなければなりません。png_malloc() 関数は、システム・メモリ・アロケータやユーザのmalloc_fn() 関数からNULLを取得したら通常png_error() を呼びます。


Memory allocation, input/output, and error handling

All of the memory allocation, input/output, and error handling in libpng goes through callbacks that are user-settable.  The default routines are in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively.  To change these functions, call the appropriate png_set_*_fn() function.

Memory allocation is done through the functions png_malloc() and png_free().  These currently just call the standard C functions.  If your pointers can't access more then 64K at a time, you will want to set MAXSEG_64K in zlib.h.  Since it is unlikely that the method of handling memory allocation on a platform will change between applications, these functions must be modified in the library at compile time.  If you prefer to use a different method of allocating and freeing data, you can use png_create_read_struct_2() or png_create_write_struct_2() to register your own functions as described above.
These functions also provide a void pointer that can be retrieved via

    mem_ptr=png_get_mem_ptr(png_ptr);

Your replacement memory functions must have prototypes as follows:

    png_voidp malloc_fn(png_structp png_ptr,
       png_size_t size);
    void free_fn(png_structp png_ptr, png_voidp ptr);

Your malloc_fn() must return NULL in case of failure.  The png_malloc() function will normally call png_error() if it receives a NULL from the system memory allocator or from your replacement malloc_fn().


libpng にある入出力はpng_read() や png_write() を通して処理されます。現行では fread() や fwrite() を呼ぶだけです。FILE * は png_struct 内部に記憶され、png_init_io() を経由して初期化されます。I/O 命令を変更したいなら、png_init_io() を呼ぶ代わりに実行時にpng_set_read_fn() と png_set_write_fn() 関数を通してライブラリ指定のコールバックを設定することができます。これらの関数は、png_get_io_ptr()を経由して取得できる void ポインタもまた供給します。例えば:

    png_set_read_fn(png_structp read_ptr,
        voidp read_io_ptr, png_rw_ptr read_data_fn)

    png_set_write_fn(png_structp write_ptr,
        voidp write_io_ptr, png_rw_ptr write_data_fn,
        png_flush_ptr output_flush_fn);

    voidp read_io_ptr = png_get_io_ptr(read_ptr);
    voidp write_io_ptr = png_get_io_ptr(write_ptr);

交換されたは I/O 関数は下記のようにプロトタイプを持たなければなりません:

    void user_read_data(png_structp png_ptr,
        png_bytep data, png_size_t length);
    void user_write_data(png_structp png_ptr,
        png_bytep data, png_size_t length);
    void user_flush_data(png_structp png_ptr);

読み込み、書き込み、フラッシュ関数がデフォルトのC関数を使うように設定が戻されれば、NULLが返ります。それは、読込ストリームに、書込みストリー ムからの、エラーです。逆もまた然りです。


Input/Output in libpng is done through png_read() and png_write(), which currently just call fread() and fwrite().  The FILE * is stored in png_struct and is initialized via png_init_io().  If you wish to change the method of I/O, the library supplies callbacks that you can set through the function png_set_read_fn() and png_set_write_fn() at run time, instead of calling the png_init_io() function.  These functions also provide a void pointer that can be retrieved via the function png_get_io_ptr().  For example:

    png_set_read_fn(png_structp read_ptr,
        voidp read_io_ptr, png_rw_ptr read_data_fn)

    png_set_write_fn(png_structp write_ptr,
        voidp write_io_ptr, png_rw_ptr write_data_fn,
        png_flush_ptr output_flush_fn);

    voidp read_io_ptr = png_get_io_ptr(read_ptr);
    voidp write_io_ptr = png_get_io_ptr(write_ptr);

The replacement I/O functions must have prototypes as follows:

    void user_read_data(png_structp png_ptr,
        png_bytep data, png_size_t length);
    void user_write_data(png_structp png_ptr,
        png_bytep data, png_size_t length);
    void user_flush_data(png_structp png_ptr);

Supplying NULL for the read, write, or flush functions sets them back to using the default C stream functions.  It is an error to read from a write stream, and vice versa.


libpng のエラー処理はpng_error() と png_warning() を通して行われます。png_error() を通して処理されるエラーは致命的エラーで、png_error() は呼び出し側に決して返されないことを意味します。現在のところ、これは setjmp() と longjmp() を経由して処理され( PNG_ABORT() を経由して処理されるときのPNG_SETJMP_NOT_SUPPORTED でlibpng をコンパイルしない限り)ますが、exit() のような動作を変更したいのなら、変更して構いません。

全く致命的エラーが無い状態でも、警告メッセージを表示する png_warning() は呼ばれ、呼び出し中のコードから制御が返ります。ライブラリが PNG_NO_CONSOLE_IO定義(メッセージを非表示にする)や、PNG_NO_STDIO定義(fprintf() が使えない状態)でコンパイルされない限り、デフォルトではfprintf() を経由してstderr 上にpng_error() と png_warning() がメッセージを表示します。エラー関数の動作を変えようと思えば、自前のメッセージ・コールバックをセットアップすることになります。これらの関数は通常 ではpng_struct が生成された時間を設定します。次の呼び出しでpng_create_*_struct() が呼ばれた後にエラー出や警告出力を交換用の自前関数にリダイレクトすることもまたできます:

    png_set_error_fn(png_structp png_ptr,
        png_voidp error_ptr, png_error_ptr error_fn,
        png_error_ptr warning_fn);

    png_voidp error_ptr = png_get_error_ptr(png_ptr);

error_fn や warning_fn にNULLをセットすれば、不具合に遭遇したときはlibpng のデフォルト関数が使われ、fprintf() か longjmp() またはその両方を呼びます。交換するエラー関数の引数は、下記のようにして下さい:

    void user_error_fn(png_structp png_ptr,
        png_const_charp error_msg);
    void user_warning_fn(png_structp png_ptr,
        png_const_charp warning_msg);

setjmp() や longjmp() を使うことに対する隠された動機は C++ が例外を処理するのに throw と catch を使うためです。関数を呼ぶ度にコードチェックする必要が無く、これはコーディングをとても簡単にしてくれます。しかし、longjmp 後のローカル変数の状態が一部はっきりしないので、setjmp 自身を返した上に非ゼロが返った後はユーザは慎重に行いたいかもしれません。さらなる詳細については自分もコンパイラの文書を調べて下さい。アプローチの 変更については、
"cexcept"機能(http://cexcept.sourceforge.net を見て下さい)を使って頂いて構いません。


Error handling in libpng is done through png_error() and png_warning(). Errors handled through png_error() are fatal, meaning that png_error() should never return to its caller.  Currently, this is handled via setjmp() and longjmp() (unless you have compiled libpng with PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), but you could change this to do things like exit() if you should wish.

On non-fatal errors, png_warning() is called to print a warning message, and then control returns to the calling code. By default png_error() and png_warning() print a message on stderr via fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined (because you don't want the messages) or PNG_NO_STDIO defined (because fprintf() isn't available).  If you wish to change the behavior of the error functions, you will need to set up your own message callbacks.  These functions are normally supplied at the time that the png_struct is created. It is also possible to redirect errors and warnings to your own replacement functions after png_create_*_struct() has been called by calling:

    png_set_error_fn(png_structp png_ptr,
        png_voidp error_ptr, png_error_ptr error_fn,
        png_error_ptr warning_fn);

    png_voidp error_ptr = png_get_error_ptr(png_ptr);

If NULL is supplied for either error_fn or warning_fn, then the libpng default function will be used, calling fprintf() and/or longjmp() if a problem is encountered.  The replacement error functions should have parameters as follows:

    void user_error_fn(png_structp png_ptr,
        png_const_charp error_msg);
    void user_warning_fn(png_structp png_ptr,
        png_const_charp warning_msg);

The motivation behind using setjmp() and longjmp() is the C++ throw and catch exception handling methods.  This makes the code much easier to write, as there is no need to check every return code of every function call. However, there are some uncertainties about the status of local variables after a longjmp, so the user may want to be careful about doing anything after setjmp returns non-zero besides returning itself.  Consult your compiler documentation for more details.  For an alternative approach, you may wish to use the "cexcept" facility (see http://cexcept.sourceforge.net).

●用語解説
"cexcept"機能 ・・・<C例外機能>
C++ で使っているthrow や try といった例外処理の機能をCで実装しようというもの。
2005.7 現在、日本でこれを解説してるサイトは無い様なので、興味のある方はhttp://cexcept.sourceforge.net(英 語)をお読み下さい。

カスタム・チャンク

カスタム・チャンクの読み込み・書込みを行うなら、libpng コードの深層部まで理解しなければならないかもしれません。ライブラリは不定タイプ・チャンクの記憶用書込み用メカニズムを持ちます; カスタム・チャンク用ののコールバックが宣言できます。しかし、ユーザのチャンクと”libpng に内在する” チャンクの相互関係についてライブラリ・コード自身に知らせたいなら、これではあまり十分ではないかもしれません。

新規の内在チャンクを書き込みたいなら、とにかくPNG仕様書を見て下さい。そしてそれがどのように動いているのか第一段階の理解レベルまで到達してくだ さい。チャンク名について記述された項を特別によく注意し、他のチャンクが如何に設計されたか、自分で同じようにできるようによく見て下さい。第2に、 libpng のチャンクの読込み・書込みの項をよく調べてください。自分のチャンクに似ていてテンプレートのように使えるチャンクを見つけて下さい。詳細はコード内部 のコメントに書いてあります。libpng 関数を変更することなく、一般的な命令で、コールバックを経由し不定チャンクを処理できればベストです。

自前の変換方法でデータを書き込みたいなら、変換を行うコード部分によく目を通し、簡単なものでいいので、それらがどういう考え方で動いているのかよく考 えて下さい。自分が追加したい変換と同じようなのを見つけてそこからコピーして下さい。詳細はそれ自身のコード内部のコメントに書いてあります。


Custom chunks

If you need to read or write custom chunks, you may need to get deeper into the libpng code.  The library now has mechanisms for storing and writing chunks of unknown type; you can even declare callbacks for custom chunks.  Hoewver, this may not be good enough if the library code itself needs to know about interactions between your chunk and existing `intrinsic' chunks.

If you need to write a new intrinsic chunk, first read the PNG specification. Acquire a first level of understanding of how it works.  Pay particular attention to the sections that describe chunk names, and look at how other chunks were designed, so you can do things similarly.  Second, check out the sections of libpng that read and write chunks.  Try to find a chunk that is similar to yours and use it as a template.  More details can be found in the comments inside the code.  It is best to handle unknown chunks in a generic method, via callback functions, instead of by modifying libpng functions.

If you wish to write your own transformation for the data, look through the part of the code that does the transformations, and check out some of the simpler ones to get an idea of how they work.  Try to find a similar transformation to the one you want to add and copy off of it.  More details can be found in the comments inside the code itself.


16ビット・プラットフォームの設定

一度に64K以上メモリ確保できない時の zlib(ひいてはlibpng)に関してはzconf.hを見て下さい。たとえメモリ確保できても、アクセス不能だと思います。MAXSEG_64K定 義することで、zlib 及び libpng に64K 制限を設けることができます。

DOS の設定

640K より小さいアクセスしかできないDOS ユーザは、png_set_compression_mem_level() 関数を経由してzlib のメモリ使用制限を設けて下さい。詳細情報はzlib ライブラリのzlib.h や zconf.h を見て下さい。

ミディアムモデルの設定

libpng は一番一般的なコンパイラでテストされたミディアム・モデルをサポートします。MAXSEG_64K 定義があるか、USE_FAR_KEYWORD 定義があるか、pngconf.h にある far へのFAR 定義があるか確かめて、すべてセットして下さい。ライブラリ内では全部(zlib 構造体は除いて)、far データになっています。ポインタの後ろにp やpp を付けた(または少なくとも、よく見て確認された)、typedef を使わなければなりません。
unsigned char far* far* である行データ がきちんと png_bytepp のように定義されてるかよく確認して下さい。


Configuring for 16 bit platforms

You will want to look into zconf.h to tell zlib (and thus libpng) that it cannot allocate more then 64K at a time.  Even if you can, the memory won't be accessible.  So limit zlib and libpng to 64K by defining MAXSEG_64K.

Configuring for DOS

For DOS users who only have access to the lower 640K, you will have to limit zlib's memory usage via a png_set_compression_mem_level() call.  See zlib.h or zconf.h in the zlib library for more information.

Configuring for Medium Model

Libpng's support for medium model has been tested on most of the popular compilers.  Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets defined, and FAR gets defined to far in pngconf.h, and you should be all set.  Everything in the library (except for zlib's structure) is expecting far data.  You must use the typedefs with the p or pp on the end for pointers (or at least look at them and be careful). 
Make note that the rows of data are defined as png_bytepp, which is an
unsigned char far * far *.

●用語解説
ミディアムモデル:medium model
Intel 80x86シリーズでのプログラミングで使うメモリモデルのひとつ。1Mバイト(far)のコードと、64Kバイト(near)のデータで構成されるも の。

GUIウィンドウ プラットフォームの設定:

前にも書いたように、GUI インタフェースで使う新しいエラー及び警告の関数を書き込む必要があります。そして、png_create_*_struct() 関数が呼ばれたとき構造体を初期化するのに使えるようなエラー関数や警告関数となるものをセットして下さい。あとでpng_set_error_fn() を使って変更することもできます。一部のコンパイラにおいてはメモリ操作関数 (png_mallocなど)も変更できるかもしれません。

コンパイラ xxx の設定:


libpng の include は全て pngconf.h にあります。もし include を追加/変更/削除 したいなら、行いたい場所に行って下さい。libpng 外部で必要とされない include は、そういったlibpng 自身の内部ルーチン用の定義である PNG_INTERNAL 定義で保護して下さい。libpng のファイルは pngconf.hファイルをincludeしている png.h ファイルだけをinclude すれば大丈夫です。


Configuring for gui/windowing platforms:

You will need to write new error and warning functions that use the GUI interface, as described previously, and set them to be the error and warning functions at the time that png_create_*_struct() is called, in order to have them available during the structure initialization. They can be changed later via png_set_error_fn().  On some compilers, you may also have to change the memory allocators (png_malloc, etc.).

Configuring for compiler xxx:

All includes for libpng are in pngconf.h.  If you need to add/change/delete an include, this is the place to do it.  The includes that are not needed outside libpng are protected by the PNG_INTERNAL definition, which is only defined for those routines inside libpng itself.  The files in libpng proper only include png.h, which includes pngconf.h.


zlib の設定:

圧縮を設定する特殊な関数です。多分一番役立つのが圧縮レベルの変更で、現行では圧縮値の入力には0〜9 範囲が使えます。ライブラリは通常デフォルト圧縮レベル(Z_DEFAULT_COMPRESSION = 6)を使います。大半の画像でテストしましたが、圧縮値3〜6の範囲なら高レベルなものと結構同じくらいに、それでいて高速に圧縮されます。オンライン・ アプリケーションは最高速度(Z_BEST_SPEED = 1)で行うのがいいかもしれません。zlib バージョン 0.99 以降のものでは無圧縮(Z_NO_COMPRESSION = 0)も指定できますが、生ビットマップよりファイルサイズは大きくなります。圧縮レベルは次の関数で設定できます:

    png_set_compression_level(png_ptr, level);

またもうひとつ便利なのがライブラリで使うメモリレベルを減らすことができることです。メモリレベルはデフォルトでは8ですが、メモリが足らない(例え ば、640Kしか扱えない DOS実行時など)ようなら低くして下さい。メモリレベルは圧縮に影響してしまうこともあるので注意して下さい; 他の事でも共通ですが、低いレベルは小さいメモリブロックで生じた圧縮できないデータ部分ができてしまい、これに相応して、最悪15%の比較的大きいオー バーヘッドが生じます。

    png_set_compression_mem_level(png_ptr, level);

他の関数はzlib の設定用です。PNGファイルにおいて書込みが無効になる可能性があるため通常の使用には推奨されません。こういった関連の詳細は zlib.h を見て下さい。

    png_set_compression_strategy(png_ptr,
        strategy);
    png_set_compression_window_bits(png_ptr,
        window_bits);
    png_set_compression_method(png_ptr, method);
    png_set_compression_buffer_size(png_ptr, size);

Configuring zlib:

There are special functions to configure the compression.  Perhaps the most useful one changes the compression level, which currently uses input compression values in the range 0 - 9.  The library normally uses the default compression level (Z_DEFAULT_COMPRESSION = 6).  Tests have shown that for a large majority of images, compression values in the range 3-6 compress nearly as well as higher levels, and do so much faster.  For online applications it may be desirable to have maximum speed (Z_BEST_SPEED = 1).  With versions of zlib after v0.99, you can also specify no compression (Z_NO_COMPRESSION = 0), but this would create files larger than just storing the raw bitmap.  You can specify the compression level by calling:

    png_set_compression_level(png_ptr, level);

Another useful one is to reduce the memory level used by the library. The memory level defaults to 8, but it can be lowered if you are short on memory (running DOS, for example, where you only have 640K). Note that the memory level does have an effect on compression; among other things, lower levels will result in sections of incompressible data being emitted in smaller stored blocks, with a correspondingly larger relative overhead of up to 15% in the worst case.

    png_set_compression_mem_level(png_ptr, level);

The other functions are for configuring zlib.  They are not recommended for normal use and may result in writing an invalid PNG file.  See zlib.h for more information on what these mean.

    png_set_compression_strategy(png_ptr,
        strategy);
    png_set_compression_window_bits(png_ptr,
        window_bits);
    png_set_compression_method(png_ptr, method);
    png_set_compression_buffer_size(png_ptr, size);


行フィルタの制御

libpng がフィルタを使うか使わないか? 使われるフィルタは? どのように行フィルタを取り出していくか? ということに関わらず制御を行うのであれば、これらの関数のうちひとつを呼ぶことができます。行フィルタの選択と設定は画像サイズとエンコード速度と大き く関わりますし、デコード速度への影響もわずかですがあります。デフォルトではRGB及びグレースケール画像(アルファ有り及び無し)へのフィルタが可能 ですが、パレット画像や 8 ビット/ピクセルより少ない画像はできません。

PNG 1.2 仕様書では現在 "0"である method 引数は主なフィルタ命令をセットします。"filters"引数はフィルタ(複数可)をセットし、使うなら、各スキャンラインにて使って下さい。可能な値 はフィルタのオン・オフを行うそれぞれ、PNG_ALL_FILTERS と PNG_NO_FILTERS です。

PNG_FILTER_NONE、PNG_FILTER_SUB、PNG_FILTER_UP、 PNG_FILTER_AVG、PNG_FILTER_PAETH は個別のフィルタで、使うフィルタをひとつ以上、”|” を使ったOR 演算でビット単位で指定できます。フィルタについての詳細はPNG仕様書を見て下さい。画像の書込みが進行している間ずっとフィルタ・タイプを変えるつも りなら、自分が使う全フィルタがセットしてあるフラグでスタートして下さい。そうすればlibpng がその内部構造体を全フィルタ・タイプで適切に初期化します。(最初の行は常に適切にフィルタリングされてなければならないということになるので注意して 下さい。なぜならlibpng は現在、png_write_row() が最初に一回呼ばれるまで、フィルタバッファのメモリ確保を行わないからです。)
    filters = PNG_FILTER_NONE | PNG_FILTER_SUB
              PNG_FILTER_UP | PNG_FILTER_AVE |
              PNG_FILTER_PAETH | PNG_ALL_FILTERS;

    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE,
       filters);

第2引数は、MNG データストリーム組込み用にPNGを書き込むなら PNG_INTRAPIXEL_DIFFERENCING でも構いません。この引数は png_set_IHDR() で使う filter_method の値と同じでなければなりません。


Controlling row filtering

If you want to control whether libpng uses filtering or not, which filters are used, and how it goes about picking row filters, you can call one of these functions.  The selection and configuration of row filters can have a significant impact on the size and encoding speed and a somewhat lesser impact on the decoding speed of an image.  Filtering is enabled by default for RGB and grayscale images (with and without alpha), but not for paletted images nor for any images with bit depths less than 8 bits/pixel.

The 'method' parameter sets the main filtering method, which is currently only '0' in the PNG 1.2 specification.  The 'filters' parameter sets which filter(s), if any, should be used for each scanline.  Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS to turn filtering on and off, respectively.

Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise ORed together with '|' to specify one or more filters to use. These filters are described in more detail in the PNG specification. If you intend to change the filter type during the course of writing the image, you should start with flags set for all of the filters you intend to use so that libpng can initialize its internal structures appropriately for all of the filter types.  (Note that this means the first row must always be adaptively filtered, because libpng currently does not allocate the filter buffers until png_write_row() is called for the first time.)

    filters = PNG_FILTER_NONE | PNG_FILTER_SUB
              PNG_FILTER_UP | PNG_FILTER_AVE |
              PNG_FILTER_PAETH | PNG_ALL_FILTERS;

    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE,
       filters);

The second parameter can also be PNG_INTRAPIXEL_DIFFERENCING if you are writing a PNG to be embedded in a MNG datastream. This parameter must be the same as the value of filter_method used in png_set_IHDR().


利用可能なフィルタの中から、libpng に選ばせて作用させることもできます。以下では2つの方法のうち1つまたは両方の処理を行っています…連続した行に同じフィルタを使うことがどれくらい重 要であるかということを使う方法と、相対的なフィルタの計算コストを考える方法。

    double weights[3] = {1.5, 1.3, 1.1},
       costs[PNG_FILTER_VALUE_LAST] =
       {1.0, 1.3, 1.3, 1.5, 1.7};

    png_set_filter_heuristics(png_ptr,
       PNG_FILTER_HEURISTIC_WEIGHTED, 3,
       weights, costs);

他の行が何回も前の行よりいいフィルタを使うということでもない限り、連続した行に対して同じ行フィルタを使うことをlibpng に示す乗算要素がweightsにあります。上記の例では、前の3フィルタがSUB, SUB, NONE なら、SUB フィルタは他のフィルタより”絶対値の差の合計”1.5 x 1.3倍高くそして選択中のままになり、NONE フィルタは他のフィルタより1.1 倍高い合計でまだ選択中のままになります。指定されないweightsは 1.0 になりますが、指定されたweightsはおそらく衰退していきます。上記のように古きフィルタを越えた新しいフィルタに重点が置かれるようになったため です。

フィルタ・コストはフィルタを選択したときによく考えて相対的なデコード・コストで各フィルタ・タイプを指定します。これは”絶対値の差の合計”が相当少 なくないと、高コストのフィルタは低いコストのフィルタを選びそうもないということです。最終画像サイズに極端に影響を与えるので、costs は必ずしも各種フィルタの実際の計算速度を反映するわけではありません。

上記の例での数値は適当に考えたもので、関数の使用方法を説明しやすくするためだけに使いました。テストは小さなもので、costs や weights の最適値を検知するだけにとどまりました。


It is also possible to influence how libpng chooses from among the available filters.  This is done in one or both of two ways - by telling it how important it is to keep the same filter for successive rows, and by telling it the relative computational costs of the filters.

    double weights[3] = {1.5, 1.3, 1.1},
       costs[PNG_FILTER_VALUE_LAST] =
       {1.0, 1.3, 1.3, 1.5, 1.7};

    png_set_filter_heuristics(png_ptr,
       PNG_FILTER_HEURISTIC_WEIGHTED, 3,
       weights, costs);

The weights are multiplying factors that indicate to libpng that the row filter should be the same for successive rows unless another row filter is that many times better than the previous filter.  In the above example, if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a "sum of absolute differences" 1.5 x 1.3 times higher than other filters and still be chosen, while the NONE filter could have a sum 1.1 times higher than other filters and still be chosen.  Unspecified weights are taken to be 1.0, and the specified weights should probably be declining like those above in order to emphasize recent filters over older filters.

The filter costs specify for each filter type a relative decoding cost to be considered when selecting row filters.  This means that filters with higher costs are less likely to be chosen over filters with lower costs, unless their "sum of absolute differences" is that much smaller. The costs do not necessarily reflect the exact computational speeds of the various filters, since this would unduly influence the final image size.

Note that the numbers above were invented purely for this example and are given only to help explain the function usage.  Little testing has been done to find optimum values for either the costs or the weights.


使わないオブジェクトコードの削除

libpng パーツのコンパイルを制御する #define の束がpngconf.h にあります。その定義群は全て_SUPPORTED の文字で終わります。もし絶対使わない機能があれば、libpng を再コンパイルする前に #define を #undef に変更でき、コードとデータ・スペースの節約になります。またそれぞれを各機能別にオフにしたいなら、PNG_NO_ で始まる定義を使って下さい。

PNG_NO_READ[or WRITE]_TRANSFORMS, または
PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS または
4こ全部 をコンパイラに指示して変換や補助チャンク機能も全てひとまとめにオフにしたり、また自分の付けたい機能をオンにしたりすることができます。 PNG_NO_READ[or WRITE]_TRANSFORMS が指示されれば、特殊な変換を無効にしますが、PNGファイルの読込み・書込みを完全に行う機能は全ての既定公式チャンクに託されます。 PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS の使用は読込み・書込み付属チャンクを無効にしたライブラリを生成します。プログレッシブ読込み機能を使用しないなら、 PNG_NO_PROGRESSIVE_READ でオフにして下さい(INTERLACING 機能と混同しないで下さい、まだあります)。


Removing unwanted object code

There are a bunch of #define's in pngconf.h that control what parts of libpng are compiled.  All the defines end in _SUPPORTED.  If you are never going to use a capability, you can change the #define to #undef before recompiling libpng and save yourself code and data space, or you can turn off individual capabilities with defines that begin with PNG_NO_.

You can also turn all of the transforms and ancillary chunk capabilities off en masse with compiler directives that define PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, or all four, along with directives to turn on any of the capabilities that you do want.  The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable the extra transformations but still leave the library fully capable of reading and writing PNG files with all known public chunks Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive produces a library that is incapable of reading or writing ancillary chunks. If you are not using the progressive reading capability, you can turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse this with the INTERLACING capability, which you'll still have).


全ての読込み・書込み指定コードは各ファイルに分かれているので、リンカは必要に応じてファイルをグラブするだけです。しかし、確認したり、スタンド・ア ローンでライブラリをビルドしたりするとき、全てのファイル読込みはpngr でスタートし、全てのファイル書込みはpngw でスタートします。どちらにもマッチしないファイル(lpng.c、pngtrans.c などのように) は読込み・書込み両方に使われ、常にインクルードされます。プログレッシブ読込みはpngpread.c にあります。

ダイナミック・リンク・ライブラリ(.so や DLL ファイル)の生成や配布を行うのなら、ライブラリを部分的に無効にしたり削除したりしないで下さい。なぜならアプリケーションが異なるバージョンのライブ ラリにリンクしたとき、そのライブラリで利用不可能な関数呼び出しを行ったとき失敗するので。ライブラリ自身のサイズは発行されません。なぜならこの項は 実際に使われるメモリへのロードだからです。


All the reading and writing specific code are in separate files, so the linker should only grab the files it needs.  However, if you want to make sure, or if you are building a stand alone library, all the reading files start with pngr and all the writing files start with pngw.  The files that don't match either (like png.c, pngtrans.c, etc.) are used for both reading and writing, and always need to be included. The progressive reader is in pngpread.c

If you are creating or distributing a dynamically linked library (a .so or DLL file), you should not remove or disable any parts of the library, as this will cause applications linked with different versions of the library to fail if they call functions not available in your library. The size of the library itself should not be an issue, because only those sections that are actually used will be loaded into memory.


デバッグ情報の出力要求

PNG_DEBUG マクロ定義はデバッグ情報の出力要求に使われます。整数値で 0〜3の間でセットして下さい。数値が高いほどデバッグ情報量は増えます。PNG_DEBUG_FILE マクロ定義を違うファイル名に変えないかぎり、情報は"stderr"ファイルに出力されます。

PNG_DEBUG > 0 のとき、下記の関数(マクロ)が利用可能になります:

   png_debug(level, message)
   png_debug1(level, message, p1)
   png_debug2(level, message, p1, p2)

level はメッセージを出力するかどうかを決めるため PNG_DEBUG と値を比較されます。message は出力の文字列フォーマットです。p1 及び p2 は printf() スタイルでの指定フォーマットで文字列に組み込まれる引数です。例えば、

   png_debug1(2, "foo=%d\n", foo);

は次より拡張されたものです。

   if(PNG_DEBUG > 2)
     fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo);

PNG_DEBUG が定義されていてもゼロなら、マクロは定義されませんが、自分自身のデバッグ制御に使うことはできます:

   #ifdef PNG_DEBUG
       fprintf(stderr, ...
   #endif

PNG_DEBUG = 1 なら、マクロは定義されますが、png_debug() 関数のメッセージだけは、level = 0 での出力になります。当該libpng のバージョンではこのようなメッセージはありませんが、出力するなら自分で挿入することになります。


Requesting debug printout

The macro definition PNG_DEBUG can be used to request debugging printout.  Set it to an integer value in the range 0 to 3.  Higher numbers result in increasing amounts of debugging information.  The information is printed to the "stderr" file, unless another file name is specified in the PNG_DEBUG_FILE macro definition.

When PNG_DEBUG > 0, the following functions (macros) become available:

   png_debug(level, message)
   png_debug1(level, message, p1)
   png_debug2(level, message, p1, p2)

in which "level" is compared to PNG_DEBUG to decide whether to print the message, "message" is the formatted string to be printed, and p1 and p2 are parameters that are to be embedded in the string according to printf-style formatting directives.  For example,

   png_debug1(2, "foo=%d\n", foo);

is expanded to

   if(PNG_DEBUG > 2)
     fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo);

When PNG_DEBUG is defined but is zero, the macros aren't defined, but you can still use PNG_DEBUG to control your own debugging:

   #ifdef PNG_DEBUG
       fprintf(stderr, ...
   #endif

When PNG_DEBUG = 1, the macros are defined, but only png_debug statements having level = 0 will be printed.  There aren't any such statements in this version of libpng, but if you insert some they will be printed.


VI.  ランタイム最適化


VI.  Runtime optimization


libpng 1.2.0 での新しい特徴に、一部ルーチンの標準・最適化バージョン間の動的な切り替え機能があります。目下のところ、PNGファイル読込み時の計算量の多いタスク 3つに制限されます: 行フィルタのデコード、拡張インタレース、前の行データを使うインタレース結合または行データ透過。現行の最適化バージョンは、MMX サポートを伴う x86(Intel, AMD, etc.) プラットフォームでだけ利用可能ですが、これについては将来のバージョンで変更されるかもしれません。(たとえば、将来のリリースにおいて zlib 用 非MMX アセンブラの最適化では同様にランタイム選択が可能になり、この場合 libpng はそういったものをサポートするため拡張が可能です。またもうひとつの方法として、ガンマ補正用の浮動小数点 対 整数ルーチンのコンパイル時選択でもランタイム選択が可能になります。)

なぜなら、このような最適化は、極めてプラットフォーム及びコンパイラ依存型になりがちで、2つはどのように書き込まれるか、及びどんなプラットフォーム かということです。クエリへのプログラム、有効、無効、指定最適化かこのような全最適化か、という新ランタイム・コードがlibpng に書かれています。たとえば、全ての可能な最適化を使うには(たまに一部の”最適化”が実際かなりゆっくり動作することに配慮しながら):

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       png_uint_32 mask, flags;

       flags = png_get_asm_flags(png_ptr);
       mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
       png_set_asm_flags(png_ptr, flags | mask);
    #endif


A new feature in libpng 1.2.0 is the ability to dynamically switch between standard and optimized versions of some routines.  Currently these are limited to three computationally intensive tasks when reading PNG files: decoding row filters, expanding interlacing, and combining interlaced or transparent row data with previous row data.  Currently the optimized versions are available only for x86 (Intel, AMD, etc.) platforms with MMX support, though this may change in future versions.  (For example, the non-MMX assembler optimizations for zlib might become similarly runtime-selectable in future releases, in which case libpng could be extended to support them.  Alternatively, the compile-time choice of floating-point versus integer routines for gamma correction might become runtime-selectable.)

Because such optimizations tend to be very platform- and compiler-dependent, both in how they are written and in how they perform, the new runtime code in libpng has been written to allow programs to query, enable, and disable either specific optimizations or all such optimizations.  For example, to enable all possible optimizations (bearing in mind that some "optimizations" may actually run more slowly in rare cases):

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       png_uint_32 mask, flags;

       flags = png_get_asm_flags(png_ptr);
       mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
       png_set_asm_flags(png_ptr, flags | mask);
    #endif


png_get_asm_flagmask() を呼ぶとき、PNGなどの読み込みに関連した最適化だけをできるようにするには、PNG_SELECT_READ を使います; 書込みだけの場合も同様です。全最適化の無効化:

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       flags = png_get_asm_flags(png_ptr);
       mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
       png_set_asm_flags(png_ptr, flags & ~mask);
    #endif

MMX関連の特性だけを有効化・無効化するには、png_get_asm_flagmask() の位置に png_get_mmx_flagmask() を使います。mmx バージョンは追加引数がひとつあります:

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       int selection = PNG_SELECT_READ | PNG_SELECT_WRITE;
       int compilerID;

       mask = png_get_mmx_flagmask(selection, &compilerID);
    #endif

関数が返ると、compilerID にはコンパイルされた MMX アセンブラ最適化バージョンが示されます。現在、2種類あります: Microsoft Visual C++ (compilerID == 1) と GNU C (a.k.a. gcc/gas, compilerID == 2) です。非x86 プラットフォームや MMX 最適化なしでコンパイルされたシステムでは -1 の値になります。


To enable only optimizations relevant to reading PNGs, use PNG_SELECT_READ by itself when calling png_get_asm_flagmask(); similarly for optimizing only writing.  To disable all optimizations:

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       flags = png_get_asm_flags(png_ptr);
       mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
       png_set_asm_flags(png_ptr, flags & ~mask);
    #endif

To enable or disable only MMX-related features, use png_get_mmx_flagmask() in place of png_get_asm_flagmask().  The mmx version takes one additional parameter:

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       int selection = PNG_SELECT_READ | PNG_SELECT_WRITE;
       int compilerID;

       mask = png_get_mmx_flagmask(selection, &compilerID);
    #endif

On return, compilerID will indicate which version of the MMX assembler optimizations was compiled.  Currently two flavors exist:  Microsoft Visual C++ (compilerID == 1) and GNU C (a.k.a. gcc/gas, compilerID == 2).
On non-x86 platforms or on systems compiled without MMX optimizations, a value of -1 is used.


ng_get_asm_flagmask() と png_get_mmx_flagmask() は両方とも全て有効値となる、その今使ってるライブラリ・バージョンで設定可能な最適化ビットを返します。共有(ダイナミック・リンク)ライブラリの場 合、コードが書かれたりコンパイルされた時点で存在しない最適化がインクルードされるかもしれません。それも可能ですが、もちろん、知らせるだけというの も可能で、最適化を指定してみると; 例えば:

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       flags = PNG_ASM_FLAG_MMX_READ_COMBINE_ROW  \
             | PNG_ASM_FLAG_MMX_READ_INTERLACE    \
             | PNG_ASM_FLAG_MMX_READ_FILTER_SUB   \
             | PNG_ASM_FLAG_MMX_READ_FILTER_UP    \
             | PNG_ASM_FLAG_MMX_READ_FILTER_AVG   \
             | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
       png_set_asm_flags(png_ptr, flags);
    #endif

この命令ではlibpng 1.2.0リリースの時点で利用可能なMMX 読込み最適化だけを、あとで新しくでるDLL バージョンで実際使われるかどうかにかかわらず、使えるようにします。(また、こういった関数は1.2.0 より過去のバージョンには存在しませんので、ダイナミック・リンク・アプリケーションを実行するつもりならこのような過去のバージョンでは失敗しますので 注意して下さい。)


Note that both png_get_asm_flagmask() and png_get_mmx_flagmask() return all valid, settable optimization bits for the version of the library that's currently in use.  In the case of shared (dynamically linked) libraries, this may include optimizations that did not exist at the time the code was written and compiled.  It is also possible, of course, to enable only known, specific optimizations; for example:

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       flags = PNG_ASM_FLAG_MMX_READ_COMBINE_ROW  \
             | PNG_ASM_FLAG_MMX_READ_INTERLACE    \
             | PNG_ASM_FLAG_MMX_READ_FILTER_SUB   \
             | PNG_ASM_FLAG_MMX_READ_FILTER_UP    \
             | PNG_ASM_FLAG_MMX_READ_FILTER_AVG   \
             | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
       png_set_asm_flags(png_ptr, flags);
    #endif

This method would enable only the MMX read-optimizations available at the time of libpng 1.2.0's release, regardless of whether a later version of the DLL were actually being used.  (Also note that these functions did not exist in versions older than 1.2.0, so any attempt to run a dynamically linked app on such an older version would fail.)


プロセッサが MMX 命令を全てサポートするかどうか決定するのに、png_mmx_support() 関数を使います:

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       mmxsupport = png_mmx_support();
    #endif

返り値が-1 ならMMX サポートはlibpng にコンパイルされません。0 ならMMX コードはコンパイルはされますがMMX はプロセッサにサポートされません。1 ならMMX サポートが完全に利用可能です。png_mmx_support()、 png_get_mmx_flagmask()、png_get_asm_flagmask() は全てPNG構造体のメモリ確保及び初期化されずに呼ばれるかもしれないので注意して下さい(例えば、使用中のスクリーンとかの一部や "情報"ボタンなどのように)。

下記コードは libpng が PNG_THREAD_UNSAFE_OK が定義されてビルドされているのに、アプリケーションが非スレッド・セーフで動作するのを防止します:

#if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) \
  && defined(PNG_THREAD_UNSAFE_OK)
    /* Disable thread-unsafe features of pnggccrd */
    if (png_access_version() >= 10200)
    {
      png_uint_32 mmx_disable_mask = 0;
      png_uint_32 asm_flags;

      mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW  \
                          | PNG_ASM_FLAG_MMX_READ_FILTER_SUB   \
                          | PNG_ASM_FLAG_MMX_READ_FILTER_AVG   \
                          | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
      asm_flags = png_get_asm_flags(png_ptr);
      png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask);
    }
#endif

最適化の有効・無効、ランタイム・クエリのさらに多くの例については、libpng 配布ソース・コードの contrib/gregbook/readpng2.c を見て下さい。


To determine whether the processor supports MMX instructions at all, use the png_mmx_support() function:

    #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
       mmxsupport = png_mmx_support();
    #endif

It returns -1 if MMX support is not compiled into libpng, 0 if MMX code is compiled but MMX is not supported by the processor, or 1 if MMX support is fully available.  Note that png_mmx_support(), png_get_mmx_flagmask(), and png_get_asm_flagmask() all may be called without allocating and initializing any PNG structures (for example, as part of a usage screen or "about" box).

The following code can be used to prevent an application from using the thread_unsafe features, even if libpng was built with PNG_THREAD_UNSAFE_OK defined:

#if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) \
  && defined(PNG_THREAD_UNSAFE_OK)
    /* Disable thread-unsafe features of pnggccrd */
    if (png_access_version() >= 10200)
    {
      png_uint_32 mmx_disable_mask = 0;
      png_uint_32 asm_flags;

      mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW  \
                          | PNG_ASM_FLAG_MMX_READ_FILTER_SUB   \
                          | PNG_ASM_FLAG_MMX_READ_FILTER_AVG   \
                          | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
      asm_flags = png_get_asm_flags(png_ptr);
      png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask);
    }
#endif

For more extensive examples of runtime querying, enabling and disabling of optimized features, see contrib/gregbook/readpng2.c in the libpng source-code distribution.


VII.  MNG サポート


VII.  MNG support


MNG 仕様書(http://www.libpng.org/pub/mng で入手可能) ではMNG データ・ストリームに組み込むためのPNG画像用に特別にPNGを拡張しています。
libpng はこういった拡張をサポートします。これを可能にするのが、png_permit_mng_features() 関数です:

   feature_set = png_permit_mng_features(png_ptr, mask)
   mask は png_uint_32 です。論理OR演算で
        次の値を使って可能にしたい特性をつけます
        PNG_FLAG_MNG_EMPTY_PLTE
        PNG_FLAG_MNG_FILTER_64
        PNG_ALL_MNG_FEATURES
   feature_set は png_uint_32 です。自分が使っているlibpng の
        バージョンでサポートされるMNG 特性のセットで
        論理AND演算でのマスクです。

スタンドアローンPNGファイルでPNG 8バイト・シグネチャの読込み・書込み時のこの関数で使われるエラーです。PNG データ・ストリームはMNG データ・ストリームにラップされなければなりません。最低でも、MNG 8バイト・シグネチャと MHDR と MEND チャンクを持たなければなりません。libpng はMNG チャンクをどれもこれもサポートしません; アプリケーションは自身でそれをサポートして下さい。libmng (http://www.libmng.com で入手可能) の使用も視野にいれて検討して下さい。


The MNG specification (available at http://www.libpng.org/pub/mng) allows certain extensions to PNG for PNG images that are embedded in MNG datastreams.
Libpng can support some of these extensions.  To enable them, use the png_permit_mng_features() function:

   feature_set = png_permit_mng_features(png_ptr, mask)
   mask is a png_uint_32 containing the logical OR of the
        features you want to enable.  These include
        PNG_FLAG_MNG_EMPTY_PLTE
        PNG_FLAG_MNG_FILTER_64
        PNG_ALL_MNG_FEATURES
   feature_set is a png_uint_32 that is the logical AND of
      your mask with the set of MNG features that is
      supported by the version of libpng that you are using.

It is an error to use this function when reading or writing a standalone PNG file with the PNG 8-byte signature.  The PNG datastream must be wrapped in a MNG datastream.  As a minimum, it must have the MNG 8-byte signature and the MHDR and MEND chunks.  Libpng does not provide support for these or any other MNG chunks; your application must provide its own support for them.  You may wish to consider using libmng (available at http://www.libmng.com) instead.


VIII.  libpng のバージョン 0.88からの変更


VIII.  Changes to Libpng from version 0.88


0.96 より後のlibpng バージョンはlibpng のオリジナルの作者の Guy Schalnat からも Andreas Dilger からも配布されておらず、むしろ Guy から引き継いだ他のオリジナルのPNGグループ・メンバ、Glenn Randers-Pehrson から 1996、1997にかけて、0.89 〜 0.96 のバージョンが配布されましたので注意して下さい。Guy と Andreas はまだ現役ですが、その役目は他者へと移行しました。

旧libpng 関数 png_read_init(), png_write_init(), png_info_init(), png_read_destroy(), png_write_destroy() はもう使えないようにするためバージョン0.95でPNG_INTERNAL へ移行しました。これらの関数はlibpng バージョン 2.0.0 からは削除される予定です。

libpng 構造体の生成と初期化の優先命令は、png_create_read_struct(), png_create_write_struct(), png_create_info_struct() を経由するものです。なぜなら、これらの関数は旧関数が処理しない、アプリケーションからの構造体のサイズを分割、バージョン・エラー・チェック、また初 期化時のカスタム・エラー処理ルーチンを使用したりします。関数 png_read_destroy() と png_write_destroy() はlibpng が確保した構造体のメモリを実際は解放しませんが、構造体をリセットだけはしますので、システム・オーバーヘッドの各画像読込みの png_struct のメモリ確保及び解放を過剰だなと感じるなら png_destroy_read_struct() と png_destroy_write_struct() の代わりに使うことができます。


It should be noted that versions of libpng later than 0.96 are not distributed by the original libpng author, Guy Schalnat, nor by Andreas Dilger, who had taken over from Guy during 1996 and 1997, and distributed versions 0.89 through 0.96, but rather by another member of the original PNG Group, Glenn Randers-Pehrson.  Guy and Andreas are still alive and well, but they have moved on to other things.

The old libpng functions png_read_init(), png_write_init(), png_info_init(), png_read_destroy(), and png_write_destroy() have been moved to PNG_INTERNAL in version 0.95 to discourage their use.  These functions will be removed from libpng version 2.0.0.

The preferred method of creating and initializing the libpng structures is via the png_create_read_struct(), png_create_write_struct(), and png_create_info_struct() because they isolate the size of the structures from the application, allow version error checking, and also allow the use of custom error handling routines during the initialization, which the old functions do not.  The functions png_read_destroy() and png_write_destroy() do not actually free the memory that libpng allocated for these structs, but just reset the data structures, so they can be used instead of png_destroy_read_struct() and png_destroy_write_struct() if you feel there is too much system overhead allocating and freeing the png_struct for each image read.


libpng-0.88 で推奨されていたたもはやサポートされない png_read_init() の前に png_set_message_fn() を使ってエラー・コールバックを設定して下さい。なぜなら、png_ptr がゼロに初期化されてなくてカスタム・エラー関数が失敗し使えないアプリケーションになるからです。
それでも png_read_init() の「後」や、png_set_error_fn() で変更したりすることで、本質的に同じ関数である、エラー・コールバックを設定することができます。しかし旧命令を使おうとしたアプリケーションはコンパ イル・エラーに強制的に新しい名前を付けさせられます。

バージョン 1.0.7でスタ−トした、ランタイムで使うライブラリ・バージョンがあります:

   png_uint_32 libpng_vn = png_access_version_number();

libpng_vn という数値はメジャー・バージョン、マイナー・バージョンの十の位のゼロをつけたもので構成されます。リリース・ナンバーも十の位のゼロをつけます(例: libpng_vn バージョンが 1.0.7 なら 10007)。

アプリケーションをコンパイルするとき使っている png.h のバージョンをチェックできます:

   png_uint_32 application_vn = PNG_LIBPNG_VER;


Setting the error callbacks via png_set_message_fn() before png_read_init() as was suggested in libpng-0.88 is no longer supported because this caused applications that do not use custom error functions to fail if the png_ptr was not initialized to zero.
It is still possible to set the error callbacks AFTER png_read_init(), or to change them with png_set_error_fn(), which is essentially the same function, but with a new name to force compilation errors with applications that try to use the old method.

Starting with version 1.0.7, you can find out which version of the library you are using at run-time:

   png_uint_32 libpng_vn = png_access_version_number();

The number libpng_vn is constructed from the major version, minor version with leading zero, and release number with leading zero, (e.g., libpng_vn for version 1.0.7 is 10007).

You can also check which version of png.h you used when compiling your application:

   png_uint_32 application_vn = PNG_LIBPNG_VER;

IX. libpng のY2K準拠 (2000年問題対応)


IX. Y2K Compliance in libpng


2004/12/3

PNG開発グループはその場その場の組織ですので、私たちは公式な宣言というものができません。

これは libpng バージョン 0.71 を含め 1.2.8 までは Y2K に対応しているという非公式な保証です。私はそれ以前のバージョンもまた Y2K に対応していたと信じています。

libpng には3つだけ"年"領域がありました。ひとつは"年"を2バイト符号なし整数の上限65535に上げることです。残り2つは文字列フォーマットの日付の維 持と、"年"の上限を9999に上げることです。

整数は
    png_time_struct の "png_uint_16 year"

文字列は
    png.c 中のローカル・キャラクタ文字列
png_struct の "png_charp time_buffer" と
"near_time_buffer"

7個の時間関連関数:



png.c: png_convert_to_rfc_1123() … png.c にあります。
  (エラー時 png_convert_to_rfc_1152() 以前)
png_convert_from_struct_tm() … pngwrite.c にあり、 pngwrite.c 内で呼ばれます。
png_convert_from_time_t() … pngwrite.cにあります。
png_get_tIME() … pngget.c にあります。
png_handle_tIME() … pngrutil.c にあり、pngread.c 内で呼ばれます。
png_set_tIME() …pngset.c にあります。
png_write_tIME() …pngwutil.cにあり、pngwrite.c 内で呼ばれます。



December 3, 2004

Since the PNG Development group is an ad-hoc body, we can't make an official declaration.

This is your unofficial assurance that libpng from version 0.71 and upward through 1.2.8 are Y2K compliant.  It is my belief that earlier versions were also Y2K compliant.

Libpng only has three year fields.  One is a 2-byte unsigned integer that will hold years up to 65535.  The other two hold the date in text format, and will hold years up to 9999.

The integer is
    "png_uint_16 year" in png_time_struct.

The strings are
    "png_charp time_buffer" in png_struct and
    "near_time_buffer", which is a local character string in png.c.

There are seven time-related functions:



png_convert_to_rfc_1123() in png.c
(formerly png_convert_to_rfc_1152() in error)
png_convert_from_struct_tm() in pngwrite.c, called
in pngwrite.c
png_convert_from_time_t() in pngwrite.c
png_get_tIME() in pngget.c
png_handle_tIME() in pngrutil.c, called in pngread.c
png_set_tIME() in pngset.c
png_write_tIME() in pngwutil.c, called in pngwrite.c


Y2K 環境でも全てハンドルは正確に時を刻みます。
png_convert_from_time_t() 関数はシステム時間を変換するために (year - 1900) を返す gmtime() を呼び、正確な4桁の年数に変換します。アプリケーションが、png_convert_to_rfc_1123() 関数に4桁の年数を渡さな い libpng を使っている可能性もありえますし、またpng_convert_from_struct_tm() 関数に "year - 1900"の代わりに2桁の年数を渡した場合も不正確に成ります。 これは私たちの制御下にないためです。
libpng 文書はいつも4桁年の状態で作業を行うようにしていましたし、API もそのように文書化されていました。

tIME チャンク自身もまた Y2K に対応しています。"年"を2バイト符号なし整数を使っており、65535 までの年を保持できます。.

libpng が依存していますzlibですが、それもまた Y2K に対応しています。なぜなら日付関連のコードがないので。


All appear to handle dates properly in a Y2K environment.  The png_convert_from_time_t() function calls gmtime() to convert from system clock time, which returns (year - 1900), which we properly convert to the full 4-digit year.  There is a possibility that applications using libpng are not passing 4-digit years into the png_convert_to_rfc_1123() function, or that they are incorrectly passing only a 2-digit year instead of "year - 1900" into the png_convert_from_struct_tm() function, but this is not under our control.  The libpng documentation has always stated that it works with 4-digit years, and the APIs have been documented as such.

The tIME chunk itself is also Y2K compliant.  It uses a 2-byte unsigned integer to hold the year, and can hold years as large as 65535.

zlib, upon which libpng depends, is also Y2K compliant.  It contains no date-related code.


   Glenn Randers-Pehrson
   libpng 管理者
   PNG 開発グループ

   Glenn Randers-Pehrson
   libpng maintainer
   PNG Development Group


翻訳後記 ・・・上記中、専門用語にかなり苦労 しました。
we'll now walk you though〜
「オレタチはお前を歩く」?よくある漫画の『おれの屍を越えて行け』ってことか?と悩みました。
正解は walk you though でウォークスルー・モデルで開発でした。walk though の間にyouがある…。
but not
という単語が、どの文章でもどのファイル慣用句的に使われているのですが、あんまり大きな辞書にも載ってません。
A but not B で、AであってBでないという単純な訳ですが、
慣用句として扱わないと、文法的に壊れたものばかりになってしまっています。



戻る