处理栅格图像文件

我们经常被问到的一个问题是:如何在 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 数组中。

今天就开始行动

免费试用 ODA 软件 60 天。
无风险,无需信用卡。

免费试用