イメージの処理

概要

Curl®言語は、画像を扱う様々な方法を提供します。以下のリストは、利用可能なツールの概要です。:
これら全てのツールは、以下のイメージファイルフォーマットをサポートします。:

ImageData

ImageDataクラスでは、imageテキスト プロシージャや、単にURLからFillPattern または Pixmapを作成するよりも洗練されたイメージ処理を実行できます。
ImageDataでは、アニメーションGIFや、マルチページTIFFファイルのような1つ以上のイメージを含むファイルフォーマットを処理することが出来ます。imageテキストプロシージャは、この例で示しているようにアニメーションGIFを表示することが出来ます。

例: imageを使用したアニメーションGIFの表示
{let f:Frame = {Frame}}

{spaced-hbox
    valign = "top",
    {spaced-vbox
        {CommandButton
            label = "Show GIF",
            {on Action do
                {f.clear}
                {f.add
                    {image
                        source = {url "../../default/images/curl.gif"}
                    }
                }
            }
        },
        {CommandButton
            label = "Clear GIF",
            {on Action do
                {f.clear}
            }
        }
    },
    f
}
ImageDataは、ファイル内のイメージを、Pixmapオブジェクトの配列であるImageData.pixmapsに返します。この配列を使って、マルチイメージファイル内の個別のイメージにアクセスすることが出来ます。Curlが提供するツールを使用して得られたpixmapを操作することが出来ます。例えば、Renderer2d.render-pixmapを使って、pixmapをレンダリングしたり、filter-pixmapプロシージャを使ってpixmapを修正したりすることが出来ます。
以下のサンプルでは、前のサンプルで使用されていたのと同じアニメーションGIFファイルからImageDataを作成しています。pixmaps配列をループし、Fillのbackgroundにpixmapを設定しています。Fillのサイズを設定するのにpixmapのwidthとheightプロパティを使用しています。最後にfillをVBoxへ追加しています。コマンドボタンをクリックして、アニメーションGIF内のイメージを表示してください。
アニメーションGIFファイルには、ImageDataを使ってアクセスできる追加の情報があります。ImageData.delaysは、各イメージが表示される時間を記述した値の配列です。ImageData.loop-countは、一連のイメージが表示される回数を示しています。

例: ImageDataでGIFコンテンツの表示
{let id:ImageData = 
    {ImageData.from-url
        {url "../../default/images/curl.gif"}
    }
}
{let vb:VBox =
    {spaced-vbox}
}
{for p:Pixmap in id.pixmaps do
    let f:Fill =
        {Fill
            border-width = 1px,
            width = p.width * 1px,
            height= p.height * 1px,
            background = p
        }
    {vb.add f}
}
{CommandButton
    label = "Show GIF images",
    {on Action do
        {popup-message
            {VBox
                vb,
                {format "Delay = %s ", id.delays[0]},
                {format "Loop count = %s ", id.loop-count}
            }
        }
    }
}
ImageData.save-to-stream メソッドと ImageData.save-to-url メソッドでは、ImageDataByteOutputStream または Urlに書き込むことが出来ます。ImageDataのファクトリfrom-streamfrom-urlは、ストリームまたはファイル名の拡張子からcontent-typeを類推しますが、ImageDataを書き込む時は、content-typeを記述すべきです。
サポートされるイメージファイルのフォーマットとcontent-typeは以下のとおりです。:
.GIFファイルフォーマットは、書き込みをサポートしていません。
以下のサンプルは、.JPGファイルからImageDataを作成し、"blur"イメージフィルターを適用してイメージを修正し、その修正されたイメージをファイルに書き込みます。

例: ImageDataの書き込み
{import * from CURL.GRAPHICS.IMAGEFILTER}
{let id:ImageData = 
    {ImageData.from-url
        {url "../../default/images/iris-1.jpg"}
    }
}
{let blurred-pixmap:Pixmap =
    {filter-pixmap
        out=null,   
        blur,       
        id.pixmaps[0], 
        amount=30%
    }
}
{set id.pixmaps[0] = blurred-pixmap}    {VBox
    halign = "center",
    {CommandButton
        label="View image",
        width = {make-elastic},
        {on Action do
            {popup-message
                {Fill
                    width = id.pixmaps[0].width * 1px,
                    height= id.pixmaps[0].height * 1px,
                    background = id.pixmaps[0]
                }
            }
        }
    },
    {CommandButton
        label="Write image to File",
        {on Action do
            {let file-url:#Url =
                {choose-file
                    style=FileDialogStyle.save-as,
                    title="Save to file"
                }
            }
            {if-non-null file-url then
                {id.save-to-url file-url, "image/jpeg"}
            }
        }
    }
}

ImageLoader

ImageLoaderクラスでは、メモリ内にイメージ全体のインスタンスを作成することを避けることが出来ます。ImageLoader.get-imageメソッドを使って、イメージの一部分を呼び出すことが出来ます。この機能は、非常に大きなファイルや高圧縮されたファイルフォーマットで大量のメモリ使用を節約することが出来ます。ImageLoader.get-image-infoメソッドは、サブユニットイメージの最適なサイズに関する情報を返します。リリース7.0では、TIFFファイルだけが部分解凍をサポートします。
以下のサンプルは、TIFFファイルの部分解凍を行うImageLoaderの簡単な使用法を示しています。

例: 部分イメージの呼び出し
{let width:int}
{let height:int}
{let delay:Time}
{let optimal-get-width:int}
{let optimal-get-height:int}
{let il:ImageLoader = 
    {ImageLoader.from-url
        {url "../../default/images/iris-1.tif"}
    }
}
{set (width, height, delay, optimal-get-width, optimal-get-height)
    = {il.get-image-info 0}
}
{let pmap:Pixmap =
    {il.get-image
        0,
        x = 0,
        y = 400,
        width = optimal-get-width,
        height = optimal-get-height * 200
    }
}
{define-proc
    {pmap-proc ren:Renderer2d}:void
    {ren.render-pixmap
        0cm, 0cm, 154mm, 50mm,
        pmap
    }
}
{define-class RepaintFrame {inherits Frame}
  {constructor {default ...}
    {construct-super ...}
  }
  {method public {draw ren:Renderer2d}:void
    {pmap-proc ren}
  }
}
{RepaintFrame
    width = 154mm,
    height = 50mm
}

ImageGraphic

ImageGraphicでは、イメージのオリジナルサイズや、ピクセル濃度を知ることなく、Curlアプレットにイメージを簡単に追加することが出来ます。

縦横比の制御

ImageGraphic.preserve-aspect-ratio?プロパティは、ImageGraphicが元の画像の縦横比を保持するかどうかを示すブール値です。規定値は、trueで縦横比を保持します。このプロパティは、縦横の寸法の指定を可能にし、ImageGraphicは縦横比を保持しながら、境界内にイメージをレンダリングします。
以下のサンプルは、縦横比の保持を行う場合と行わない場合の違いを示しています。7cm角の四角形に、長方形のイメージをフィットさせる際に縦横比を保持する為に、ImageGraphicは、縦方向にスペースを残していることに注意してください。グラフィック内にイメージを配置する為にhalign プロパティと valignプロパティを使うことが出来ます。halign = "left"のコメントを外して、サンプルを実行してみてください。ImageGraphicが縦横比を保持しない時、定義された領域にフィットさせる為にイメージをゆがめます。

例: preserve-aspect-ratio?の使用
{spaced-hbox
    {spaced-vbox
        "preserve-aspect-ratio? = true:",
        {ImageGraphic
            {url "../../default/images/iris-1.jpg"},
||--                halign = "left",
            border-width = 1px,
            width = 4cm,
            height = 4cm
        }
    },
    {spaced-vbox
        "preserve-aspect-ratio? = false:",
        {ImageGraphic
            {url "../../default/images/iris-1.jpg"},
            preserve-aspect-ratio? = false,
            border-width = 1px,
            width = 4cm,
            height = 4cm
        }
    }
}

イメージのサイズの制御

ImageGraphicの既定の振る舞いは、1つのイメージ ピクセルを1つのスクリーン ピクセルに対応させるようにイメージをレンダリングすることです。これにより、高ピクセル濃度のイメージは、スクリーン上で非常に大きく見えます。
ImageGraphicそのもののwidth プロパティと heightプロパティを設定するか、サイズが指定されたコンテナオブジェクト内にImageGraphicを配置することにより、イメージのスクリーン上のサイズを制御することが出来ます。
以下のサンプルは、簡単なイメージビューワです。サムネイルイメージをクリックして表示してください。このサンプルではImageGraphicの幅を指定することでサムネイルイメージのサイズを制御していますが、大きなイメージのサイズは、幅が指定されたFrame内にImageGraphicを置くことで制御していることに注意してください。両方のケースで、ImageGraphicは正確な縦横比を保持しています。

例: シンプル イメージビューワ
{let strarr:StringArray =
    {StringArray
        "../../default/images/image004.jpg",
        "../../default/images/image005.jpg",
        "../../default/images/image012.jpg",
        "../../default/images/image009.jpg"
    }
}
{let thumb-width = 100px}
{let thumbs:HBox =
    {spaced-hbox}
}
{let display:Frame =
    {Frame
        border-width = 1px,
        valign = "center",
        width = 11cm,
        {ImageGraphic
            {url "../../default/images/image004.jpg"}
        }
    }
}
{for s:String in strarr do
    {thumbs.add
        {ImageGraphic
            {url s},
            border-width = 1px,
            width = thumb-width,
            opaque-to-events? = true,
            {on PointerPress do
                {display.clear}
                {display.add
                    {ImageGraphic
                        {url s}
                    }
                }
            }
        }
    }
}
{spaced-vbox
    halign = "center",
    display,
    thumbs
}
ImageGraphic.desired-resolutionプロパティでイメージのサイズを制御することも出来ます。ImageGraphicの高さと幅の設定は、イメージを表示しようとしているスクリーン領域のサイズが分かっている時は便利です。desired-resolutionは、イメージのおおよそのイメージの解像度は知っているが、サイズを計算したくないような状況で便利です。以下の二つのサンプルを吟味してください。最初のサンプルは、ImageGraphicの幅と高さを設定していますが、それぞれの写真は 異なる向きなので、それら全てを同じサイズで表示する為に、各グラフィックには余分なスペースがあります。

例: widthの設定
{let strarr:StringArray =
    {StringArray
        "../../default/images/iris-1.jpg",
        "../../default/images/iris-2.jpg",
        "../../default/images/iris-3.jpg",
        "../../default/images/iris-4.jpg"
    }
}
{let set-dimensions:HBox =
    {spaced-hbox
        border-width = 1px,
        valign = "center"
    }
}
{for s:String in strarr do
    {set-dimensions.add
        {ImageGraphic
            {url s},
            border-width = 1px,
            width = 5cm,
            height = 5cm
        }
    }
}
{spaced-vbox
    set-dimensions
}
次のサンプルでは、イメージの表示サイズを設定するためにdesired-resolutionを使用しています。これは写真は全て同じカメラで 撮影され、オリジナルの解像度は同じなので合理的なアプローチです。 イメージの周囲に余分なスペースがありません。

例: Setting the desired-resolution
{let strarr:StringArray =
    {StringArray
        "../../default/images/iris-1.jpg",
        "../../default/images/iris-2.jpg",
        "../../default/images/iris-3.jpg",
        "../../default/images/iris-4.jpg"
    }
}
{let set-resolution:HBox =
    {spaced-hbox
        border-width = 1px,
        valign = "center"
    }
}

{for s:String in strarr do
    {set-resolution.add
        {ImageGraphic
            {url s},
            border-width = 1px,
            desired-resolution = 800dpi
        }
    }
}
{spaced-vbox
    set-resolution
}

回転の調節

ImageGraphic.angleプロパティでは、90度単位で画像を回転させることが出来ます。正の角度は、時計回りにイメージを回転させます。負の角度は、反時計回りに回転させます。角度を設定することは、イメージが適した向きになっていない時に回転させるのに便利です。以下のサンプルにはImageGraphicangleを変更するコマンドボタンがあります。

例: angleを使用したイメージの回転
{let ig:ImageGraphic =
    {ImageGraphic
        {url "../../default/images/iris-rotated.jpg"}
    }
}
{let display:Frame =
    {Frame
        border-width = 1px,
        valign = "center",
        width = 15cm,
        height = 15cm,
        ig
    }
}

{spaced-vbox
    halign = "center",
    {Frame
        border-width = 1px,
        valign = "center",
        width = 10cm,
        height = 10cm,
        ig
    },
    {spaced-hbox
        {CommandButton
            label = "Rotate 90% CCW",
            {on Action do
                set ig.angle = ig.angle - 90deg
            }
        } ,
        {CommandButton
            label = "Rotate 90% CW",
            {on Action do
                set ig.angle = ig.angle + 90deg
            }
        }
    }
}

リサンプル アルゴリズム

ImageGraphic.resample-algorithmでは、元のイメージと異なるサイズで表示する時にどのようにスケーリングを実行するかを選択します。もっとも処理が速いのは、nearestlinearですが、ある種のイメージでは好ましくない結果になります。averageオプションは、多くの場合好ましい結果が得られる最も速いオプションです。以下のサンプルでは、CurlのWebサイトからのページを表示するのに各アルゴリズムを使用しています。nearestlinearの結果が好ましくないのを確認することが出来ます。

例: リサンプル アルゴリズム
{let iw:Distance = 7cm}
{let iurl:Url = {url "../../default/images/curl-page.png"}}
{CommandButton
    label = "Show resample algorithms",
    {on Action do
        let view:View = 
            {View
                font-size = 16pt,
                {HBox
                    width = 4 * iw,
                    {spaced-vbox
                        "nearest:",
                        {ImageGraphic
                            width = iw,
                            resample-algorithm = "nearest",
                            iurl
                        },
                        "linear:",
                        {ImageGraphic
                            width = iw,
                            resample-algorithm = "linear",
                            iurl
                        }
                    },
                    {spaced-vbox
                        "average:",
                        {ImageGraphic
                            width = iw,
                            resample-algorithm = "average",
                            iurl        },
                        "hermite:",
                        {ImageGraphic
                            width = iw,
                            resample-algorithm = "hermite",
                            iurl
                        }
                    },
                    {spaced-vbox
                        "bell:",
                        {ImageGraphic
                            width = iw,
                            resample-algorithm = "bell",
                            iurl
                        },
                        "b-spline:",
                        {ImageGraphic
                            width = iw,
                            resample-algorithm = "b-spline",
                            iurl
                        }
                    },
                    {spaced-vbox
                        "mitchell:",
                        {ImageGraphic
                            width = iw,
                            resample-algorithm = "mitchell",
                            iurl
                        },
                        "lanczos:",
                        {ImageGraphic
                            width = iw,
                            resample-algorithm = "lanczos",
                            iurl
                        }
                    }
                }
            }
        {view.show}
    }
}

イメージの情報の取得

ImageGraphic.get-image-infoメソッドは、イメージに関する以下の情報を返します。
次のサンプルでは、カスタムRecordGridセルを作成するデータ レコードとグリッドで提示されたサンプルを書き直しています。オリジナルでは、旗のアイコンの寸法に依存していた所、このバージョンでは、アイコンの高さと幅を決定するのにImageGraphic.get-image-infoを使用しています。全てのアイコンのサイズは同じものと仮定しています。

例: イメージからイメージサイズの取得
{let maritime-signal-flags:RecordSet =
    {evaluate
        {url "../../default/support/flag-data.scurl"}
    }
}
{let ig:ImageGraphic =
    {ImageGraphic
        {url {{maritime-signal-flags.select-one}.get "flag"}}
    }
}
{let width:int}
{let height:int}
{let delay:Time}
{let optimal-get-width:int}
{let optimal-get-height:int}

{set (width, height, delay, optimal-get-width, optimal-get-height)
    = {ig.get-image-info 0}
}
{let width-px:PixelDistance = width * 1px}

{define-class public open FlagCell
  {inherits StandardRecordGridCell}
  
  field private flag:Frame = 
      {Frame
        width = width-px
      }

  {constructor public {default}
    {construct-super}
    set self.width = width-px
    {self.add-internal self.flag}
    set self.cells-take-focus? = self.can-update?
  }
  
  {method public open {refresh-data}:void
    {super.refresh-data}
    let (data:String, valid?:bool) = {self.get-formatted-data}
    {if valid? then
        {self.flag.clear}
        {self.flag.add
            {ImageGraphic
                width = width-px,
                {url data}
            }
        }
     else
        {self.flag.clear}
    }
  }
}
{let rg:RecordGrid = 
    {RecordGrid 
        width = 14cm,
        height = 14cm,
        record-source = maritime-signal-flags,
        editable? = false,
        automatic-columns? = false,
        {RecordGridColumn
            width = 1.3cm,
            "letter"},
        {RecordGridColumn
            width = 2cm,
            "phonetic"},
        {RecordGridColumn
            width = 1.3cm,
            "colors"},
        {RecordGridColumn
            width = 1.3cm,
            "red?"},
        {RecordGridColumn
            width = 1.3cm,
            "white?"},
        {RecordGridColumn
            width = 1.3cm,
            "blue?"},
        {RecordGridColumn
            width = 1.3cm,
            "yellow?"},
        {RecordGridColumn
            width = 1.3cm,
            "black?"},
        {RecordGridColumn
            "flag",
            width = width-px, 
            column-resizable? = false,
            cell-spec = FlagCell
        }
    }
}
{value rg}

マルチイメージファイルでのImageGraphic の使用

ImageDataのように、ImageGraphicは、マルチイメージ ファイル フォーマットを処理することが出来ます。ImageGraphic.image-countプロパティは、ファイル内のイメージ数を示し、ImageGraphic.image-numberは、表示するイメージを選択します。以下のサンプルでは、TIFFファイル内のイメージを表示しています。表示されているイメージをクリックして、次を表示してください。

例: マルチイメージ TIFF ファイル
{let t:#Timer}
{let ig:ImageGraphic = 
    {ImageGraphic
        {url "../../default/images/irises.tif"},
        opaque-to-events? = true,
        {on PointerPress do
            set t.repeat = 1
        }
    }
}
{value
    let i:int = 0
    set t =
        {ig.animate
            interval = 0.1s,
            repeat = 1,
            {on TimerEvent do
                set ig.image-number = i
                {if i < ig.image-count - 1 then
                    set i = i + 1
                 else
                    set i = 0
                }
            }
        }    
    ig
}

イメージ フィルタ

IMAGEFILTER パッケージのインポート

Curl®言語は、FillPatternを処理するイメージフィルタを提供します。イメージフィルタは、CURL.GRAPHICS.IMAGEFILTERパッケージでプロシージャとして実装されています。このパッケージは自動的にインポートされません。したがって、Curl アプレットでイメージ フィルタを使用するには、ソースに次のコード行を追加して明示的にパッケージをインポートします。
{import * from CURL.GRAPHICS.IMAGEFILTER}
または、パッケージ名を含むイメージ フィルタ プロシージャのフルネームを使用します。たとえば、blur プロシージャを呼び出すには、そのパッケージを明示的にインポートしなくても、次のように呼び出すことができます。
{IMAGEFILTER.blur in-fill-pattern}

標準イメージ フィルタ引数

各イメージ フィルタ プロシージャは、ソースFillPattern (in とも呼ばれる) を引数とします。これは、フィルタを適用しようとするテクスチャまたはパターンです。
各プロシージャは、オプションで出力先 FillPattern (out とも呼ばれる) も取ります。この値はキーワード引数として変更可能である必要があります。フィルタは、この FillPattern をメモリの最適化として利用しようとします。メモリの最適化が可能かどうかは、各フィルタ特有のさまざまな要因によります。詳細は、『API リファレンス』を参照してください。

ピクスマップにおけるイメージ フィルタの適用

FillPattern ではなく、Pixmap で作業する場合は、filter-pixmap プロシージャをイメージ フィルタのラッパーとして利用できます。
イメージ フィルタと同様に、filter-pixmapは、入力としてPixmapとオプションとしての出力Pixmapを引数とします。引数の名前と順序はイメージ フィルタとは異なります。さらに、filter-pixmap がラップするイメージ フィルタの名前を与える必要があります。イメージ フィルタへの引数が filter-pixmap の残余引数として指定されます。
次の例では、Pixmap における blur イメージ フィルタの使用法 (左側) と、FillPattern における使用法 (右側) を示します。

例: Pixmap へのフィルターの適用
{import * from CURL.GRAPHICS.IMAGEFILTER}
{value
    let src-pixmap:Pixmap =
        {Pixmap.from-url {url "curl://install/docs/default/images/adria.jpg"}}
    let blurred-pixmap:Pixmap =
        {filter-pixmap
            out=null,   || out Pixmap
            blur,       || image filter name
            src-pixmap, || in Pixmap
            amount=60%} || amount to blur the image

    let src-fp:FillPattern =
        {FillPattern.from-url {url "curl://install/docs/default/images/adria.jpg"}}
    let blurred-fp:FillPattern =
        {blur
            src-fp,     || in FillPattern
            amount=60%, || amount to blur the image
            out=null}   || out FillPattern

    {HBox
        {Fill
            width = 2.5in, height = 2.5in,
            background = blurred-pixmap},
        {Fill
            width = 2.5in, height = 2.5in,
            background = blurred-fp}
    }
}

イメージ フィルタの使用法と例

以下のフィルタ名をクリックすると、『API リファレンス マニュアル』にある各イメージ フィルタの使用法の詳細および例を参照できます。以下のフィルタ名をクリックすると、『API リファレンス マニュアル』にある各イメージ フィルタの使用法の詳細および例を参照できます。