Внедрение изображения в чертеж
В этой статье мы рассмотрим создание пользовательского объекта, унаследованного от AcDbRasterImageDef, который сохраняет / загружает данные изображения в / из чертежа с помощью ATIL. Это гарантирует, что ваш чертеж не зависит от внешнего файла изображения, и данные изображения будут загружены в AcDbRasterImageDef, если ARX загружен в AutoCAD. Для других способов встроить изображение на рисунке, не имея зависимости от внешнего файла изображения, пожалуйста, обратитесь к этой статье: https://adn-cis.org/vstraivanie-izobrazheniya-v-chertezh.html
- // AcDbMyRasterImageDef.h
- class DLLIMPEXP AcDbMyRasterImageDef :
- public AcDbRasterImageDef
- {
- protected:
- static Adesk::UInt32 kCurrentVersionNumber;
- public:
- ACRX_DECLARE_MEMBERS(AcDbMyRasterImageDef);
- AcDbMyRasterImageDef();
- virtual ~AcDbMyRasterImageDef();
- virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* pFiler) const;
- virtual Acad::ErrorStatus dwgInFields (AcDbDwgFiler* pFiler);
- //----- deepClone
- virtual Acad::ErrorStatus subDeepClone(AcDbObject* pOwnerObject,
- AcDbObject*& pClonedObject, AcDbIdMapping& idMap,
- Adesk::Boolean isPrimary = true) const;
- //----- wblockClone
- virtual Acad::ErrorStatus subWblockClone (AcRxObject* pOwnerObject, AcDbObject*& pClonedObject,
- AcDbIdMapping& idMap, Adesk::Boolean isPrimary = true)
- const;
- Acad::ErrorStatus setEmbeddedImage(const ACHAR* imageFilePath);
- private:
- void* operator new [](size_t) throw () { return (void*)0; }
- void operator delete [](void*) {};
- void* operator new [](size_t, const char*, int) throw () { return (void*) 0; }
- Atil::Image* m_pAtilImage;
- };
- // AcDbMyRasterImageDef.cpp
- AcDbMyRasterImageDef::AcDbMyRasterImageDef()
- : AcDbRasterImageDef()
- {
- m_pAtilImage = NULL;
- }
- AcDbMyRasterImageDef::~AcDbMyRasterImageDef()
- {
- if (m_pAtilImage != NULL)
- {
- delete m_pAtilImage;
- m_pAtilImage = NULL;
- }
- }
- Acad::ErrorStatus AcDbMyRasterImageDef::dwgOutFields (AcDbDwgFiler* pFiler) const
- {
- assertReadEnabled();
- //----- Сначала сохраняем информацию родительского класса.
- Acad::ErrorStatus es = AcDbRasterImageDef::dwgOutFields(pFiler);
- if (es != Acad::eOk)
- return (es);
- //----- Сначала сохраняем версию объекта
- if ((es = pFiler->writeUInt32 (AcDbMyRasterImageDef::kCurrentVersionNumber)) != Acad::eOk)
- return (es);
- if (m_pAtilImage)
- {
- Atil::Size size = m_pAtilImage->size();
- Int32 width = size.width;
- Int32 height = size.height;
- pFiler->writeInt32(width);
- pFiler->writeInt32(height);
- // Записываем данные изображения в Atil
- // при помощи контекста изображения
- 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 AcDbMyRasterImageDef::dwgInFields (AcDbDwgFiler* pFiler)
- {
- assertWriteEnabled();
- Acad::ErrorStatus es =
- AcDbRasterImageDef::dwgInFields(pFiler);
- if (es != Acad::eOk)
- return (es);
- Adesk::UInt32 version = 0;
- if ((es = pFiler->readUInt32(&version))
- != Acad::eOk)
- return (es);
- if (version >
- AcDbMyRasterImageDef::kCurrentVersionNumber)
- return (Acad::eMakeMeProxy);
- Int32 width = 0;
- Int32 height = 0;
- pFiler->readInt32(&width);
- pFiler->readInt32(&height);
- // Создаём Atil::Image.
- // Он необходим для AcDbRasterImageDef::setImage
- 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);
- // Записываем данные изображения в Atil
- // используя контекст изображения
- 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++)
- {
- Int32 value;
- pFiler->readInt32(&value);
- pImgContext->put32(xf, yf, value);
- }
- }
- }
- pImgContext->flush();
- delete pImgContext;
- setImage(m_pAtilImage, NULL);
- return (pFiler->filerStatus());
- }
- //----- deepClone
- Acad::ErrorStatus AcDbMyRasterImageDef::subDeepClone (AcDbObject* pOwnerObject, AcDbObject*& pClonedObject,
- AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const
- {
- assertReadEnabled();
- return (AcDbRasterImageDef::subDeepClone (pOwnerObject, pClonedObject, idMap, isPrimary));
- }
- //----- wblockClone
- Acad::ErrorStatus AcDbMyRasterImageDef::subWblockClone (AcRxObject* pOwnerObject, AcDbObject*& pClonedObject,
- AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const
- {
- assertReadEnabled();
- return (AcDbRasterImageDef::subWblockClone (pOwnerObject, pClonedObject, idMap, isPrimary));
- }
- Acad::ErrorStatus AcDbMyRasterImageDef::setEmbeddedImage (const ACHAR* imageFilePath)
- {
- AcString imagePath(imageFilePath);
- AcTcImage tc;
- tc.Load(imagePath);
- HBITMAP bmp = 0;
- tc.GetHBITMAP(RGB(0xff, 0xff, 0xff), bmp);
- if (bmp == NULL)
- return Acad::eFileNotFound;
- BITMAP _bmp = { 0 };
- GetObject(bmp, sizeof BITMAP, &_bmp);
- HDC hdcScr = GetDC(NULL);
- HDC hdcMem = CreateCompatibleDC(hdcScr);
- SelectObject(hdcMem, bmp);
- Atil::ImagePixel initialImage;
- initialImage.setToZero();
- initialImage.type = Atil::DataModelAttributes::kBgra;
- initialImage.value.rgba = 0xff000000;
- Atil::Size size(_bmp.bmWidth, _bmp.bmHeight);
- 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);
- Atil::Offset upperLeft(0, 0);
- Atil::ImageContext* pImgContext = m_pAtilImage->createContext(
- Atil::ImageContext::kWrite,
- size,
- upperLeft);
- if (pImgContext != NULL)
- {
- for (int xf = 0; xf < _bmp.bmWidth; xf++)
- {
- for (int yf = 0; yf < _bmp.bmHeight; yf++)
- {
- BYTE alpha = 0xff;
- COLORREF pix = GetPixel(hdcMem, xf, yf);
- BYTE rr = (pix & 0xff);
- BYTE gg = (pix >> 8) & 0xff;
- BYTE bb = (pix >> 16) & 0xff;
- Atil::RgbColor p;
- p.set(rr, gg, bb, alpha);
- pImgContext->put32(xf, yf, p);
- }
- }
- }
- pImgContext->flush();
- delete pImgContext;
- bool isImageValid = m_pAtilImage->isValid();
- assert(isImageValid);
- // Очистка
- DeleteDC(hdcMem);
- ReleaseDC(NULL, hdcScr);
- DeleteObject(bmp);
- return setImage(m_pAtilImage, NULL);
- }
- // Тестовая команда внедрения изображения
- static void AdskMyTestEmbedImage(void)
- {
- AcDbMyRasterImageDef* pImageDef
- = new AcDbMyRasterImageDef();
- pImageDef->setEmbeddedImage(ACRX_T("D:\\TestFiles\\MyTexture.jpg"));
- Acad::ErrorStatus es = InsertImageInDwg(pImageDef);
- if (es != Acad::eOk)
- {
- delete pImageDef;
- return;
- }
- }
- static Acad::ErrorStatus InsertImageInDwg(AcDbRasterImageDef* pImageDef)
- {
- Acad::ErrorStatus es;
- if (!pImageDef->isLoaded())
- {
- es = pImageDef->load();
- if (es != Acad::eOk)
- return es;
- }
- AcApDocument* pActiveDoc
- = acDocManager->mdiActiveDocument();
- AcDbDatabase* pDB = pActiveDoc->database();
- // Получаем словарь изображений
- // Если его еще нет – создадим его
- 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;
- ACHAR* DICT_NAME = ACRX_T("RASTER_USING_BUFFER");
- BOOL bExist = pDict->has(DICT_NAME);
- AcDbObjectId objID = AcDbObjectId::kNull;
- if (!bExist)
- {
- es = pDict->setAt(DICT_NAME, pImageDef, objID);
- if (es != Acad::eOk)
- {
- pDict->close();
- return es;
- }
- }
- else
- {
- pDict->getAt(DICT_NAME,
- (AcDbObject*&)pImageDef,
- AcDb::kForWrite);
- objID = pImageDef->objectId();
- }
- // Закрываем и словарь, и определение изображения.
- pDict->close();
- pImageDef->close();
- // Создаем растровое изображение при помощи RasterImage Def
- AcDbRasterImage* pImage = new AcDbRasterImage;
- es = pImage->setImageDefId(objID);
- if (es != Acad::eOk)
- {
- delete pImage;
- return es;
- }
- // Добавляем растровое изображение в Пространство модели
- AcDbBlockTable* pBlockTable;
- AcDbBlockTableRecord* pBTRecord;
- es = acdbCurDwg()->getBlockTable(pBlockTable,
- AcDb::kForRead);
- assert(es == Acad::eOk);
- es = pBlockTable->getAt(ACDB_MODEL_SPACE,
- pBTRecord,
- AcDb::kForWrite);
- assert(es == Acad::eOk);
- es = pBTRecord->appendAcDbEntity(pImage);
- assert(es == Acad::eOk);
- pBTRecord->close();
- pBlockTable->close();
- AcDbObjectId entID = pImage->objectId();
- AcDbObjectPointer<AcDbRasterImageDefReactor> rasterImageDefReactor;
- rasterImageDefReactor.create();
- es = rasterImageDefReactor->setOwnerId(pImage->objectId());
- if (es == Acad::eOk)
- {
- AcDbObjectId defReactorId;
- es = curDoc()->database()->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);
- }
- }
- }
- pImageDef->close();
- pImage->close();
- return Acad::eOk;
- }
- virtual AcRx::AppRetCode On_kInitAppMsg(void* pkt)
- {
- AcRx::AppRetCode retCode =
- AcRxArxApp::On_kInitAppMsg(pkt);
- acrxDynamicLinker->loadModule
- (L"acismobj20.dbx", true);
- AcDbMyRasterImageDef::rxInit();
- acrxBuildClassHierarchy();
- return (retCode);
- }
Проект этого примера можно загрузить отсюда: https://adndevblog.typepad.com/files/embedimage.zip
Если вы хотите создать встроенный растровое изображение с помощью AutoCAD .NET API, то вам понадобится создать управляемую обертку для этого пользовательского объекта. Сделать это только при помощи .NET невозможно, поскольку пользовательские объекты могут быть созданы только с помощью C ++. Кроме того, ATIL - это только библиотека C++, которую мы используем в этом классе.
Способ доступа к встроенному растровому изображению в .NET демонстрируется в следующем примере проекта. Чтобы попробовать его, загрузите .arx и .dll-файлы из него и запустите команду "EmbedImageMgd".
Этот пример проекта здесь: https://adndevblog.typepad.com/files/customrasterimagedef.zip
Обновление:
Код примера обновлен до версии ObjectARX 2022 и помещен в GitHub: https://github.com/MadhukarMoogala/EmbedRasterImage
Источник: https://adndevblog.typepad.com/autocad/2022/02/embedding-an-image-in-a-drawing.html
Опубликовано 20.02.2022
Отредактировано 20.02.2022 в 20:09:25