ADN Open CIS
Сообщество программистов Autodesk в СНГ

20/02/2022

Внедрение изображения в чертеж

В этой статье мы рассмотрим создание пользовательского объекта, унаследованного от AcDbRasterImageDef, который сохраняет / загружает данные изображения в / из чертежа с помощью ATIL. Это гарантирует, что ваш чертеж не зависит от внешнего файла изображения, и данные изображения будут загружены в AcDbRasterImageDef, если ARX загружен в AutoCAD. Для других способов встроить изображение на рисунке, не имея зависимости от внешнего файла изображения, пожалуйста, обратитесь к этой статье: https://adn-cis.org/vstraivanie-izobrazheniya-v-chertezh.html

Код - C++: [Выделить]
  1. // AcDbMyRasterImageDef.h
  2. class  DLLIMPEXP AcDbMyRasterImageDef :
  3.     public  AcDbRasterImageDef
  4. {
  5. protected:
  6.  
  7.     static  Adesk::UInt32 kCurrentVersionNumber;
  8.  
  9. public:
  10.  
  11.     ACRX_DECLARE_MEMBERS(AcDbMyRasterImageDef);
  12.     AcDbMyRasterImageDef();
  13.  
  14.     virtual  ~AcDbMyRasterImageDef();
  15.  
  16.     virtual  Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* pFiler) const;
  17.  
  18.     virtual  Acad::ErrorStatus dwgInFields (AcDbDwgFiler* pFiler);
  19.  
  20.     //----- deepClone
  21.  
  22.     virtual  Acad::ErrorStatus subDeepClone(AcDbObject* pOwnerObject,
  23.             AcDbObject*& pClonedObject, AcDbIdMapping& idMap,
  24.             Adesk::Boolean isPrimary = true) const;
  25.  
  26.     //----- wblockClone
  27.  
  28.     virtual  Acad::ErrorStatus subWblockClone  (AcRxObject* pOwnerObject, AcDbObject*& pClonedObject,
  29.         AcDbIdMapping& idMap, Adesk::Boolean isPrimary = true)
  30.         const;
  31.  
  32.  
  33.  
  34.     Acad::ErrorStatus setEmbeddedImage(const  ACHAR* imageFilePath);
  35.  
  36. private:
  37.  
  38.     void* operator  new [](size_t) throw () { return  (void*)0; }
  39.  
  40.     void  operator  delete [](void*) {};
  41.  
  42.     void* operator  new [](size_t, const  char*, int) throw ()   { return  (void*) 0; }
  43.  
  44.     Atil::Image* m_pAtilImage;
  45.  
  46. };
  47.  
  48. // AcDbMyRasterImageDef.cpp
  49.  
  50. AcDbMyRasterImageDef::AcDbMyRasterImageDef()
  51.     : AcDbRasterImageDef()
  52.  
  53. {
  54.  
  55.     m_pAtilImage = NULL;
  56.  
  57. }
  58.  
  59. AcDbMyRasterImageDef::~AcDbMyRasterImageDef()
  60.  
  61. {
  62.     if (m_pAtilImage != NULL)
  63.     {
  64.         delete  m_pAtilImage;
  65.         m_pAtilImage = NULL;
  66.     }
  67. }
  68.  
  69.  
  70.  
  71. Acad::ErrorStatus AcDbMyRasterImageDef::dwgOutFields (AcDbDwgFiler* pFiler) const
  72.  
  73. {
  74.  
  75.     assertReadEnabled();
  76.  
  77.     //----- Сначала сохраняем информацию родительского класса.
  78.  
  79.     Acad::ErrorStatus es = AcDbRasterImageDef::dwgOutFields(pFiler);
  80.  
  81.     if (es != Acad::eOk)
  82.         return  (es);
  83.  
  84.     //----- Сначала сохраняем версию объекта
  85.  
  86.     if ((es = pFiler->writeUInt32 (AcDbMyRasterImageDef::kCurrentVersionNumber)) != Acad::eOk)
  87.         return  (es);
  88.  
  89.  
  90.  
  91.     if (m_pAtilImage)
  92.     {
  93.  
  94.         Atil::Size size = m_pAtilImage->size();
  95.  
  96.         Int32 width = size.width;
  97.  
  98.         Int32 height = size.height;
  99.  
  100.         pFiler->writeInt32(width);
  101.  
  102.         pFiler->writeInt32(height);
  103.  
  104.         // Записываем данные изображения в Atil
  105.         // при помощи контекста изображения
  106.  
  107.         Atil::Offset upperLeft(0, 0);
  108.  
  109.         Atil::ImageContext* pImgContext = m_pAtilImage->createContext(
  110.                 Atil::ImageContext::kRead,
  111.                 size,
  112.                 upperLeft);
  113.  
  114.         if (pImgContext != NULL)
  115.         {
  116.             for (int xf = 0; xf < width; xf++)
  117.             {
  118.                 for (int yf = 0; yf < height; yf++)
  119.                 {
  120.                     Atil::RgbColor p;
  121.                     p = pImgContext->get32(xf, yf);
  122.                     pFiler->writeInt32(p.packed);
  123.                 }
  124.             }
  125.         }
  126.         pImgContext->flush();
  127.         delete  pImgContext;
  128.  
  129.     }
  130.  
  131.     return  (pFiler->filerStatus());
  132.  
  133. }
  134.  
  135.  
  136. Acad::ErrorStatus AcDbMyRasterImageDef::dwgInFields (AcDbDwgFiler* pFiler)
  137.  
  138. {
  139.  
  140.     assertWriteEnabled();
  141.  
  142.     Acad::ErrorStatus es =
  143.         AcDbRasterImageDef::dwgInFields(pFiler);
  144.  
  145.     if (es != Acad::eOk)
  146.         return  (es);
  147.  
  148.     Adesk::UInt32 version = 0;
  149.  
  150.     if ((es = pFiler->readUInt32(&version))
  151.         != Acad::eOk)
  152.         return  (es);
  153.  
  154.     if (version >
  155.         AcDbMyRasterImageDef::kCurrentVersionNumber)
  156.         return  (Acad::eMakeMeProxy);
  157.  
  158.     Int32 width = 0;
  159.     Int32 height = 0;
  160.  
  161.     pFiler->readInt32(&width);
  162.  
  163.     pFiler->readInt32(&height);
  164.  
  165.     // Создаём Atil::Image.
  166.  
  167.     // Он необходим для AcDbRasterImageDef::setImage
  168.  
  169.     Atil::ImagePixel initialImage;
  170.  
  171.     initialImage.setToZero();
  172.  
  173.     initialImage.type  = Atil::DataModelAttributes::kBgra;
  174.  
  175.     initialImage.value.rgba = 0xff000000;
  176.  
  177.     Atil::Size size(width, height);
  178.  
  179.     const  Atil::RgbModel* pDm  = new  Atil::RgbModel(
  180.             Atil::RgbModelAttributes::k4Channels,
  181.             Atil::DataModelAttributes::kBlueGreenRedAlpha);
  182.  
  183.     if (m_pAtilImage != NULL)
  184.     {
  185.         delete  m_pAtilImage;
  186.         m_pAtilImage = NULL;
  187.     }
  188.  
  189.     m_pAtilImage  = new  Atil::Image(size, pDm, initialImage);
  190.  
  191.     // Записываем данные изображения в Atil
  192.     // используя контекст изображения
  193.  
  194.     Atil::Offset upperLeft(0, 0);
  195.  
  196.     Atil::ImageContext* pImgContext  = m_pAtilImage->createContext(
  197.             Atil::ImageContext::kWrite,
  198.             size,
  199.             upperLeft);
  200.  
  201.     if (pImgContext != NULL)
  202.     {
  203.         for (int xf = 0; xf < width; xf++)
  204.         {
  205.             for (int yf = 0; yf < height; yf++)
  206.             {
  207.                 Int32 value;
  208.                 pFiler->readInt32(&value);
  209.                 pImgContext->put32(xf, yf, value);
  210.             }
  211.         }
  212.     }
  213.  
  214.     pImgContext->flush();
  215.     delete  pImgContext;
  216.     setImage(m_pAtilImage, NULL);
  217.     return  (pFiler->filerStatus());
  218.  
  219. }
  220.  
  221.  
  222.  
  223. //----- deepClone
  224.  
  225. Acad::ErrorStatus AcDbMyRasterImageDef::subDeepClone (AcDbObject* pOwnerObject, AcDbObject*& pClonedObject,
  226.     AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const
  227.  
  228. {
  229.  
  230.     assertReadEnabled();
  231.     return  (AcDbRasterImageDef::subDeepClone (pOwnerObject, pClonedObject, idMap, isPrimary));
  232.  
  233. }
  234.  
  235.  
  236.  
  237. //----- wblockClone
  238.  
  239. Acad::ErrorStatus AcDbMyRasterImageDef::subWblockClone (AcRxObject* pOwnerObject, AcDbObject*& pClonedObject,
  240.     AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const
  241.  
  242. {
  243.     assertReadEnabled();
  244.     return  (AcDbRasterImageDef::subWblockClone (pOwnerObject, pClonedObject, idMap, isPrimary));
  245.  
  246. }
  247.  
  248.  
  249.  
  250. Acad::ErrorStatus  AcDbMyRasterImageDef::setEmbeddedImage (const  ACHAR* imageFilePath)
  251. {
  252.  
  253.     AcString imagePath(imageFilePath);
  254.  
  255.     AcTcImage tc;
  256.  
  257.     tc.Load(imagePath);
  258.  
  259.     HBITMAP bmp = 0;
  260.     tc.GetHBITMAP(RGB(0xff, 0xff, 0xff), bmp);
  261.  
  262.     if (bmp == NULL)
  263.         return  Acad::eFileNotFound;
  264.  
  265.     BITMAP _bmp = { 0 };
  266.     GetObject(bmp, sizeof  BITMAP, &_bmp);
  267.  
  268.     HDC hdcScr = GetDC(NULL);
  269.     HDC hdcMem = CreateCompatibleDC(hdcScr);
  270.  
  271.     SelectObject(hdcMem, bmp);
  272.  
  273.     Atil::ImagePixel initialImage;
  274.     initialImage.setToZero();
  275.     initialImage.type = Atil::DataModelAttributes::kBgra;
  276.     initialImage.value.rgba = 0xff000000;
  277.  
  278.     Atil::Size size(_bmp.bmWidth, _bmp.bmHeight);
  279.  
  280.     const  Atil::RgbModel* pDm = new  Atil::RgbModel(
  281.         Atil::RgbModelAttributes::k4Channels,
  282.         Atil::DataModelAttributes::kBlueGreenRedAlpha);
  283.  
  284.     if (m_pAtilImage != NULL)
  285.     {
  286.         delete  m_pAtilImage;
  287.         m_pAtilImage = NULL;
  288.     }
  289.  
  290.     m_pAtilImage = new  Atil::Image(size, pDm, initialImage);
  291.     Atil::Offset upperLeft(0, 0);
  292.     Atil::ImageContext* pImgContext = m_pAtilImage->createContext(
  293.             Atil::ImageContext::kWrite,
  294.             size,
  295.             upperLeft);
  296.  
  297.     if (pImgContext != NULL)
  298.     {
  299.         for (int xf = 0; xf < _bmp.bmWidth; xf++)
  300.         {
  301.             for (int yf = 0; yf < _bmp.bmHeight; yf++)
  302.             {
  303.                 BYTE alpha = 0xff;
  304.                 COLORREF pix = GetPixel(hdcMem, xf, yf);
  305.                 BYTE rr = (pix & 0xff);
  306.                 BYTE gg = (pix >> 8) & 0xff;
  307.                 BYTE bb = (pix >> 16) & 0xff;
  308.                 Atil::RgbColor p;
  309.                 p.set(rr, gg, bb, alpha);
  310.                 pImgContext->put32(xf, yf, p);
  311.             }
  312.         }
  313.     }
  314.  
  315.     pImgContext->flush();
  316.     delete  pImgContext;
  317.     bool  isImageValid = m_pAtilImage->isValid();
  318.  
  319.     assert(isImageValid);
  320.  
  321.     // Очистка
  322.  
  323.     DeleteDC(hdcMem);
  324.     ReleaseDC(NULL, hdcScr);
  325.     DeleteObject(bmp);
  326.     return  setImage(m_pAtilImage, NULL);
  327. }
  328.  
  329. // Тестовая команда внедрения изображения
  330.  
  331. static  void  AdskMyTestEmbedImage(void)
  332. {
  333.  
  334.     AcDbMyRasterImageDef* pImageDef
  335.         = new  AcDbMyRasterImageDef();
  336.  
  337.     pImageDef->setEmbeddedImage(ACRX_T("D:\\TestFiles\\MyTexture.jpg"));
  338.  
  339.     Acad::ErrorStatus es  = InsertImageInDwg(pImageDef);
  340.     if (es != Acad::eOk)
  341.  
  342.     {
  343.         delete  pImageDef;
  344.         return;
  345.     }
  346.  
  347. }
  348.  
  349. static  Acad::ErrorStatus InsertImageInDwg(AcDbRasterImageDef* pImageDef)
  350. {
  351.     Acad::ErrorStatus es;
  352.  
  353.     if (!pImageDef->isLoaded())
  354.     {
  355.         es = pImageDef->load();
  356.         if (es != Acad::eOk)
  357.             return  es;
  358.  
  359.     }
  360.  
  361.     AcApDocument* pActiveDoc
  362.         = acDocManager->mdiActiveDocument();
  363.  
  364.     AcDbDatabase* pDB = pActiveDoc->database();
  365.  
  366.     // Получаем словарь изображений
  367.     // Если его еще нет – создадим его
  368.  
  369.     AcDbObjectId dictID
  370.         = AcDbRasterImageDef::imageDictionary(pDB);
  371.  
  372.  
  373.  
  374.     if (dictID == AcDbObjectId::kNull)
  375.  
  376.     {
  377.  
  378.         es = AcDbRasterImageDef::createImageDictionary
  379.  
  380.         (pDB, dictID);
  381.  
  382.         if (es != Acad::eOk)
  383.             return  es;
  384.  
  385.     }
  386.  
  387.     AcDbDictionary* pDict;
  388.  
  389.     es = acdbOpenObject(pDict, dictID, AcDb::kForWrite);
  390.  
  391.     if (es != Acad::eOk)
  392.         return  es;
  393.  
  394.     ACHAR* DICT_NAME = ACRX_T("RASTER_USING_BUFFER");
  395.  
  396.     BOOL bExist = pDict->has(DICT_NAME);
  397.  
  398.     AcDbObjectId objID = AcDbObjectId::kNull;
  399.  
  400.     if (!bExist)
  401.  
  402.     {
  403.         es = pDict->setAt(DICT_NAME, pImageDef, objID);
  404.  
  405.         if (es != Acad::eOk)
  406.         {
  407.             pDict->close();
  408.             return  es;
  409.         }
  410.     }
  411.     else
  412.     {
  413.  
  414.         pDict->getAt(DICT_NAME,
  415.             (AcDbObject*&)pImageDef,
  416.             AcDb::kForWrite);
  417.  
  418.         objID = pImageDef->objectId();
  419.  
  420.     }
  421.  
  422.     // Закрываем и словарь, и определение изображения.
  423.  
  424.     pDict->close();
  425.  
  426.     pImageDef->close();
  427.  
  428.     // Создаем растровое изображение при помощи RasterImage Def
  429.  
  430.     AcDbRasterImage* pImage = new  AcDbRasterImage;
  431.  
  432.     es = pImage->setImageDefId(objID);
  433.  
  434.     if (es != Acad::eOk)
  435.     {
  436.         delete  pImage;
  437.         return  es;
  438.     }
  439.  
  440.  
  441.  
  442.     // Добавляем растровое изображение в Пространство модели
  443.  
  444.     AcDbBlockTable* pBlockTable;
  445.     AcDbBlockTableRecord* pBTRecord;
  446.     es = acdbCurDwg()->getBlockTable(pBlockTable,
  447.         AcDb::kForRead);
  448.  
  449.     assert(es == Acad::eOk);
  450.  
  451.     es = pBlockTable->getAt(ACDB_MODEL_SPACE,
  452.         pBTRecord,
  453.         AcDb::kForWrite);
  454.     assert(es == Acad::eOk);
  455.     es = pBTRecord->appendAcDbEntity(pImage);
  456.     assert(es == Acad::eOk);
  457.     pBTRecord->close();
  458.     pBlockTable->close();
  459.     AcDbObjectId entID = pImage->objectId();
  460.     AcDbObjectPointer<AcDbRasterImageDefReactor> rasterImageDefReactor;
  461.     rasterImageDefReactor.create();
  462.     es = rasterImageDefReactor->setOwnerId(pImage->objectId());
  463.  
  464.     if (es == Acad::eOk)
  465.     {
  466.         AcDbObjectId defReactorId;
  467.  
  468.         es = curDoc()->database()->addAcDbObject(
  469.             defReactorId,
  470.             rasterImageDefReactor.object());
  471.  
  472.         if (es == Acad::eOk)
  473.         {
  474.             pImage->setReactorId(defReactorId);
  475.             AcDbObjectPointer<AcDbRasterImageDef> rasterImagedef (pImage->imageDefId(), AcDb::kForWrite);
  476.             if (rasterImagedef.openStatus() == Acad::eOk)
  477.             {
  478.                 rasterImagedef->addPersistentReactor (defReactorId);
  479.             }
  480.         }
  481.     }
  482.     pImageDef->close();
  483.     pImage->close();
  484.     return  Acad::eOk;
  485. }
  486.  
  487. virtual  AcRx::AppRetCode On_kInitAppMsg(void* pkt)
  488. {
  489.     AcRx::AppRetCode retCode =
  490.         AcRxArxApp::On_kInitAppMsg(pkt);
  491.     acrxDynamicLinker->loadModule
  492.     (L"acismobj20.dbx", true);
  493.     AcDbMyRasterImageDef::rxInit();
  494.     acrxBuildClassHierarchy();
  495.     return  (retCode);
  496. }

 

Проект этого примера можно загрузить отсюда: 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