明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1899|回复: 25

使用 ObjectARX Atil工具屏幕截图

[复制链接]
发表于 2025-8-18 15:52:17 | 显示全部楼层 |阅读模式
本帖最后由 gzxl 于 2025-8-18 16:02 编辑

这两期属于搬砖形式,使用 ObjectARX Atil 工具屏幕截图

以前见到一个有意思的贴子,不想让贴子沉没。
http://adndevblog.typepad.com/au ... sing-objectarx.html



包含目录
  D:\ObjectARXSDK\ObjectARX 2025\utils\Atil\Inc
  D:\ObjectARXSDK\ObjectARX 2025\utils\Atil\Inc\format_codecs
  D:\ObjectARXSDK\ObjectARX 2025\utils\Atil\Inc\codec_properties

库目录
  D:\ObjectARXSDK\ObjectARX 2025\utils\Atil\Lib-x64

头文件:
  #include "AtilDefs.h"
  #include "Image.h"
  #include "RgbModel.h"
  #include "RgbPaletteModel.h"
  #include "ngCustomProperties.h"
  #include "BitonalModel.h"
  #include "atilformats.h"
  #include "JFIFFormatCodec.h"
  #include "TiffFormatCodec.h"
  #include "TiffCustomProperties.h"
  #include "BmpFormatCodec.h"
  #include "FileSpecifier.h"
  #include "FileWriteDescriptor.h"
  #include "FileReadDescriptor.h"
  #include "RowProviderInterface.h"

项目依赖项
  #pragma comment (lib ,"AdImaging.lib")
  #pragma comment (lib ,"AdIntImgServices.lib")


enum eFormatType
{
    kJPG,
    kPNG,
    kTIF,
    kBMP
};

  1. /*
  2. bool bSuccess = false;
  3. eFormatType formatType = kJPG;
  4. wchar_t const *pFileName = NULL;

  5. double fieldWidth = 800.0, fieldHeight = 600.0;
  6. AcGePoint3d position, target;
  7. AcGeVector3d upVector(AcGeVector3d::kZAxis);

  8. pFileName = _T("C:\\temp\\atil.bmp");
  9. bSuccess = RecordViewDetails(kBMP, fieldWidth, fieldHeight, position, target, upVector, pFileName);
  10. pFileName = _T("C:\\temp\\atil.png");
  11. bSuccess = RecordViewDetails(kPNG, fieldWidth, fieldHeight, position, target, upVector, pFileName);
  12. pFileName = _T("C:\\temp\\atil.jpg");
  13. bSuccess = RecordViewDetails(kJPG, fieldWidth, fieldHeight, position, target, upVector, pFileName);
  14. */

  15. AcGePoint3d pt1, pt2;
  16. if (RTNORM != acedGetPoint(NULL, _T("\n拾取屏幕截图左下角点:"), asDblArray(pt1)))
  17.     return;
  18. if (RTNORM != acedGetCorner(asDblArray(pt1), _T("\n拾取屏幕截图右上角点:"), asDblArray(pt2)))
  19.     return;
  20. double fieldWidth = fabs(pt2.x - pt1.x);
  21. double fieldHeight = fabs(pt2.y - pt1.y);

  22. AcGePoint3d target;
  23. AcGeVector3d upVector(AcGeVector3d::kZAxis);
  24. AcApDocument *pDoc = acDocManager->curDocument();
  25. CString file = pDoc->fileName();
  26. int nPosDot = file.ReverseFind('.');
  27. CString csFileNameWithoutExt = file.Left(nPosDot);
  28. acedInitGet(0, _T("A B C"));
  29. ACHAR kword[255];
  30. int res = acedGetKword(_T("输出图像类型[bmp(A)/png(B)/jpg(C)]:"), kword);
  31. if (res == RTNORM)
  32. {
  33.     if (_tcscmp(kword, _T("A")) == 0)
  34.     {
  35.         CString pFileName = csFileNameWithoutExt + _T(".bmp");
  36.         RecordViewDetails(kBMP, fieldWidth, fieldHeight, pt1, target, upVector, pFileName);
  37.     }
  38.     else if (_tcscmp(kword, _T("B")) == 0)
  39.     {
  40.         CString pFileName = csFileNameWithoutExt + _T(".png");
  41.         RecordViewDetails(kBMP, fieldWidth, fieldHeight, pt1, target, upVector, pFileName);
  42.     }
  43.     else if (_tcscmp(kword, _T("C")) == 0)
  44.     {
  45.         CString pFileName = csFileNameWithoutExt + _T(".jpg");
  46.         RecordViewDetails(kBMP, fieldWidth, fieldHeight, pt1, target, upVector, pFileName);
  47.     }
  48.     else
  49.     {
  50.         acutPrintf(_T("无效的输入\n"));
  51.     }
  52. }


// get the current vp
static int getCVPort()
{
    struct resbuf rb;
    ads_getvar(_T("CVPORT"), &rb);
    return rb.resval.rint;
}

static Atil::DataModel* colorSpace(char *&pRGBData, int colorDepth, int paletteSize)
{
    _ASSERT(NULL != pRGBData);

    // Setup a color space, with palette if needed
    Atil::DataModel *pDm = NULL;
    if (colorDepth == 8)
    {
        Atil::RgbColor space[256];

        Atil::RgbPaletteModel *pPM = new Atil::RgbPaletteModel();
        _ASSERT(NULL != pPM);
        if (!pPM)
            return NULL;

        pDm = pPM;
        char *palette = pRGBData;
        pRGBData += paletteSize;
        for (int i = 0; i < paletteSize; i += 4)
            space[i / 4] = Atil::RgbColor(palette[i + 2], palette[i + 1], palette, 255);

        pPM->setEntries(0, 256, (Atil::RgbColor *)&space);
    }
    else
        pDm = new Atil::RgbModel(32);

    _ASSERT(NULL != pDm);
    return pDm;
}

static Atil::Image *constructAtilImg(char *pRGBData, unsigned long bufferSize, unsigned long rowBytes, unsigned long xSize, unsigned long ySize, int colorDepth, int paletteSize)
{
    if ((8 != colorDepth) && (32 != colorDepth))
    {
        return NULL;
    }

    if (paletteSize)
    {
        if ((paletteSize < 0) || (paletteSize > 255))
        {
            return NULL;
        }
    }

    if ((xSize <= 0) || (ySize <= 0))
    {
        return NULL;
    }

    Atil::Image *pImg = NULL;
    Atil::Size size(xSize, ySize);

    // construct the Atil::Image object
    if (pRGBData)
    {
        // Check the buffer for size and definition
        if (bufferSize)
        {
            if (!rowBytes)
            {
                return NULL;
            }

            // did they allocate enough?
            if (rowBytes * ySize > bufferSize)
            {
                return NULL;
            }
        }
        else
        {
            return NULL;
        }

        Atil::DataModel *pM = colorSpace(pRGBData, colorDepth, paletteSize);
        _ASSERT(NULL != pM);
        if (NULL == pM)
            return NULL;

        try
        {
            // BEWARE: pRGBData may be moved in colorSpace
            pImg = new Atil::Image(pRGBData, bufferSize, rowBytes, size, pM);
        }
        catch (Atil::ATILException* pExpCon)
        {
            // image construction failure
            delete pExpCon;
            delete pM;
            pImg = NULL;
            _ASSERT(FALSE);
            return NULL;
        }

        delete pM;
    }
    else
    {
        Atil::RgbModel rgbM(32);
        Atil::RgbGrayModel gM;

        Atil::ImagePixel initialColor(colorDepth == 32 ? Atil::DataModelAttributes::kRgba : Atil::DataModelAttributes::kGray);
        initialColor.setToZero();

        try
        {
            pImg = new Atil::Image(size, colorDepth == 32 ? &rgbM : &gM, initialColor);
        }
        catch (Atil::ATILException* pExpCon)
        {
            // image construction failure
            delete pExpCon;
            pImg = NULL;
            _ASSERT(FALSE);
            return NULL;
        }
    }

    _ASSERT(NULL != pImg);
    return pImg;
}

static bool writeImageFile(Atil::Image *pImageSource, eFormatType formatType, wchar_t const *pFileName)
{
    _ASSERT(NULL != pImageSource);
    if (NULL == pImageSource)
        return false;

    _ASSERT(pImageSource->isValid());
    if (!pImageSource->isValid())
        return false;

    if (PathFileExists(pFileName))
        DeleteFile(pFileName);

    /*if(PathFileExists(pFileName))
    {
        if(IsFileReadOnly(pFileName))
        {
            RemoveReadonlyAttribute(pFileName);
            DeleteFile(pFileName);
        }
    }*/

    if (PathFileExists(pFileName))
        return false;

    Atil::RowProviderInterface* pPipe = pImageSource->read(pImageSource->size(),
        Atil::Offset(0, 0));
    _ASSERTE(NULL != pPipe);
    if (!pPipe)
        return false;

    Atil::FileWriteDescriptor *pFWD = NULL;
    Atil::ImageFormatCodec *pCodec = NULL;

    if (formatType == kJPG)
        pCodec = new JfifFormatCodec();
    else if (formatType == kPNG)
        pCodec = new PngFormatCodec();
    else if (formatType == kTIF)
        pCodec = new TiffFormatCodec();
    else if (formatType == kBMP)
        pCodec = new BmpFormatCodec();

    _ASSERTE(NULL != pCodec);
    if (NULL == pCodec)
        return false;

    if (!Atil::FileWriteDescriptor::isCompatibleFormatCodec(pCodec, &(pPipe->dataModel()), pPipe->size()))
    {
        delete pCodec;
        return false;
    }

    pFWD = new Atil::FileWriteDescriptor(pCodec);
    _ASSERTE(NULL != pFWD);

#ifdef UNICODE
#ifndef _ADESK_MAC_
    Atil::FileSpecifier fs(Atil::StringBuffer((lstrlen(pFileName) + 1) * sizeof(TCHAR),
        (const Atil::Byte *) pFileName, Atil::StringBuffer::kUTF_16),
        Atil::FileSpecifier::kFilePath);
#else
    Atil::FileSpecifier fs(Atil::StringBuffer((lstrlen(pFileName) + 1) * sizeof(TCHAR),
        (const Atil::Byte *) pFileName, Atil::StringBuffer::kUTF_32),
        Atil::FileSpecifier::kFilePath);

#endif
#else
    Atil::FileSpecifier fs(Atil::StringBuffer(lstrlen(pFileName) + 1,
        (const Atil::Byte *) pFileName, Atil::StringBuffer::kASCII),
        Atil::FileSpecifier::kFilePath);
#endif

    if (!pFWD->setFileSpecifier(fs))
        return false;

    pFWD->createImageFrame(pPipe->dataModel(), pPipe->size());

    if (formatType == kPNG)
    {
        Atil::FormatCodecPropertyInterface* pProp = pFWD->getProperty(Atil::FormatCodecPropertyInterface::kCompression);
        if (pProp != NULL)
        {
            PngCompression* pPngComp = (PngCompression*)(pProp);
            if (pPngComp != NULL)
            {
                // Why not compress all we can?
                pPngComp->selectCompression(PngCompressionType::kHigh);
                pFWD->setProperty(pPngComp);
            }
            delete pProp;
            pProp = NULL;
        }
    }
    else if (formatType == kTIF)
    {
        Atil::FormatCodecPropertyInterface* pProp = pFWD->getProperty(Atil::FormatCodecPropertyInterface::kCompression);
        if (pProp != NULL)
        {
            TiffCompression* pComp = (TiffCompression*)(pProp);
            if (pComp != NULL)
            {
                // G4 is only valid for 1 bit images.
                if (pComp->selectCompression(TiffCompressionType::kCCITT_FAX4) == false)
                {
                    // So if that fails, resort to LZW now that it is patent free
                    if (pComp->selectCompression(TiffCompressionType::kLZW) == false)
                    {
                        // If that fails (and is shouldn't, be) then set none.
                        pComp->selectCompression(TiffCompressionType::kNone);
                    }
                }
                pFWD->setProperty(pComp);
            }
            delete pProp;
            pProp = NULL;
        }
    }

    //TB141111 this was missing:
    int iRet = pFWD->writeImageFrame(pPipe);
    delete pFWD;
    pFWD = NULL;

    return true;
}

static bool snapGSView(eFormatType fmt, AcGsView *pView, int width, int height, double &fieldWidth,
    double &fieldHeight, AcGePoint3d &position, AcGePoint3d &target, AcGeVector3d &upVector, const TCHAR *imagePath)
{
    Atil::Size size(width, height);
    int nBytesPerRow = Atil::DataModel::bytesPerRow(width, Atil::DataModelAttributes::k32);
    unsigned long nBufferSize = height * nBytesPerRow;

    // Create an ATIL image for accepting the rendered image.
    //std::auto_ptr apCharBuffer = std::auto_ptr(new char[nBufferSize]);
    std::auto_ptr<char> apCharBuffer = std::auto_ptr<char>(new char[nBufferSize]);
    char *pSnapshotData = apCharBuffer.get(); // auto_ptr still owns the buffer.

    // in shaded mode (from GS)
    Atil::Image * pImage = NULL;
    pImage = constructAtilImg(pSnapshotData, nBufferSize, nBytesPerRow, width, height, 32, 0);
    //std::auto_ptr autodeleter = std::auto_ptr(pImage); // auto_ptr now owns the image
    std::auto_ptr<Atil::Image> autodeleter = std::auto_ptr<Atil::Image>(pImage);
    pView->getSnapShot(pImage, AcGsDCPoint(0, 0));

    // add a temp image to invert the image. do we have a better way to turn an image around?
    Atil::Image imgTempForInverted(pImage->read(pImage->size(), Atil::Offset(0, 0), Atil::kBottomUpLeftRight));
    *pImage = imgTempForInverted;

    if (!writeImageFile(pImage, fmt, imagePath))
    {
        acutPrintf(_T("\nFailed to write image file %s"), imagePath);
        return false;
    }
    else
        acutPrintf(_T("\nSuccessfully written %s"), imagePath);

    // record the view data
    fieldHeight = pView->fieldHeight();
    fieldWidth = pView->fieldWidth();
    position = pView->position();
    target = pView->target();
    upVector = pView->upVector();

    return true;
}

static bool getTempImgFile(TCHAR * fileName)
{
    // Here we create a temp bmp file as a transitional file
    TCHAR tempDic[MAX_PATH];
    ::memset(tempDic, 0, MAX_PATH);
    DWORD nRetSize = ::GetTempPath(MAX_PATH, tempDic);
    if (nRetSize > MAX_PATH || nRetSize == 0)
    {
        const TCHAR * tempStr = _T("C:\\temp");
        if (wcscpy_s(tempDic, tempStr) != 0)
        {
            return false;
        }

        if (::PathFileExists(tempStr) == FALSE && ::CreateDirectory(tempStr, NULL) == FALSE)
        {
            return false;
        }
    }

    // create the temp file whose prefix is "img"
    if (::GetTempFileName(tempDic, _T("tmp"), 0, fileName) == 0)
    {
        return false;
    }

    // now split the filepath into its individual components
    TCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
    _tsplitpath(fileName, drive, dir, fname, ext);
    _stprintf(fileName, _T("%s%s%s.bmp"), drive, dir, fname);

    return true;
}

// by Fenton Webb, DevTech, 1/30/2013
// screen shoots the view details as a BMP
static bool RecordViewDetails(eFormatType fmt, double &fieldWidth, double &fieldHeight, AcGePoint3d &position, AcGePoint3d &target, AcGeVector3d &upVector, const TCHAR *imagePath)
{
    int iVP = getCVPort();

    // Compute the viewport dimensions.
    int nLeft, nBottom, nRight, nTop;
    int iImageWidth, iImageHeight;
    acgsGetViewportInfo(iVP, nLeft, nBottom, nRight, nTop);

    iImageWidth = nRight - nLeft + 1;
    iImageHeight = nTop - nBottom + 1;
    Atil::Size size(iImageWidth, iImageHeight);
    int nBytesPerRow = Atil::DataModel::bytesPerRow(iImageWidth,
        Atil::DataModelAttributes::k32);
    unsigned long nBufferSize = iImageHeight * nBytesPerRow;

    // Create an ATIL image for accepting the rendered image.
    //std::auto_ptr autoBuff = std::auto_ptr(new char[nBufferSize]);
    std::auto_ptr<char> autoBuff = std::auto_ptr<char>(new char[nBufferSize]);
    char *pSnapshotData = autoBuff.get();
    Atil::Image * pImage = NULL;
    // see if there is a GS view created
    //AcGsView *pView = acgsGetGsView(iVP, false);
    resbuf cvport;
    acedGetVar(L"CVPORT", &cvport);
    AcGsView *pView = acgsGetCurrent3dAcGsView(cvport.resval.rint);

    // if not
    if (NULL == pView)
    {
        // then we must be in 2D wireframe mode, so use acgsGetScreenShot
        //std::auto_ptr autoScreenShot(acgsGetScreenShot(iVP));
        std::auto_ptr<AcGsScreenShot> autoScreenShot(acgsGetScreenShot(iVP));
        AcGsScreenShot* screenShot = autoScreenShot.get(); // auto_ptr still owns the pointer.
        if (screenShot)
        {
            int w = 0, h = 0, d = 0;
            screenShot->getSize(w, h, d);

            char* pBufTemp = pSnapshotData;
            for (int row = 0; row < h; row++)
            {
                memcpy(pBufTemp, screenShot->getScanline(0, row), nBytesPerRow);

                // convert from RGBA to BGRA
                char* pColor = pBufTemp;
                for (int i = 0; i < w; i++) // Slow but it works
                {
                    char temp = *pColor;
                    *pColor = *(pColor + 2);
                    *(pColor + 2) = temp;
                    pColor += 4;
                }
                pBufTemp += nBytesPerRow;
            }
            //pImage = constructAtilImg(reinterpret_cast(pSnapshotData), nBufferSize, nBytesPerRow, w, h, 32, 0);
            pImage = constructAtilImg(reinterpret_cast<char*>(pSnapshotData),
                nBufferSize, nBytesPerRow, w, h, 32, 0);
            //std::auto_ptr autodeleter = std::auto_ptr(pImage); // auto_ptr now owns the image
            std::auto_ptr<Atil::Image> autodeleter = std::auto_ptr<Atil::Image>(pImage);
            if (!writeImageFile(pImage, fmt, imagePath))
            {
                acutPrintf(_T("\nFailed to write image file %s"), imagePath);
                return false;
            }
            else
                acutPrintf(_T("\nSuccessfully written %s"), imagePath);
        }
        return true;
    }
    else
    {
        return snapGSView(fmt, pView, iImageWidth, iImageHeight, fieldHeight, fieldWidth, position, target, upVector, imagePath);
    }
}







本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
回复

使用道具 举报

发表于 2025-8-24 10:56:17 | 显示全部楼层
大佬厉害,搞个截图插件给我们白嫖下。lisp干不动截图
回复 支持 0 反对 1

使用道具 举报

发表于 2025-8-20 06:00:26 | 显示全部楼层
gzxl 发表于 2025-8-20 05:17
惊惊,好像看你们之前在研究 cad.net 自定义实体,成了没。

没有啊,我用"重定义"也一样效果就行了.
大部分人还是ARX封装一个基础给C#进行自定义图元,
我不太喜欢这个方案...
【C#编写自定义实体-哔哩哔哩】 https://b23.tv/aHG2apP
回复 支持 反对

使用道具 举报

发表于 2025-8-21 20:26:35 | 显示全部楼层
你有种再说一遍 发表于 2025-8-20 06:00
没有啊,我用"重定义"也一样效果就行了.
大部分人还是ARX封装一个基础给C#进行自定义图元,
我不太喜欢这 ...

辗转的一个方案毕竟还是感觉不太好,但也挺佩服大佬们的研究的。值得敬佩。
回复 支持 反对

使用道具 举报

发表于 2025-8-18 16:01:40 | 显示全部楼层
矢量转像素这种没啥意思啦,就是一个渲染机制,
像素转矢量才是难度,嘻嘻
回复 支持 反对

使用道具 举报

发表于 2025-8-18 21:58:33 | 显示全部楼层
感谢楼主分享!!
回复 支持 反对

使用道具 举报

发表于 2025-8-18 22:05:25 | 显示全部楼层
看看咋样,感谢分享
回复 支持 反对

使用道具 举报

发表于 2025-8-19 05:48:40 | 显示全部楼层
谢谢大佬的分享!
回覆来学习一下
回复 支持 反对

使用道具 举报

发表于 2025-8-19 11:01:55 | 显示全部楼层
看看咋样,感谢分享
回复 支持 反对

使用道具 举报

发表于 2025-8-19 14:19:02 | 显示全部楼层
就是截屏,输出像素是多少哟
回复 支持 反对

使用道具 举报

发表于 2025-8-19 17:56:14 | 显示全部楼层
谢谢版主的共享……
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-10-6 01:41 , Processed in 0.229004 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表