よくある質問に「Teighaでラスター画像データを変更するにはどうすればよいですか?」というものがあります。開発者は、ラスター画像データゲッターのみを含むOdGiRasterImage APIにラスター画像編集機能がないことに戸惑うことがあります。この記事では、ラスター画像を読み込んだ後に変更する方法を示します。
ファイルからラスター画像を読み込む
ファイルからラスター画像を読み込むために、TeighaはTeighaダイナミックリンカーを使用して実行時にアクセスできるラスターサービスモジュールを提供します。
OdRxRasterServicesPtr pRasSvcs = odrxDynamicLinker()->loadApp(RX_RASTER_SERVICES_APPNAME, false);
if (pRasSvcs.isNull()) // Check that raster services module correctly loaded
throw OdError(eNullPtr);
ダイナミックライブラリプロジェクト構成の場合、「RxRasterServices.tx」モジュールがアプリケーションディレクトリで利用可能である必要があります。スタティックライブラリプロジェクト構成の場合、アプリケーションは「RxRasterServices」スタティックライブラリとリンクする必要があり、ラスターサービスモジュールはTeighaスタティックモジュールマップに登録されている必要があります。
ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(ExRasterModule);
ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdRasterProcessingServicesImpl);
ODRX_BEGIN_STATIC_MODULE_MAP()
ODRX_DEFINE_STATIC_APPLICATION(RX_RASTER_SERVICES_APPNAME, ExRasterModule)
ODRX_DEFINE_STATIC_APPLICATION(OdRasterProcessorModuleName, OdRasterProcessingServicesImpl)
ODRX_END_STATIC_MODULE_MAP()
この例では、ラスター画像の読み込みまたは保存中に必要となる可能性があるため、ラスター処理モジュールも登録しました。
ラスターサービスモジュールが正しく読み込まれた場合、単一の呼び出しでファイルからラスター画像を読み込むことができます。
OdGiRasterImagePtr pInputImage = pRasSvcs->loadRasterImage(inputFileName);
if (pInputImage.isNull()) // Check that raster image correctly loaded
throw OdError(eNullPtr);
OdRxRasterServices::loadRasterImageメソッドは、ラスター画像形式を自動的に検出します。ラスター画像が正しく読み込まれた場合、ラスター画像スマートポインタはnull以外になり、それを使用してラスター画像のピクセルデータ、形式、パレット、その他のプロパティにアクセスできます。
ファイルにラスター画像を保存する
ラスターサービスモジュールは、ラスター画像を保存するためにも使用できます。この例では、出力ファイル名拡張子からラスター画像の保存形式を検出する最も簡単な方法を使用します。
bool bSaveState = pRasSvcs->saveRasterImage(pOutputImage, outputFileName);
if (!bSaveState)
throw OdError(eFileWriteError);
ラスター画像ピクセルへのアクセス
この記事では、湖の波の以下のラスター画像を使用します。
このシリーズの記事で説明されているラスター画像実験では、画像の四隅からのピクセル色が必要です。画像ピクセルにアクセスするために、OdGiRasterImageはscanLinesメソッドの2つのバージョンを提供します。最初の(直接の)scanlinesアクセス方法は、すべてのラスター画像タイプでサポートされているわけではありません。なぜなら、すべてのラスター画像が互換性のあるピクセル配列を含んでいるわけではないからです。したがって、まず、この種のラスター画像に最適化されたscanlinesアクセスを使用できることを確認する必要があります。
ODCOLORREF inputColors[4];
if (pInputImage->scanLines())
{
const OdUInt8 *pPixels = pInputImage->scanLines();
inputColors[0] = ODRGB(pPixels[0], pPixels[1], pPixels[2]); // Bottom-left corner
pPixels += (pInputImage->pixelWidth() - 1) * 3;
inputColors[1] = ODRGB(pPixels[0], pPixels[1], pPixels[2]); // Bottom-right corner
pPixels = pInputImage->scanLines() + (pInputImage->scanLineSize() * (pInputImage->pixelHeight() - 1));
inputColors[2] = ODRGB(pPixels[0], pPixels[1], pPixels[2]); // Top-left corner
pPixels += (pInputImage->pixelWidth() - 1) * 3;
inputColors[3] = ODRGB(pPixels[0], pPixels[1], pPixels[2]); // Top-right corner
}
この例では(最適化されたピクセルアクセサーがnull以外のデータポインターを返す場合)、左下、右下、左上、右上のピクセルカラーをinputColors配列に格納します。Teigha内では、ラスター画像のスキャンラインは下から上への順序で格納されるため、scanLinesメソッドによって返されるポインターは、画像の下部のスキャンラインを指すことに注意してください。
ラスター画像が直接スキャンラインアクセサーを提供しない場合でも、ピクセル配列を中間ユーザー定義配列にコピーする別のバージョンのscanLinesメソッドを常に使用できます。このメソッドは、すべての種類のラスター画像でサポートされています。
if (!pInputImage->scanLines())
{
OdUInt8Array scanLine;
scanLine.resize(pInputImage->scanLineSize());
pInputImage->scanLines(scanLine.asArrayPtr(), 0);
inputColors[0] = ODRGB(scanLine[0], scanLine[1], scanLine[2]); // Bottom-left corner
inputColors[1] = ODRGB(scanLine[(pInputImage->pixelWidth() - 1) * 3 + 0], // Bottom-right corner
scanLine[(pInputImage->pixelWidth() - 1) * 3 + 1],
scanLine[(pInputImage->pixelWidth() - 1) * 3 + 2]);
pInputImage->scanLines(scanLine.asArrayPtr(), pInputImage->pixelHeight() - 1);
inputColors[2] = ODRGB(scanLine[0], scanLine[1], scanLine[2]); // Top-left corner
inputColors[3] = ODRGB(scanLine[(pInputImage->pixelWidth() - 1) * 3 + 0], // Top-right corner
scanLine[(pInputImage->pixelWidth() - 1) * 3 + 1],
scanLine[(pInputImage->pixelWidth() - 1) * 3 + 2]);
}
この例では、最初(下)と最後(上)のスキャンラインを中間配列にコピーし、それらの最初と最後のピクセルカラーをinputColors配列内にコピーします。