[Back to Blog](/blog) # Working with raster image files

Andrew Markovich February 02, 2017 [\#Raster image](/blog/tag/raster-image) [\#Example](/blog/tag/example)

<a class="a2a_button_facebook"></a><a class="a2a_button_twitter"></a><a class="a2a_button_linkedin"></a>

A question we’re often asked is: How do I modify raster image data in Teigha? Sometimes a developer is confused by the absence of raster image editing functions in the OdGiRasterImage API, which contains only raster image data getters. This article shows how raster images can be modified after loading.

### Loading raster images from a file

For loading raster images from a file, Teigha provides a raster services module which can be accessed at runtime using the Teigha dynamic linker:

```
<span class="hljs-title">OdRxRasterServicesPtr</span> pRasSvcs = <span class="hljs-keyword">odrxDynamicLinker</span>()-><span class="hljs-keyword">loadApp</span>(RX_RASTER_SERVICES_APPNAME, false);
if (pRasSvcs.<span class="hljs-keyword">isNull</span>()) // Check that raster services module correctly loaded
    throw <span class="hljs-keyword">OdError</span>(eNullPtr);
```

For dynamic library project configurations, the **“RxRasterServices.tx”** module must be available in the application directory. For static library project configurations, the application must link with the **“RxRasterServices”** static library, and the raster services module must be registered in the Teigha static modules map:

```
<span class="hljs-keyword">ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT</span>(ExRasterModule);
<span class="hljs-keyword">ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT</span>(OdRasterProcessingServicesImpl);

<span class="hljs-keyword">ODRX_BEGIN_STATIC_MODULE_MAP</span>()
    <span class="hljs-keyword">ODRX_DEFINE_STATIC_APPLICATION</span>(RX_RASTER_SERVICES_APPNAME,  ExRasterModule)
    <span class="hljs-keyword">ODRX_DEFINE_STATIC_APPLICATION</span>(OdRasterProcessorModuleName, OdRasterProcessingServicesImpl)
<span class="hljs-keyword">ODRX_END_STATIC_MODULE_MAP</span>()
```

In this example, we additionally registered the raster processing module since it can be required during raster image loading or saving.

If the raster services module loaded correctly, we can load a raster image from a file using a single call:

```
<span class="hljs-title">OdGiRasterImagePtr</span> pInputImage = pRasSvcs-><span class="hljs-keyword">loadRasterImage</span>(inputFileName);
if (pInputImage.<span class="hljs-keyword">isNull</span>()) // Check that raster image correctly loaded
    throw <span class="hljs-keyword">OdError</span>(eNullPtr);
```

The OdRxRasterServices::loadRasterImage method detects the raster image format automatically. If the raster image loaded correctly, the raster image smart pointer will be non-null, and we can use it to access raster image pixel data, format, palette and other properties.

### Saving raster images in a file

The raster services module can also be used for saving raster images. In our example, we will use the simplest method which detects the save format of the raster image from the output file name extension:

```
bool bSaveState = pRasSvcs-><span class="hljs-keyword">saveRasterImage</span>(pOutputImage, outputFileName);
if (!bSaveState)
    throw <span class="hljs-keyword">OdError</span>(eFileWriteError);
```

### Accessing raster image pixels

For this article, we’ll use the following raster image of waves on a lake:

[![](/files/images/blog/2017-02-02-pic1.png)](/files/images/blog/2017-02-02-pic1.png)

For the raster image experiments described in this series of articles, we require pixel colors from the four image corners. To access image pixels, OdGiRasterImage provides two versions of the scanLines method. The first (direct) scanlines access method isn’t supported by all types of raster images because not all of them contain a compatible pixel array. So first we must check that optimized scanlines access can be used for this kind of raster image:

```
<span class="hljs-title">ODCOLORREF</span> inputColors[4];
if (pInputImage-><span class="hljs-keyword">scanLines</span>())
{
    const <span class="hljs-title">OdUInt8</span> *pPixels = pInputImage-><span class="hljs-keyword">scanLines</span>();
    inputColors[0] = <span class="hljs-keyword">ODRGB</span>(pPixels[0], pPixels[1], pPixels[2]); // Bottom-left corner
    pPixels += (pInputImage-><span class="hljs-keyword">pixelWidth</span>() - 1) * 3;
    inputColors[1] = <span class="hljs-keyword">ODRGB</span>(pPixels[0], pPixels[1], pPixels[2]); // Bottom-right corner
    pPixels = pInputImage-><span class="hljs-keyword">scanLines</span>() + (pInputImage-><span class="hljs-keyword">scanLineSize</span>() * (pInputImage-><span class="hljs-keyword">pixelHeight</span>() - 1));
    inputColors[2] = <span class="hljs-keyword">ODRGB</span>(pPixels[0], pPixels[1], pPixels[2]); // Top-left corner
    pPixels += (pInputImage-><span class="hljs-keyword">pixelWidth</span>() - 1) * 3;
    inputColors[3] = <span class="hljs-keyword">ODRGB</span>(pPixels[0], pPixels[1], pPixels[2]); // Top-right corner
}
```

In this example (if the optimized pixels accessor returns a non-null data pointer), we store bottom-left, bottom-right, top-left and top-right pixel colors inside the inputColors array. Take into account that inside Teigha, raster image scanlines are stored in order from bottom to top, so the pointer returned by the scanLines method points to the bottom image scanline.

If the raster image doesn’t provide a direct scanlines accessor, we can always use another version of the scanLines method which copies the pixels array into an intermediate user-defined array. This method is supported for all types of raster images:

```
if (!pInputImage->scanLines())
{
    <span class="hljs-title">OdUInt8Array</span> scanLine;
    scanLine.<span class="hljs-keyword">resize</span>(pInputImage-><span class="hljs-keyword">scanLineSize</span>());
    pInputImage-><span class="hljs-keyword">scanLines</span>(scanLine.<span class="hljs-keyword">asArrayPtr</span>(), 0);
    inputColors[0] = <span class="hljs-keyword">ODRGB</span>(scanLine[0], scanLine[1], scanLine[2]); // Bottom-left corner
    inputColors[1] = <span class="hljs-keyword">ODRGB</span>(scanLine[(pInputImage-><span class="hljs-keyword">pixelWidth</span>() - 1) * 3 + 0], // Bottom-right corner
                     scanLine[(pInputImage-><span class="hljs-keyword">pixelWidth</span>() - 1) * 3 + 1],
                     scanLine[(pInputImage-><span class="hljs-keyword">pixelWidth</span>() - 1) * 3 + 2]);
    pInputImage-><span class="hljs-keyword">scanLines</span>(scanLine.<span class="hljs-keyword">asArrayPtr</span>(), pInputImage-><span class="hljs-keyword">pixelHeight</span>() - 1);
    inputColors[2] = <span class="hljs-keyword">ODRGB</span>(scanLine[0], scanLine[1], scanLine[2]); // Top-left corner
    inputColors[3] = <span class="hljs-keyword">ODRGB</span>(scanLine[(pInputImage-><span class="hljs-keyword">pixelWidth</span>() - 1) * 3 + 0], // Top-right corner
                     scanLine[(pInputImage-><span class="hljs-keyword">pixelWidth</span>() - 1) * 3 + 1],
                     scanLine[(pInputImage-><span class="hljs-keyword">pixelWidth</span>() - 1) * 3 + 2]);
}
```

In this example, we copy first (bottom) and last (top) scanlines into an intermediate array and copy their first and last pixel colors inside the inputColors array.

## Get started today

**Try ODA software free for 60 days.  
No risk, no credit card required.**

[Try for Free](https://www.opendesign.com/free-trial)
