Skip to content

Instantly share code, notes, and snippets.

@MadhukarMoogala
Created January 22, 2025 15:22
Show Gist options
  • Save MadhukarMoogala/939e98dc88846634753f227d95353d26 to your computer and use it in GitHub Desktop.
Save MadhukarMoogala/939e98dc88846634753f227d95353d26 to your computer and use it in GitHub Desktop.
AutoCAD Custom Raster Image Handling : Embedding and Display Techniques
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{21E65A9C-E654-4DDA-B631-4CA512141022}</ProjectGuid>
<!--Change this SDK Path for ObjectARX and OpenCV-->
<ArxSdk>D:\ArxSdks\Arx2025</ArxSdk>
<OpenCVSdk>D:\ArxSDKs\opencv\build</OpenCVSdk>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetExt>.dbx</TargetExt>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(ArxSdk)\inc;$(ArxSdk)\inc-x64;$(ArxSdk)\utils\Atil\Inc;$(ArxSdk)\utils\Atil\Inc\format_codecs;$(ArxSdk)\utils\Atil\Inc\codec_properties;$(OpenCVSdk)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ACRXAPP;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(ArxSdk)\lib-x64;$(ArxSdk)\utils\Atil\Lib-x64;$(OpenCVSdk)\x64\vc16\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ModuleDefinitionFile>$(ArxSdk)\inc\AcRxDefault.def</ModuleDefinitionFile>
<AdditionalDependencies>ac1st25.lib;acad.lib;acapp.lib;acapp_crx.lib;AcCamera.lib;accore.lib;acdb25.lib;acdbmgd.lib;AcDbPointCloudObj.lib;AcDrawBridge.lib;AcFdEval.lib;AcFdUi.lib;acge25.lib;AcGeolocationObj.lib;acgeoment.lib;acgiapi.lib;acismobj25.lib;AcJsCoreStub_crx.lib;aclmvexport_crx.lib;acModelDocObj.lib;AcMPolygonObj.lib;AcPal.lib;AcPublish_crx.lib;AcSceneOE.lib;AcTc.lib;AcTcUi.lib;acui25.lib;AdApplicationFrame.lib;adui25.lib;aNav.lib;axdb.lib;rxapi.lib;userdata.lib;AdImaging.lib;AdIntImgServices.lib;opencv_world4100.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
#include "Windows.h"
#include "adesk.h"
#include "rxboiler.h"
#include "accmd.h"
#include "rxobject.h"
#include "dbents.h"
#include "dbmain.h"
#include "dbobjptr.h"
#include "dbapserv.h"
#include "tchar.h"
#include "rxregsvc.h"
#include "imgdef.h"
#include "imgent.h"
//opencv
#include <opencv2/opencv.hpp>
//ATIL
#include "FileWriteDescriptor.h"
#include "RowProviderInterface.h"
#include "FileSpecifier.h"
#include "DataModelAttributes.h"
#include "DataModel.h"
#include "Image.h"
#include "RgbColor.h"
#include "ImageFilter.h"
#include <JfifFormatCodec.h>
#include <PngFormatCodec.h>
#include <TiffFormatCodec.h>
#include <BmpFormatCodec.h>
#include <TiffCustomProperties.h>
#include <PngCustomProperties.h>
#include <FileReadDescriptor.h>
#include <RgbPaletteModel.h>
#include "AcTc.h"
/// <summary>
/// This project demonstrates two approaches to embedding and displaying images in AutoCAD drawings,
/// tailored to different use cases and requirements:
///
/// 1. TstRasterImageDef Class:
/// - A custom implementation of the AcDbRasterImageDef class.
/// - Provides functionality to embed an image from a specified file path into the drawing
/// using the ATIL image library.
/// - Handles image data through the Atil::Image class, with support for serialization and
/// deserialization of image data in DWG files.
/// - NOTE: This approach does not generate proxy graphics. If the parent DBX application is
/// unloaded, the embedded image will not be displayed.
///
/// 2. AcDbEntity-Based Image Display:
/// - Implements a lightweight AcDbEntity to display images using AcGiWorldDraw and
/// AcGiViewportDraw.
/// - Images are read from bitmap files using OpenCV and rendered as AcGiImageBGRA32,
/// scaled to fit the viewport.
/// - Stores the image directly in the drawing's database, generating proxy graphics to
/// ensure the image remains visible even if the parent DBX application is unloaded.
///
/// Together, these implementations highlight the flexibility of AutoCAD's API for handling
/// raster images, whether for performance-critical scenarios requiring lightweight entities
/// or for robust, persistent image embedding using ATIL. This project serves as a reference
/// for developers seeking to extend AutoCAD's capabilities with custom image-handling functionality.
///
/// NOTE: To use this project, ensure that the OpenCV and ATIL libraries are correctly linked.
/// NOTE: This project is intended for educational purposes only and may require additional testing and validation.
///
/// </summary>
/// <summary>
/// The function appends the entity to the MODEL_SPACE block table record and closes the entity as it's now part of the database.
/// </summary>
/// <param name="ent"></param>
/// <param name="objId"></param>
/// <returns>Acad::eOk</returns>
Acad::ErrorStatus postToDatabase(AcDbEntity* ent, AcDbObjectId& objId)
{
Acad::ErrorStatus es;
// Use AcDbBlockTablePointer for automatic management of AcDbBlockTable
AcDbBlockTablePointer pBlockTable(acdbHostApplicationServices()->workingDatabase(), AcDb::kForRead);
if ((es = pBlockTable.openStatus()) != Acad::eOk) {
return es;
}
// Use AcDbBlockTableRecordPointer for automatic management of AcDbBlockTableRecord
AcDbBlockTableRecordPointer pSpaceRecord(ACDB_MODEL_SPACE, acdbHostApplicationServices()->workingDatabase(), AcDb::kForWrite);
if ((es = pSpaceRecord.openStatus()) != Acad::eOk) {
return es;
}
// Append the entity to the MODEL_SPACE block table record
if ((es = pSpaceRecord->appendAcDbEntity(objId, ent)) != Acad::eOk) {
return es;
}
// Close the entity as it's now part of the database
if ((es = ent->close()) != Acad::eOk) {
return es;
}
return Acad::eOk;
}
/// <summary>
/// Utility function to read Pixel data from bitmap using OpenCV.
/// </summary>
struct ImageData {
std::unique_ptr<AcGiPixelBGRA32[]> pixelData;
Adesk::UInt32 width{ 100 };
Adesk::UInt32 height{ 200 };
size_t size() const { return static_cast<size_t>(width) * height; }
bool isInitialized() const { return pixelData != nullptr; }
void initialize(const std::string& imagePath) {
cv::Mat img = cv::imread(imagePath, cv::IMREAD_COLOR); // Read in color (BGR)
if (img.empty()) {
acutPrintf(_T("Error: Could not open or find the image!\n"));
pixelData.reset();
return;
}
// Flip the image vertically
cv::flip(img, img, 0);
width = img.cols;
height = img.rows;
pixelData = std::make_unique<AcGiPixelBGRA32[]>(size());
for (size_t i = 0; i < size(); ++i) {
int y = i / width, x = i % width;
if (y < img.rows && x < img.cols) {
cv::Vec3b color = img.at<cv::Vec3b>(y, x);
pixelData[i].setRGBA(color[2], color[1], color[0], 255); // Convert BGR to RGBA
}
}
}
};
//AcDbEntity-Based Image Display
/// <summary>
/// This class is a lightweight AcDbEntity designed to display an image within a drawing using
/// AcGiWorldDraw and AcGiViewportDraw. The image is read from a bitmap file using OpenCV and
/// rendered as an AcGiImageBGRA32, scaled to fit the viewport.
/// The image is embedded in the drawing's database, and proxy graphics are generated to ensure
/// the image remains visible even if the parent DBX application is unloaded.
/// </summary>
class ImageWorldDraw : public AcDbEntity {
public:
ACRX_DECLARE_MEMBERS(ImageWorldDraw);
ImageWorldDraw();
ImageWorldDraw(std::unique_ptr<ImageData> imageData);
~ImageWorldDraw();
virtual Adesk::Boolean subWorldDraw(AcGiWorldDraw* mode) override;
virtual void subViewportDraw(AcGiViewportDraw* mode) override;
virtual Acad::ErrorStatus dwgInFields(AcDbDwgFiler* filer) override;
virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* filer) const override;
virtual Acad::ErrorStatus subTransformBy(const AcGeMatrix3d& xform) override;
virtual void saveAs(AcGiWorldDraw* mode, AcDb::SaveType st) override;
private:
std::unique_ptr<ImageData> m_imageData;
double scaleFactor = 1.0;
};
ACRX_DXF_DEFINE_MEMBERS(
ImageWorldDraw,
AcDbEntity,
AcDb::kDHL_CURRENT,
AcDb::kMReleaseCurrent,
0,
IMAGE_WORLD_DRAW,
ImgSamp);
ImageWorldDraw::ImageWorldDraw() = default;
ImageWorldDraw::ImageWorldDraw(std::unique_ptr<ImageData> imageData)
: m_imageData(std::move(imageData)) {
}
ImageWorldDraw::~ImageWorldDraw() = default;
Adesk::Boolean ImageWorldDraw::subWorldDraw(AcGiWorldDraw* mode) {
return Adesk::kFalse;
}
void ImageWorldDraw::subViewportDraw(AcGiViewportDraw* mode)
{
if (!m_imageData || !m_imageData->isInitialized())
return;
// Get the current viewport
AcGePoint2d lower_left, upper_right;
mode->viewport().getViewportDcCorners(lower_left, upper_right);
double xsize = upper_right.x - lower_left.x;
double ysize = upper_right.y - lower_left.y;
xsize /= 10.0;
ysize /= 10.0;
scaleFactor = xsize / ysize;
std::unique_ptr<AcGiPixelBGRA32[]> scaledPixelData;
AcGiImageBGRA32* imageSource = nullptr;
if (scaleFactor != 1.0) {
Adesk::UInt32 scaledWidth = static_cast<Adesk::UInt32>(m_imageData->width * scaleFactor);
Adesk::UInt32 scaledHeight = static_cast<Adesk::UInt32>(m_imageData->height * scaleFactor);
// Ensure minimum dimensions
scaledWidth = std::max(scaledWidth, (Adesk::UInt32)1);
scaledHeight = std::max(scaledHeight, (Adesk::UInt32)1);
// Create OpenCV matrix with the correct format
cv::Mat srcMat(m_imageData->height, m_imageData->width, CV_8UC3);
// Copy pixel data to OpenCV matrix
for (size_t i = 0; i < m_imageData->size(); ++i) {
int y = i / m_imageData->width;
int x = i % m_imageData->width;
const auto& pixel = m_imageData->pixelData[i];
srcMat.at<cv::Vec3b>(y, x)[0] = pixel.blue();
srcMat.at<cv::Vec3b>(y, x)[1] = pixel.green();
srcMat.at<cv::Vec3b>(y, x)[2] = pixel.red();
}
// Resize
cv::Mat dstMat;
cv::resize(srcMat, dstMat, cv::Size(scaledWidth, scaledHeight), 0, 0, cv::INTER_LINEAR);
// Create scaled pixel data
scaledPixelData = std::make_unique<AcGiPixelBGRA32[]>(scaledWidth * scaledHeight);
// Copy back to BGRA format
for (size_t i = 0; i < static_cast<size_t>(scaledWidth) * scaledHeight; ++i) {
int y = i / scaledWidth;
int x = i % scaledWidth;
const auto& color = dstMat.at<cv::Vec3b>(y, x);
scaledPixelData[i].setRGBA(color[2], color[1], color[0], 255); // Set alpha to 255
}
imageSource = new AcGiImageBGRA32(scaledWidth, scaledHeight, scaledPixelData.get());
}
else {
imageSource = new AcGiImageBGRA32(m_imageData->width, m_imageData->height, m_imageData->pixelData.get());
}
if (imageSource) {
AcGePoint3d position(4.0, 5.0, 6.0);
AcGeVector3d u(std::abs(scaleFactor) * m_imageData->width, 0.0, 0.0);
AcGeVector3d v(0.0, std::abs(scaleFactor) * m_imageData->height, 0.0);
mode->geometry().image(*imageSource, position, u, v, AcGiGeometry::kTransparencyOff);
delete imageSource;
}
}
Acad::ErrorStatus ImageWorldDraw::dwgInFields(AcDbDwgFiler* filer) {
assertWriteEnabled();
Acad::ErrorStatus es = AcDbEntity::dwgInFields(filer);
if (es != Acad::eOk)
return es;
m_imageData = std::make_unique<ImageData>();
filer->readUInt32(&m_imageData->width);
filer->readUInt32(&m_imageData->height);
const size_t imageSize = m_imageData->size();
if (imageSize > 0) {
m_imageData->pixelData = std::make_unique<AcGiPixelBGRA32[]>(imageSize);
for (size_t i = 0; i < imageSize; ++i) {
filer->readBytes(&m_imageData->pixelData[i], sizeof(AcGiPixelBGRA32));
}
}
return filer->filerStatus();
}
Acad::ErrorStatus ImageWorldDraw::dwgOutFields(AcDbDwgFiler* filer) const {
Acad::ErrorStatus es = AcDbEntity::dwgOutFields(filer);
if (es != Acad::eOk)
return es;
filer->writeUInt32(m_imageData->width);
filer->writeUInt32(m_imageData->height);
const size_t imageSize = m_imageData->size();
if (imageSize > 0 && m_imageData->pixelData) {
for (size_t i = 0; i < imageSize; ++i) {
filer->writeBytes(&m_imageData->pixelData[i], sizeof(AcGiPixelBGRA32));
}
}
return filer->filerStatus();
}
Acad::ErrorStatus ImageWorldDraw::subTransformBy(const AcGeMatrix3d& xform) {
if (!m_imageData || !m_imageData->isInitialized())
return Acad::eOk;
scaleFactor = xform.scale();
return Acad::eOk;
}
void ImageWorldDraw::saveAs(AcGiWorldDraw* mode, AcDb::SaveType st) {
if (!m_imageData || !m_imageData->isInitialized())
return;
AcGiImageBGRA32 imageSource(m_imageData->width, m_imageData->height, m_imageData->pixelData.get());
AcGePoint3d position(4.0, 5.0, 6.0);
AcGeVector3d u(scaleFactor * m_imageData->width, 0.0, 0.0);
AcGeVector3d v(0.0, scaleFactor * m_imageData->height, 0.0);
AcGiGeometry::TransparencyMode transparencyMode = AcGiGeometry::kTransparencyOff;
mode->rawGeometry()->image(imageSource, position, u, v, transparencyMode);
}
/// <summary>
/// The TstRasterImageDef class is a custom implementation of the AcDbRasterImageDef class.
/// It provides methods to read and write data to and from DWG files, along with the capability
/// to embed an image from a specified file path into the object using the ATIL image library.
/// The class uses the Atil::Image class for image handling and supports serialization and
/// deserialization of image data within a DWG file.
/// NOTE: This implementation embeds the image in the drawing but does not generate proxy graphics.
/// If the DBX application is unloaded, the image will not be displayed.
/// </summary>
class TstRasterImageDef: public AcDbRasterImageDef {
protected:
static Adesk::UInt32 kCurrentVersionNumber;
public:
ACRX_DECLARE_MEMBERS(TstRasterImageDef);
TstRasterImageDef();
virtual ~TstRasterImageDef();
virtual Acad::ErrorStatus dwgInFields(AcDbDwgFiler* filer) override;
virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* filer) const override;
Acad::ErrorStatus setEmbeddedImage(const ACHAR* imageFilePath);
private:
Atil::Image* m_pAtilImage;
};
Adesk::UInt32 TstRasterImageDef::kCurrentVersionNumber = 1;
ACRX_DXF_DEFINE_MEMBERS(
TstRasterImageDef, AcDbRasterImageDef,
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
0, TST_RASTER_IMAGE_DEF, "TstRasterImageApp")
TstRasterImageDef::TstRasterImageDef() : m_pAtilImage(nullptr) {}
TstRasterImageDef::~TstRasterImageDef() {
if (m_pAtilImage) {
delete m_pAtilImage;
m_pAtilImage = nullptr;
}
}
Acad::ErrorStatus TstRasterImageDef::dwgOutFields(AcDbDwgFiler* pFiler) const {
assertReadEnabled();
//----- Save parent class information first.
Acad::ErrorStatus es = AcDbRasterImageDef::dwgOutFields(pFiler);
if (es != Acad::eOk)
return (es);
//----- Object version number needs to be saved first
if ((es = pFiler->writeUInt32(TstRasterImageDef::kCurrentVersionNumber)) != Acad::eOk)
return (es);
if (m_pAtilImage)
{
Atil::Size size = m_pAtilImage->size();
Adesk::Int32 width = size.width;
Adesk::Int32 height = size.height;
pFiler->writeInt32(width);
pFiler->writeInt32(height);
// Write the image data on to the Atil image
// using an Image Context
Atil::Offset upperLeft(0, 0);
Atil::ImageContext* pImgContext = m_pAtilImage->createContext(
Atil::ImageContext::kRead,
size,
upperLeft
);
if (pImgContext != NULL)
{
for (int xf = 0; xf < width; xf++)
{
for (int yf = 0; yf < height; yf++)
{
Atil::RgbColor p;
p = pImgContext->get32(xf, yf);
pFiler->writeInt32(p.packed);
}
}
}
pImgContext->flush();
delete pImgContext;
}
return (pFiler->filerStatus());
}
Acad::ErrorStatus TstRasterImageDef::dwgInFields(AcDbDwgFiler* pFiler) {
assertWriteEnabled();
//----- Read parent class information first.
Acad::ErrorStatus es = AcDbRasterImageDef::dwgInFields(pFiler);
if (es != Acad::eOk)
return (es);
//----- Object version number needs to be read first
Adesk::UInt32 version = 0;
if ((es = pFiler->readUInt32(&version)) != Acad::eOk)
return (es);
if (version > TstRasterImageDef::kCurrentVersionNumber)
return (Acad::eMakeMeProxy);
Adesk::Int32 width = 0;
Adesk::Int32 height = 0;
pFiler->readInt32(&width);
pFiler->readInt32(&height);
// Create an Atil::Image.
// The AcDbRasterImageDef::setImage requires it
Atil::ImagePixel initialImage;
initialImage.setToZero();
initialImage.type = Atil::DataModelAttributes::kBgra;
initialImage.value.rgba = 0xff000000;
Atil::Size size(width, height);
const Atil::RgbModel* pDm = new Atil::RgbModel(
Atil::RgbModelAttributes::k4Channels,
Atil::DataModelAttributes::kBlueGreenRedAlpha);
if (m_pAtilImage != NULL)
{
delete m_pAtilImage;
m_pAtilImage = NULL;
}
m_pAtilImage = new Atil::Image(size, pDm, initialImage);
// Write the image data on to the Atil image
// using an Image Context
Atil::Offset upperLeft(0, 0);
Atil::ImageContext* pImgContext = m_pAtilImage->createContext(
Atil::ImageContext::kWrite,
size,
upperLeft
);
if (pImgContext != NULL)
{
for (int xf = 0; xf < width; xf++)
{
for (int yf = 0; yf < height; yf++)
{
Adesk::Int32 value;
pFiler->readInt32(&value);
pImgContext->put32(xf, yf, value);
}
}
}
pImgContext->flush();
delete pImgContext;
setImage(m_pAtilImage, NULL);
return (pFiler->filerStatus());
}
Acad::ErrorStatus TstRasterImageDef::setEmbeddedImage(const ACHAR* imageFilePath) {
assertWriteEnabled();
if (!imageFilePath || *imageFilePath == '\0') {
return Acad::eInvalidInput;
}
AcString imagePath(imageFilePath);
// Load the image to get access to its image buffer
AcTcImage tc;
if (!tc.Load(imagePath)) {
return Acad::eFileNotFound;
}
HBITMAP bmp = 0;
tc.GetHBITMAP(RGB(0xff, 0xff, 0xff), bmp);
if (!bmp) {
return Acad::eFileNotFound;
}
BITMAP bmpInfo = { 0 };
if (!GetObject(bmp, sizeof(BITMAP), &bmpInfo)) {
DeleteObject(bmp);
return Acad::eInvalidInput;
}
HDC hdcScr = GetDC(NULL);
if (!hdcScr) {
DeleteObject(bmp);
return Acad::eCreateFailed;
}
HDC hdcMem = CreateCompatibleDC(hdcScr);
if (!hdcMem) {
ReleaseDC(NULL, hdcScr);
DeleteObject(bmp);
return Acad::eCreateFailed;
}
SelectObject(hdcMem, bmp);
// Create an Atil::Image for AcDbRasterImageDef::setImage
Atil::ImagePixel initialImage;
initialImage.setToZero();
initialImage.type = Atil::DataModelAttributes::kBgra;
initialImage.value.rgba = 0xff000000;
Atil::Size size(bmpInfo.bmWidth, bmpInfo.bmHeight);
std::unique_ptr<const Atil::RgbModel> pDm(new Atil::RgbModel(
Atil::RgbModelAttributes::k4Channels,
Atil::DataModelAttributes::kBlueGreenRedAlpha));
if (m_pAtilImage) {
delete m_pAtilImage;
m_pAtilImage = nullptr;
}
m_pAtilImage = new Atil::Image(size, pDm.get(), initialImage);
// Write image data to Atil::Image using an ImageContext
Atil::Offset upperLeft(0, 0);
std::unique_ptr<Atil::ImageContext> pImgContext(
m_pAtilImage->createContext(Atil::ImageContext::kWrite, size, upperLeft));
if (!pImgContext) {
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScr);
DeleteObject(bmp);
return Acad::eInvalidInput;
}
for (int x = 0; x < bmpInfo.bmWidth; ++x) {
for (int y = 0; y < bmpInfo.bmHeight; ++y) {
COLORREF pixelColor = GetPixel(hdcMem, x, y);
BYTE r = GetRValue(pixelColor);
BYTE g = GetGValue(pixelColor);
BYTE b = GetBValue(pixelColor);
BYTE a = (r != 0xff || g != 0xff || b != 0xff) ? 0xff : 0x00;
Atil::RgbColor pixel;
pixel.set(r, g, b, a);
pImgContext->put32(x, y, pixel);
}
}
pImgContext->flush();
if (!m_pAtilImage->isValid()) {
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScr);
DeleteObject(bmp);
return Acad::eInvalidInput;
}
// Cleanup
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScr);
DeleteObject(bmp);
return setImage(m_pAtilImage, nullptr);
}
/// <summary>
/// Command method to embed an image in the drawing database.
/// </summary>
void embedImage() {
auto imageData = std::make_unique<ImageData>();
imageData->initialize("D:\\Work\\Projects\\2025\\imgSamp\\1234.bmp");
if (!imageData->isInitialized()) {
acutPrintf(_T("\nFailed to initialize image data."));
return;
}
auto* pImageWorldDraw = new ImageWorldDraw(std::move(imageData));
AcDbObjectId imageOID;
Acad::ErrorStatus es = postToDatabase(pImageWorldDraw, imageOID);
if (es != Acad::eOk) {
acutPrintf(_T("\nFailed to post the image to the database."));
delete pImageWorldDraw;
}
}
static Acad::ErrorStatus InsertImageInDwg(AcDbRasterImageDef* pImageDef)
{
Acad::ErrorStatus es;
if (!pImageDef->isLoaded()) {
es = pImageDef->load();
if (es != Acad::eOk)
return es;
}
AcDbDatabase* pDB = acdbHostApplicationServices()->workingDatabase();
// Get or create the image dictionary
AcDbObjectId dictID = AcDbRasterImageDef::imageDictionary(pDB);
if (dictID == AcDbObjectId::kNull) {
es = AcDbRasterImageDef::createImageDictionary(pDB, dictID);
if (es != Acad::eOk)
return es;
}
AcDbDictionary* pDict;
es = acdbOpenObject(pDict, dictID, AcDb::kForWrite);
if (es != Acad::eOk)
return es;
const ACHAR* DICT_NAME = ACRX_T("RASTER_USING_BUFFER");
AcDbObjectId objID = AcDbObjectId::kNull;
if (!pDict->has(DICT_NAME)) {
es = pDict->setAt(DICT_NAME, pImageDef, objID);
if (es != Acad::eOk) {
pDict->close();
return es;
}
}
else {
es = pDict->getAt(DICT_NAME, (AcDbObject*&)pImageDef, AcDb::kForWrite);
if (es != Acad::eOk) {
pDict->close();
return es;
}
objID = pImageDef->objectId();
}
pDict->close();
pImageDef->close();
// Create and configure a raster image entity
AcDbRasterImage* pImage = new AcDbRasterImage();
es = pImage->setImageDefId(objID);
if (es != Acad::eOk) {
delete pImage;
return es;
}
es = postToDatabase(pImage, objID);
if (es != Acad::eOk) {
delete pImage;
return es;
}
// Set up the reactor for the raster image
AcDbObjectPointer<AcDbRasterImageDefReactor> rasterImageDefReactor;
rasterImageDefReactor.create();
es = rasterImageDefReactor->setOwnerId(pImage->objectId());
if (es == Acad::eOk) {
AcDbObjectId defReactorId;
es = pDB->addAcDbObject(defReactorId, rasterImageDefReactor.object());
if (es == Acad::eOk) {
pImage->setReactorId(defReactorId);
AcDbObjectPointer<AcDbRasterImageDef> rasterImagedef(pImage->imageDefId(), AcDb::kForWrite);
if (rasterImagedef.openStatus() == Acad::eOk) {
rasterImagedef->addPersistentReactor(defReactorId);
}
}
}
return Acad::eOk;
}
/// <summary>
/// command method to insert a raster image in the drawing database.
/// </summary>
void rasterImage() {
TstRasterImageDef* pImageDef = new TstRasterImageDef();
Acad::ErrorStatus es = pImageDef->setEmbeddedImage(L"D:\\Work\\Projects\\2025\\imgSamp\\1234.bmp");
if (es != Acad::eOk) {
delete pImageDef;
return;
}
es = InsertImageInDwg(pImageDef);
if (es != Acad::eOk) {
delete pImageDef;
}
}
void initApp()
{
acrxDynamicLinker->loadModule(L"acismobj25.dbx", true);
ImageWorldDraw::rxInit();
TstRasterImageDef::rxInit();
acedRegCmds->addCommand(_T("IMGSAMP_COMMANDS"), _T("IMAGETEST"), _T("IMAGETEST"),
ACRX_CMD_MODAL, &embedImage);
acedRegCmds->addCommand(_T("IMGSAMP_COMMANDS"), _T("RASTERIMAGE"), _T("RASTERIMAGE"), ACRX_CMD_MODAL, &rasterImage);
acrxBuildClassHierarchy();
}
void unloadApp()
{
acedRegCmds->removeGroup( _T("IMGSAMP_COMMANDS") );
}
extern "C" AcRx::AppRetCode acrxEntryPoint( AcRx::AppMsgCode msg, void* pkt)
{
switch( msg ) {
case AcRx::kInitAppMsg:
//An ARX application is locked to memory by default.
//You must make the following function call to unlock it.
acrxDynamicLinker->unlockApplication(pkt);
//support MDI
acrxDynamicLinker->registerAppMDIAware(pkt);
initApp();
break;
case AcRx::kUnloadAppMsg:
deleteAcRxClass(ImageWorldDraw::desc());
unloadApp();
break;
default:
break;
}
return AcRx::kRetOK;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment