我们经常被问到的一个问题是:如何在 Teigha 中修改栅格图像数据?有时开发人员会因为 OdGiRasterImage API 中缺少栅格图像编辑功能而感到困惑,该 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 方法会自动检测栅格图像格式。如果栅格图像加载正确,栅格图像智能指针将为非空,我们可以使用它来访问栅格图像像素数据、格式、调色板和其他属性。
将栅格图像保存到文件
栅格服务模块也可以用于保存栅格图像。在我们的示例中,我们将使用最简单的方法,该方法根据输出文件名的扩展名自动检测栅格图像的保存格式:
bool bSaveState = pRasSvcs->saveRasterImage(pOutputImage, outputFileName);
if (!bSaveState)
throw OdError(eFileWriteError);
访问栅格图像像素
在本文中,我们将使用以下湖面波浪的栅格图像:
对于本系列文章中描述的栅格图像实验,我们需要图像四个角的像素颜色。为了访问图像像素,OdGiRasterImage 提供了两个版本的 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
}
在此示例中(如果优化的像素访问器返回非空数据指针),我们将左下、右下、左上和右上像素颜色存储在 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 数组中。