Using AcGiWorldGeometry::image() in custom entities,how can images be displayed when it's proxy entity?

dziwve67853
Advocate

Using AcGiWorldGeometry::image() in custom entities,how can images be displayed when it's proxy entity?

dziwve67853
Advocate
Advocate

I rewrote the saveas function, but it didn't work.

@daniel_cadext @tbrammer @Alexander.Rivilis 

0 Likes
Reply
Accepted solutions (2)
938 Views
24 Replies
Replies (24)

Kyudos
Collaborator
Collaborator

Raster vs OLERaster vs OLE

 

The OLE (my code, right) is definitely more pixelated than the raster (left) - I guess that is either down to AutoCAD or the OLE server (MS Paint). Is there a reason why OLE? Other than the embedding aspect, AcDbRasterImage seems a better choice?

 

0 Likes

dziwve67853
Advocate
Advocate

The effect on the left is very good, it's what I want. Can you upload the project as a compressed file with attachments? The ole image I currently obtained from the code cannot be displayed.

0 Likes

Kyudos
Collaborator
Collaborator

It is fairly easy to create an image object in code. Obviously you can exclude or replace my error handling and point manipulations. The disadvantage with these is that they are image references...meaning you need to send the image file with the DWG if you want it to display (unlike an embedded OLE image).

 

 

//------------------------------------------------------------------------------
void CreateImageEntity(CString sFileName, My_Point3D LL, My_Point3D UR, double dRot, CString sLayer)
//------------------------------------------------------------------------------
{
    CString szName = NameOnly(sFileName);
    AcApDocument *pActiveDoc = acDocManager->mdiActiveDocument();
    AcDbDatabase *pDb = pActiveDoc->database();
    AcDbRasterImageDef* pImageDef = new AcDbRasterImageDef();

    // Use a relative path if there is one
    CString sDesPath = pActiveDoc->fileName();
    CString sRelPath = GetRelativePath(sDesPath, sFileName);

    Acad::ErrorStatus es;
    if (!sRelPath.IsEmpty())
    {
        es = pImageDef->setSourceFileName(sRelPath);

        // This can fail erroneously in ACAD 2019, so try full path as alternative
        if (es != Acad::eOk)
        {
            es = pImageDef->setSourceFileName(sFileName);
        }
    }
    else
    {
        es = pImageDef->setSourceFileName(sFileName);
    }

    if (es != Acad::eOk)
    {
        // Report failure
        AEI_Error Error(AEI_Error::LEVEL1, IDE_FILE_23, sFileName);
        AEI_ErrorManager* pErrManager = pApp->GetErrorManager();
        pErrManager->OnError(Error);

        delete pImageDef;
        return;
    }
    es = pImageDef->load();
    ASSERT(es == Acad::eOk);
    AcDbObjectId dictID = AcDbRasterImageDef::imageDictionary(pDb);

    if (dictID == AcDbObjectId::kNull)
    {
        es = AcDbRasterImageDef::createImageDictionary(pDb, dictID);
        if (es != Acad::eOk)
        {
            delete pImageDef;
            pApp->DebugMessage(_T("\nCreateImageEntity - Could not create image dictionary"), 3);
            LOGMESSAGE(_T("\nCreateImageEntity - Could not create image dictionary"));
            return;
        }
    }

    AcDbDictionary* pDict = NULL;
    es = acdbTransactionManager->getObject((AcDbObject*&)pDict, dictID, AcDb::kForWrite);
    if (es != Acad::eOk)
    {
        delete pImageDef;
        pApp->DebugMessage(_T("\nCreateImageEntity - Could not open image dictionary"), 3);
        LOGMESSAGE(_T("\nCreateImageEntity - Could not open image dictionary"));
        return;
    }

    BOOL bExist = pDict->has(szName);
    AcDbObjectId objID;
    if (!bExist)
    {
        es = pDict->setAt(szName, pImageDef, objID);
    }
    else
    {
        es = pDict->getAt(szName, (AcDbObject*&)pImageDef, AcDb::kForWrite);
        objID = pImageDef->objectId();
    }
    // Close Dictionary and Definition.
    es = pDict->close();
    es = pImageDef->close();

    // Create a raster image using the RasterImage Def
    AcDbRasterImage* pImage = new AcDbRasterImage;
    es = pImage->setImageDefId(objID);
    if (es != Acad::eOk)
    {
        delete pImage;
        return;
    }

    // Add the raster image to the model space
    AcDbObjectId imageId = AcDbObjectId::kNull;
    es = pApp->GetTableRecord()->appendAcDbEntity(imageId, pImage);
    es = acdbTransactionManager->addNewlyCreatedDBRObject(pImage);

    // The points are rotated (i.e., correspond to the actual
    // corners on screen). To make the rotation work we have to de-rotate
    // the points and re-rotate the whole image, inserting it at the original point.
    LL.z = 0.0L;
    UR.z = 0.0L;

    AcGePoint3d ptOrg = CADManager.ConvertPoint(LL);
    AcGePoint3d ptLL = CADManager.ConvertPoint(LL);
    AcGePoint3d ptUR = CADManager.ConvertPoint(UR);
    ptLL.rotateBy(-dRot, AcGeVector3d::kZAxis);
    ptUR.rotateBy(-dRot, AcGeVector3d::kZAxis);
    AcGeVector3d LowerRightVector(ptUR.x - ptLL.x, 0, 0);
    LowerRightVector.rotateBy(dRot, AcGeVector3d::kZAxis);
    AcGeVector3d OnPlaneVector(0, ptUR.y - ptLL.y, 0);
    OnPlaneVector.rotateBy(dRot, AcGeVector3d::kZAxis);
    if (pImage->setOrientation(ptOrg, LowerRightVector, OnPlaneVector) != Adesk::kTrue)
    {
        pApp->DebugMessage(_T("\nCreateImageEntity - Set Orientation failed."), 3);
        LOGMESSAGE(_T("\nCreateImageEntity - Set Orientation failed"));
        es = pImage->close();
        return;
    }

    pImage->setDisplayOpt(AcDbRasterImage::kShow, Adesk::kTrue);
    pImage->setDisplayOpt(AcDbRasterImage::kTransparent, Adesk::kTrue);
    es = pImage->setLayer(sLayer);

    // This persistent reactor informs the image object(s) when the image def changes.
    // We need this to avoid the images being reported as 'Unreferenced' in the XREF panel
    AcDbObjectPointer<AcDbRasterImageDefReactor>  rasterImageDefReactor;
    rasterImageDefReactor.create();

    // Set the entity to be its owner.
    es = rasterImageDefReactor->setOwnerId(pImage->objectId());
    if (es == Acad::eOk)
    {
        AcDbObjectId defReactorId;

        // Assign the object an objectId
        es = pDb->addAcDbObject(defReactorId, rasterImageDefReactor.object());
        if (es == Acad::eOk)
        {
            // Set the image reactor id
            pImage->setReactorId(defReactorId);

            AcDbObjectPointer<AcDbRasterImageDef> rasterImagedef(pImage->imageDefId(), AcDb::kForWrite);
            if (rasterImagedef.openStatus() == Acad::eOk)
            {
                rasterImagedef->addPersistentReactor(defReactorId);
            }
        }
    }

    es = pImage->close();
}

 

 

0 Likes

dziwve67853
Advocate
Advocate

The most important goal is to send DWG to others without the need to include the original image like a raster image, and without sending ARX and DBX programs together. It is best to use code to generate OLE images or display images like proxy entities (with the same display effect as OLE, without too large pixel blocks)
Have you achieved full code insertion of OLE images without manually opening MS Paint? Can you upload the project code in a compressed file? AcDbRasterImage needs to be sent together with the same source file, which is not the effect I expected.

0 Likes

Kyudos
Collaborator
Collaborator

Yes, my code (above) works... but MS Paint (or some other OLE server) needs to be registered as the server for the file type. You can do this on your system by right-clicking a BMP file, choosing "Open with...|More Apps...|MS Paint" - be sure to check "Always use this app to open .bmp files" to set a permanent file association. The problem you might run into is that you have no control over what OLE server is registered for the BMP file type on someone else machine. That's why I recommend MS Paint - since it will always be on a Windows system. Even so, if the other user has a different application registered for BMPs, they might not be able to access the OLE commands. Nevertheless, the image generated by MS Paint (essentially, a thumbnail) when you insert the OLE object is likely rendered at the specific zoom level and resolution of the screen you add it on, meaning it won't (can't) look very good at other zoom states.  I'm afraid the only way to maintain full fidelity at different zoom states is to not use a raster format. e.g., use a vector format, such as SVG. But then you need to find an OLE server for SVGs, and make sure it is available to everyone who wants to interact with your inserted object...

0 Likes