Forráskód Böngészése

蘭雅CPG更新支持 CorelDRAW 2026

蘭雅sRGB 6 napja
szülő
commit
eb5dbff5b6

BIN
09_BoundaryGroup/Makefile


+ 16 - 3
09_BoundaryGroup/ToolsBox.cpp

@@ -3,6 +3,7 @@
 #include "resource.h"
 #include <stdio.h>
 #include <windows.h>
+#include <wtypes.h>
 
 
 corel *cdr = NULL;
@@ -123,10 +124,22 @@ STDMETHODIMP ToolsBoxPlugin::raw_StartSession() {
   cdr = m_pApp;
   lycpg = this;
 
-  try {
-    m_pApp->AddPluginCommand(_bstr_t("OpenToolsBox"), _bstr_t("Tools Box"), _bstr_t("打开工具窗口"));
+  auto cmdbars = m_pApp->CommandBars;
+
+  try { // 尝试获取指定的CommandBar
+      auto pBar = cmdbars->Item[_bstr_t("LYCPG")];
+      pBar->Visible = TRUE;
+  }
+  catch(...)
+  {  // 如果不存在则创建
+    auto pBar = cmdbars->Add(_bstr_t("LYCPG"), VGCore::cuiBarFloating, VARIANT_FALSE);
+    pBar->Visible = TRUE;
+  }
 
-    VGCore::ICUIControlPtr ctl = m_pApp->CommandBars->Item[_bstr_t("Standard")]->Controls->AddCustomButton(VGCore::cdrCmdCategoryPlugins, _bstr_t("OpenToolsBox"), 10, VARIANT_FALSE);
+   try {
+    m_pApp->AddPluginCommand(_bstr_t("OpenToolsBox"), _bstr_t("Tools Box"), _bstr_t("蘭雅CPG插件"));
+    
+    VGCore::ICUIControlPtr ctl = m_pApp->CommandBars->Item[_bstr_t("LYCPG")]->Controls->AddCustomButton(VGCore::cdrCmdCategoryPlugins, _bstr_t("OpenToolsBox"), 1, VARIANT_FALSE);
     ctl->SetIcon2(_bstr_t("guid://d2fdc0d9-09f8-4948-944c-4297395c05b7"));
     m_lCookie = m_pApp->AdviseEvents(this);
   } catch (_com_error &e) {

+ 1 - 1
09_BoundaryGroup/WinData.cpp

@@ -1,4 +1,4 @@
-// WinData.c
+// WinData.c
 #include "WinData.h"
 #include <stdlib.h>
 #include <string.h>

+ 6 - 6
09_BoundaryGroup/WinData.h

@@ -5,14 +5,14 @@
 #include <stdio.h>
 
 typedef struct {
-    int x;  // x 鍧愭爣
-    int y;  // y 鍧愭爣
-    int w;  // 瀹藉害
-    int h;  // 楂樺害
-    double exp; // 瀹瑰樊鍊�
+    int x;  // x 坐标
+    int y;  // y 坐标
+    int w;  // 宽度
+    int h;  // 高度
+    double exp; // 容差值
 } WinData;
 
-// 鍑芥暟澹版槑
+// 函数声明
 void saveWinData(const char* filename, const WinData* win);
 WinData loadWinData(const char *filename, WinData win);
 

+ 209 - 0
src/BoundaryGroup.cpp

@@ -0,0 +1,209 @@
+#include "cdrapp.h"
+#include <cerrno>
+#include <cmath>
+#include <cstddef>
+
+bool isDPCurve(IVGShapePtr s) {
+  auto dpc = (s->Type == cdrRectangleShape) || (s->Type == cdrEllipseShape) ||
+             (s->Type == cdrCurveShape) || (s->Type == cdrPolygonShape) ||
+             (s->Type == cdrBitmapShape);
+  return dpc;
+}
+IVGShapePtr CreateBoundary(corel *cdr, IVGShapePtr s) {
+  IVGShapePtr scp;
+  if (cdr->VersionMajor < 17) {
+    // s->CreateSelection();
+    // cdr->FrameWork->Automation->InvokeItem( _bstr_t("b0491566-5ffe-450a-b17e-f2f496b4eb22"));
+    // scp = cdr->ActiveSelectionRange->Shapes->Item[1];
+    BoundingBox box;
+    s->GET_BOUNDING_BOX(box);
+    scp = cdr->ActiveLayer->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC);
+  } else {
+    //  这个 API X7 以上才支持,所以现在直接画矩形
+    scp = s->CreateBoundary(0, 0, true, false);    
+  }
+  return scp;
+}
+
+// VGCore::IVGShapePtr VGCore::IVGShape::CreateBoundary ( double x, double y, VARIANT_BOOL PlaceOnTop, VARIANT_BOOL DeleteSource ); VGCore::IVGShapePtr
+// VGCore::IVGShapeRange::CreateBoundary ( double x, double y, VARIANT_BOOL PlaceOnTop, VARIANT_BOOL DeleteSource );
+// VARIANT_BOOL VGCore::IVGCurve::IntersectsWith ( struct IVGCurve * Curve )
+bool isIntWith(corel *cdr, IVGShape *s1, IVGShape *s2) {
+  bool isIn = false;
+  if (isDPCurve(s1) && isDPCurve(s2)) {
+    isIn = s1->GetDisplayCurve()->IntersectsWith(s2->GetDisplayCurve());
+  } else if (isDPCurve(s1)) {
+    // 群组文字和OLE等其他类型,创建一个临时边界范围
+    auto scp = CreateBoundary(cdr, s2);
+    isIn = s1->GetDisplayCurve()->IntersectsWith(scp->GetDisplayCurve());
+    scp->Delete();
+
+  } else if (isDPCurve(s2)) {
+    auto scp = CreateBoundary(cdr, s1);
+    isIn = scp->GetDisplayCurve()->IntersectsWith(s2->GetDisplayCurve());
+    scp->Delete();
+
+  } else {
+    auto scp = CreateBoundary(cdr, s1);
+    auto scp2 = CreateBoundary(cdr, s2);
+    isIn = scp->GetDisplayCurve()->IntersectsWith(scp2->GetDisplayCurve());
+    scp->Delete();
+    scp2->Delete();
+  }
+  return isIn;
+}
+
+// 从矩形边界坐标 获得中心坐标
+void calculate_center(const BoundingBox &box, double &cx, double &cy) {
+  cx = box.x + (box.w / 2);
+  cy = box.y + (box.h / 2);
+}
+
+// VGCore::cdrPositionOfPointOverShape VGCore::IVGShape::IsOnShape ( double x, double y, double HotArea );
+// VGCore::cdrPositionOfPointOverShape VGCore::IVGCurve::IsOnCurve ( double x, double y, double HotArea );
+
+bool BoundaryGroup(corel *cdr, IVGShapeRange *sr, IVGShapeRange *srs) {
+
+  if (sr->Count < 2)
+    return false;
+
+  BoundingBox box, bound_box;
+  double x, y;
+  int OnSh = 0;
+  auto red = cdr->CreateCMYKColor(0, 100, 100, 0);
+
+  // 处理文字和影响的物件
+  auto txtbox = cdr->CreateShapeRange();
+  auto sr_text =
+      sr->Shapes->FindShapes(_bstr_t(), cdrTextShape, VARIANT_TRUE, _bstr_t());
+  if (sr_text->Count > 0) {
+    auto al = cdr->ActiveLayer;
+    for (auto i = 0; i != sr_text->Count; i++) {
+      sr_text->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box);
+      auto s = al->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC);
+      txtbox->Add(s);
+    }
+    sr->AddRange(txtbox);
+  }
+
+
+  // auto stmp = sr->CreateBoundary(0, 0, true, false); // 建立异性边界物件
+  // auto ef1 = stmp->CreateContour(
+  //     cdrContourOutside, 0.2, 1, cdrDirectFountainFillBlend, red, NULL, NULL, 0,
+  //     0, cdrContourSquareCap, cdrContourCornerMiteredOffsetBevel, 15);
+
+  // auto bounds = ef1->Separate();
+  // stmp->Delete();
+  // // bounds->SetOutlineProperties(0.076, NULL, cdr->CreateCMYKColor(100, 50, 0,
+  // // 0), NULL, NULL, cdrUndefined,  cdrUndefined, cdrOutlineUndefinedLineCaps,
+  // // cdrOutlineUndefinedLineJoin, NULL, NULL, NULL, NULL, NULL);
+
+  // auto sbox = bounds->BreakApartEx();
+  // sbox->ApplyUniformFill(red);
+
+
+  // 建立辅助的异性边界物件,需要填充颜色,搞了半天才搞定
+  IVGShapePtr bounds;
+  if (cdr->VersionMajor < 17) {
+    sr->CreateSelection();
+    cdr->FrameWork->Automation->InvokeItem( _bstr_t("b0491566-5ffe-450a-b17e-f2f496b4eb22"));
+    bounds = cdr->ActiveSelectionRange->Shapes->Item[1];
+    bounds->OrderToFront();
+  } else {
+    bounds = sr->CreateBoundary(0, 0, true, false); // 建立异性边界物件  
+  }
+
+  bounds->Fill->UniformColor->RGBAssign(255, 0, 0);
+  auto sbox = bounds->BreakApartEx(); // 把边界 拆分为多个边界 用来分组
+
+  if (sbox->Count > 2) {
+    //  VGCore::IVGShapeRange::Sort ( _bstr_t CompareExpression, long
+    //  StartIndex, long EndIndex, const _variant_t & Data );
+    sbox->Sort(bstr_t( "@shape1.width * @shape1.height > @shape2.width * @shape2.height"),  1, sbox->Count, _variant_t());
+  }
+
+  // 删除文字添加的方框
+  if (sr_text->Count > 0) {
+    sr->RemoveRange(txtbox);
+    txtbox->Delete();
+  }
+
+  // 按照边界框异形范围进行分组群组
+  auto srgp = cdr->CreateShapeRange();
+
+  for (int k = 0; k < sbox->Count && sr->Count; k++) {
+    sbox->Shapes->Item[k + 1]->GET_BOUNDING_BOX(bound_box);
+
+    for (int i = 0; i < sr->Count; i++) {
+      auto sh = sr->Shapes->Item[i + 1];
+      sh->GET_BOUNDING_BOX(box);   // 获得物件矩形边界坐标
+      calculate_center(box, x, y); // 获得物件中心坐标
+      OnSh = sbox->Shapes->Item[k + 1]->IsOnShape(x, y, -1);
+
+      if (OnSh) {
+        srgp->Add(sh);
+      } else if (isOverlapped(box, bound_box)) {
+        if (isIntWith(cdr, sbox->Shapes->Item[k + 1], sh))
+          srgp->Add(sh);
+      }
+    }
+
+    // 从Range中移除已分组的图形
+    sr->RemoveRange(srgp);
+    if (srgp->Count > 1) {
+      srs->Add(srgp->Group());
+    } else {
+      srs->AddRange(srgp);
+    }
+    srgp->RemoveAll();
+  }
+
+  // 删除辅助的异性边界物件
+  if(!debug_flg)
+    sbox->Delete();
+  return true;
+}
+
+// 测试运行 异形群组
+void run_BoundaryGroup(corel *cdr) {
+  auto start = std::chrono::high_resolution_clock::now(); // 开始时间
+  // if (cdr->VersionMajor < 17) {
+  //   sprintf(infobuf, "异形群组目前只支持X7以上版本!");  return; }
+
+  BeginOpt(cdr);
+
+  auto sr = cdr->ActiveSelectionRange;
+  auto srs = cdr->CreateShapeRange();
+  auto sr_box = cdr->CreateShapeRange();
+
+  int cnt = sr->Count;
+
+  // 取消选择,速度优化
+  cdr->ActiveDocument->ClearSelection();
+
+  if (cnt > 300) {
+    // 调用矩形分组,分步执行异形群组
+    if (BoxGrouping(cdr, sr, sr_box, 0.1)) {
+      for (int i = 0; i < sr_box->Count; i++) {
+        auto s = sr_box->Shapes->Item[i + 1];
+        if (!s->IsSimpleShape) {
+          auto sr2 = s->UngroupEx();
+          BoundaryGroup(cdr, sr2, srs);
+        }
+      }
+    }
+  } else {
+    BoundaryGroup(cdr, sr, srs);
+  }
+
+  srs->CreateSelection();
+
+  // 计算持续时间
+  double runtime = 0.0;
+  auto end = std::chrono::high_resolution_clock::now();
+  std::chrono::duration<double> duration = end - start;
+  runtime = duration.count();
+
+  sprintf(infobuf, "选择物件: %d 个进行异形群组\n群组: %d 组, 时间: %.2f秒", cnt, srs->Count, runtime);
+  EndOpt(cdr);
+}

BIN
src/LYVBA.ico


BIN
src/Makefile


+ 416 - 0
src/ToolsBox.cpp

@@ -0,0 +1,416 @@
+#include "cdrapi.h"
+#include "cdrapp.h"
+#include "resource.h"
+#include <stdio.h>
+#include <windows.h>
+#include <wtypes.h>
+
+
+corel *cdr = NULL;
+static HINSTANCE g_hResource = NULL;
+HICON  g_hIcon;         // 窗口图标句柄
+bool debug_flg = false; // 调试->高级模式
+char infobuf[256] = {0};
+BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
+  if (fdwReason == DLL_PROCESS_ATTACH) {
+    g_hResource = (HINSTANCE)hinstDLL;
+  }
+  return TRUE;
+}
+
+class ToolsBoxPlugin : public VGCore::IVGAppPlugin {
+private:
+  volatile ULONG m_ulRefCount;
+  long m_lCookie;
+  static intptr_t CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+public:
+  ToolsBoxPlugin();
+  VGCore::IVGApplication *m_pApp;
+  void OpenToolsBox();
+
+  // IUnknown
+public:
+  STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
+  STDMETHOD_(ULONG, AddRef)(void) { return ++m_ulRefCount; }
+  STDMETHOD_(ULONG, Release)(void) {
+    ULONG ulCount = --m_ulRefCount;
+    if (ulCount == 0) {
+      delete this;
+    }
+    return ulCount;
+  }
+
+  // IDispatch
+public:
+  STDMETHOD(GetTypeInfoCount)(UINT *pctinfo) { return E_NOTIMPL; }
+  STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) {
+    return E_NOTIMPL;
+  }
+  STDMETHOD(GetIDsOfNames)
+  (REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) {
+    return E_NOTIMPL;
+  }
+  STDMETHOD(Invoke)
+  (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
+
+  // IVGAppPlugin
+public:
+  STDMETHOD(raw_OnLoad)(VGCore::IVGApplication *Application);
+  STDMETHOD(raw_StartSession)();
+  STDMETHOD(raw_StopSession)();
+  STDMETHOD(raw_OnUnload)();
+};
+
+ToolsBoxPlugin::ToolsBoxPlugin() {
+  m_pApp = NULL;
+  m_lCookie = 0;
+  m_ulRefCount = 1;
+}
+
+STDMETHODIMP ToolsBoxPlugin::QueryInterface(REFIID riid, void **ppvObject) {
+  HRESULT hr = S_OK;
+  m_ulRefCount++;
+  if (riid == IID_IUnknown) {
+    *ppvObject = (IUnknown *)this;
+  } else if (riid == IID_IDispatch) {
+    *ppvObject = (IDispatch *)this;
+  } else if (riid == __uuidof(VGCore::IVGAppPlugin)) {
+    *ppvObject = (VGCore::IVGAppPlugin *)this;
+  } else {
+    m_ulRefCount--;
+    hr = E_NOINTERFACE;
+  }
+  return hr;
+}
+
+STDMETHODIMP ToolsBoxPlugin::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) {
+  switch (dispIdMember) {
+
+  case 0x0014: // DISPID_APP_ONPLUGINCMD
+    if (pDispParams != NULL && pDispParams->cArgs == 1) {
+      _bstr_t strCmd(pDispParams->rgvarg[0].bstrVal);
+      if (strCmd == _bstr_t("OpenToolsBox")) {
+        //   MessageBox(NULL, _bstr_t("OpenToolsBox"), _bstr_t("OpenToolsBox"),
+        //   MB_ICONSTOP);
+        OpenToolsBox();
+      }
+    }
+    break;
+
+  case 0x0015: // DISPID_APP_ONPLUGINCMDSTATE
+    if (pDispParams != NULL && pDispParams->cArgs == 3) {
+      _bstr_t strCmd(pDispParams->rgvarg[2].bstrVal);
+      if (strCmd == _bstr_t("OpenToolsBox")) {
+        *pDispParams->rgvarg[1].pboolVal = VARIANT_TRUE;
+      }
+    }
+    break;
+  }
+  return S_OK;
+}
+
+STDMETHODIMP ToolsBoxPlugin::raw_OnLoad(VGCore::IVGApplication *Application) {
+  m_pApp = Application;
+  if (m_pApp) {
+    m_pApp->AddRef();
+  }
+  return S_OK;
+}
+
+ToolsBoxPlugin* lycpg = nullptr;
+STDMETHODIMP ToolsBoxPlugin::raw_StartSession() {
+  // 接口转交给cdr
+  cdr = m_pApp;
+  lycpg = this;
+
+  auto cmdbars = m_pApp->CommandBars;
+
+  try { // 尝试获取指定的CommandBar
+      auto pBar = cmdbars->Item[_bstr_t("LYCPG")];
+      pBar->Visible = TRUE;
+  }
+  catch(...)
+  {  // 如果不存在则创建
+    auto pBar = cmdbars->Add(_bstr_t("LYCPG"), VGCore::cuiBarFloating, VARIANT_FALSE);
+    pBar->Visible = TRUE;
+  }
+
+   try {
+    m_pApp->AddPluginCommand(_bstr_t("OpenToolsBox"), _bstr_t("Tools Box"), _bstr_t("蘭雅CPG插件"));
+    
+    VGCore::ICUIControlPtr ctl = m_pApp->CommandBars->Item[_bstr_t("LYCPG")]->Controls->AddCustomButton(VGCore::cdrCmdCategoryPlugins, _bstr_t("OpenToolsBox"), 1, VARIANT_FALSE);
+    ctl->SetIcon2(_bstr_t("guid://d2fdc0d9-09f8-4948-944c-4297395c05b7"));
+    m_lCookie = m_pApp->AdviseEvents(this);
+  } catch (_com_error &e) {
+    MessageBox(NULL, e.Description(), _bstr_t("Error"), MB_ICONSTOP);
+  }
+  return S_OK;
+}
+
+STDMETHODIMP ToolsBoxPlugin::raw_StopSession() {
+  try {
+    m_pApp->UnadviseEvents(m_lCookie);
+    m_pApp->RemovePluginCommand(_bstr_t("OpenToolsBox"));
+  } catch (_com_error &e) {
+    MessageBox(NULL, e.Description(), _bstr_t("Error"), MB_ICONSTOP);
+  }
+  return S_OK;
+}
+
+STDMETHODIMP ToolsBoxPlugin::raw_OnUnload() {
+  if (m_pApp) {
+    m_pApp->Release();
+    m_pApp = NULL;
+  }
+  return S_OK;
+}
+
+void ToolsBoxPlugin::OpenToolsBox() {
+  m_pApp->StartupMode = VGCore::cdrStartupDoNothing;
+
+  intptr_t nHandle = m_pApp->AppWindow->Handle;
+  HWND hAppWnd = reinterpret_cast<HWND>(nHandle);
+
+  // 创建非模态对话框
+  HWND hDlgWnd = CreateDialogParam(g_hResource, MAKEINTRESOURCE(IDD_TOOLS_BOX), hAppWnd, DlgProc, (LPARAM)m_pApp);
+  // 在创建对话框之前存储 m_pApp 指针
+  SetWindowLongPtr(hDlgWnd, DWLP_USER, (LONG_PTR)m_pApp);
+
+  // 获取屏幕的宽度和高度
+  RECT rect;
+  GetWindowRect(GetDesktopWindow(), &rect);
+  int screenWidth = rect.right - rect.left;
+  int screenHeight = rect.bottom - rect.top;
+
+  // 计算对话框窗口的宽度和高度
+  RECT dlgRect;
+  GetWindowRect(hDlgWnd, &dlgRect);
+  int w = dlgRect.right - dlgRect.left;
+  int h = dlgRect.bottom - dlgRect.top;
+
+  // 计算对话框窗口的左上角坐标,使其居中显示
+  int x = (screenWidth - w) / 2;
+  int y = (screenHeight - h) / 2;
+
+  double exp = 0.0; // 默认初始容差值
+
+  // 创建窗口数据实例      // 从文件加载
+  WinData win = {x, y, w, h, exp};
+  win = loadWinData("window.dat", win);
+
+  // 设置对话框窗口的位置
+  SetWindowPos(hDlgWnd, NULL, win.x, win.y, win.w, win.h, SWP_NOZORDER | SWP_NOACTIVATE);
+  // 设置对话框窗口的父窗口  // #define GWL_HWNDPARENT      (-8)
+  SetWindowLong(hDlgWnd, -8, (LONG)hAppWnd);
+
+  // 设置容差值 文本框的数值
+  char expbuf[64] = {0};
+  sprintf(expbuf, "%.1f", win.exp);
+  SetWindowText(::GetDlgItem(hDlgWnd, EXP_TEXT), expbuf); // 设置为需要的数值
+
+  // 显示对话框窗口
+  ShowWindow(hDlgWnd, SW_SHOW);
+
+  // 使用 g_hResource 作为 HINSTANCE
+  g_hIcon = ::LoadIcon(g_hResource, MAKEINTRESOURCE(IDI_ICON1));
+  // 小图标:就是窗口左上角对应的那个图标
+  ::SendMessage(hDlgWnd, WM_SETICON, ICON_SMALL, (LPARAM)g_hIcon);
+
+}
+
+// MessageBox(NULL, "更新提示信息: 激活CorelDRAW窗口", "CPG代码测试", MB_ICONSTOP);
+#define UPDATE_INFO_ACTIVE_CDRWND                                              \
+  PutTextValue(hDlg, INFO_TEXT, infobuf);                                      \
+  Active_CorelWindows(hDlg);
+intptr_t CALLBACK ToolsBoxPlugin::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+  // 从附加数据中获取 m_pApp 指针
+  VGCore::IVGApplication *cdr = reinterpret_cast<VGCore::IVGApplication *>(
+      GetWindowLongPtr(hDlg, DWLP_USER));
+
+  if (uMsg == WM_COMMAND) {
+    try {
+      switch (LOWORD(wParam)) {
+
+      case ID_BOUNDARY_GROUP: {
+
+        if (BST_CHECKED == IsDlgButtonChecked(hDlg, DEBUG_FLG))
+          debug_flg = true;
+        else
+          debug_flg = false;
+        double exp = GetTextValue(hDlg, EXP_TEXT);
+
+        run_BoundaryGroup(cdr);
+        UPDATE_INFO_ACTIVE_CDRWND
+      } break;
+
+      case IDC_BOX_GROUP: {
+        double exp = GetTextValue(hDlg, EXP_TEXT);
+        AutoMakeSelection(cdr);
+        Box_AutoGroup(cdr, exp);
+        UPDATE_INFO_ACTIVE_CDRWND
+
+      } break;
+
+      case IDC_CQL_OUTLINE:
+        cql_OutlineColor(cdr);
+
+        UPDATE_INFO_ACTIVE_CDRWND
+        break;
+
+      case IDC_CQL_FILL:
+        cql_FillColor(cdr);
+
+        UPDATE_INFO_ACTIVE_CDRWND
+        break;
+
+      case IDC_CQL_SIZE: {
+        double exp = GetTextValue(hDlg, EXP_TEXT);
+        cql_SameSize(cdr, exp);
+        UPDATE_INFO_ACTIVE_CDRWND
+      } break;
+
+      case IDC_DRAW_RECT: {
+        double exp = GetTextValue(hDlg, EXP_TEXT);
+        AutoMakeSelection(cdr);
+        BBox_DrawRectangle(cdr, exp);
+
+        UPDATE_INFO_ACTIVE_CDRWND
+      } break;
+
+      case IDC_SR_FLIP:
+        Shapes_Filp(cdr);
+      break;
+
+      case IDC_CDR2AI: {
+        CdrCopy_to_AdobeAI(cdr);
+        sprintf(infobuf, "把CorelDRAW软件中选择物件复制到剪贴板,请切换到AI软件粘贴");
+        UPDATE_INFO_ACTIVE_CDRWND
+      } break;
+
+      case IDC_AI2CDR: {
+        AdobeAI_Copy_ImportCdr(cdr);
+        sprintf(infobuf, "请先在AI软件选择物件复制,再切换到CorelDRAW软件点执行本功能");
+        UPDATE_INFO_ACTIVE_CDRWND
+      } break;
+
+      case IDC_SetFontCN: {
+        setFontChinese(cdr);
+        sprintf(infobuf, "CorelDRAW CPG 统一中英文字体");
+        UPDATE_INFO_ACTIVE_CDRWND
+      } break;
+
+      case IDC_Copy1KOBJ: {
+        double distance = GetTextValue(hDlg, EXP_TEXT);
+        sprintf(infobuf, "极速将选定对象复制1000次的工具");
+        Copy_1K_Objects(cdr, distance);
+        UPDATE_INFO_ACTIVE_CDRWND
+      } break;
+
+      case IDC_SAVEX4CDR: {
+      
+        // if (SaveAs_X4CDR(cdr, filePath)) {
+      sprintf(infobuf, "还在调试中,请期待; 只支持CorelDRAW 2020和之下版本保存CDRX4格式");
+        // } 
+
+      UPDATE_INFO_ACTIVE_CDRWND  
+      } break;
+
+
+
+//////////// 窗口扩展、最小化、恢复按钮按钮////////////////////////////////////////////////
+      case EXPAND_TOOLS: {
+        // 获取当前窗口的句柄
+        HWND hwnd = GetActiveWindow();
+        // 获取当前窗口的矩形区域
+        RECT rect;
+        GetWindowRect(hwnd, &rect);
+        // 计算新的宽度
+        int newWidth = rect.right - rect.left + 120; // 增加120单位
+        // 移动窗口到新的大小
+        SetWindowPos(hwnd, NULL, rect.left, rect.top, newWidth, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
+        // 隐藏按钮 (假设按钮的句柄为 buttonHandle)
+        ShowWindow(::GetDlgItem(hDlg, EXPAND_TOOLS), SW_HIDE);
+      } break;
+
+      case MIN_TOOLS: {
+        RECT rect;
+        GetWindowRect(hDlg, &rect);
+        int currentWidth = rect.right - rect.left;
+        int currentHeight = rect.bottom - rect.top;
+        int h = 98;
+        SetWindowPos(hDlg, NULL, rect.left, rect.top, currentWidth, h, SWP_NOZORDER | SWP_NOACTIVATE);
+        ShowWindow(::GetDlgItem(hDlg, MIN_TOOLS), SW_HIDE);
+        double exp = GetTextValue(hDlg, EXP_TEXT);
+
+        int x = rect.left;
+        int y = rect.top;
+        int w = currentWidth;
+        // 保存窗口位置
+        WinData win = {x, y, w, h, exp};
+        saveWinData("window.dat", &win);
+      } break;
+
+      case RENEW_TOOLS: {
+        RECT rect;
+        GetWindowRect(hDlg, &rect);
+        int x = rect.left;
+        int y = rect.top;
+        int h = 240; // 恢复宽高
+        int w = 220;
+        SetWindowPos(hDlg, NULL, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE);
+        ShowWindow(::GetDlgItem(hDlg, MIN_TOOLS), !SW_HIDE);
+        ShowWindow(::GetDlgItem(hDlg, EXPAND_TOOLS), !SW_HIDE);
+        double exp = GetTextValue(hDlg, EXP_TEXT);
+
+        // 保存窗口位置
+        WinData win = {x, y, w, h, exp};
+        saveWinData("window.dat", &win);
+
+      } break;
+
+      case IDOK:
+        break;
+
+       // 关闭CPG插件,保存窗口位置
+      case IDCANCEL:{
+
+        RECT rect;
+        GetWindowRect(hDlg, &rect);
+        int w = rect.right - rect.left;
+        int h = rect.bottom - rect.top;
+        int x = rect.left;
+        int y = rect.top;
+        double exp = GetTextValue(hDlg, EXP_TEXT);
+
+        // 保存窗口位置
+        WinData win = {x, y, w, h, exp};
+        saveWinData("window.dat", &win);
+
+        EndDialog(hDlg, 0);
+      } break;
+
+      }
+
+    } catch (_com_error &e) {
+      MessageBox(NULL, e.Description(), "Error", MB_ICONSTOP);
+      EndOpt(cdr);
+    }
+
+  } else if (uMsg == WM_INITDIALOG) {
+    SetWindowText(::GetDlgItem(hDlg, EXP_TEXT), "0");
+    return 1;
+  }
+  return 0;
+}
+
+extern "C" __declspec(dllexport) DWORD APIENTRY AttachPlugin(VGCore::IVGAppPlugin **ppIPlugin) {
+  *ppIPlugin = new ToolsBoxPlugin;
+  return 0x100;
+}
+
+void open_lycpg() {
+    if (lycpg) {
+        lycpg->OpenToolsBox(); // 使用类的实例调用成员函数
+    }
+}

+ 49 - 0
src/ToolsBox.rc

@@ -0,0 +1,49 @@
+// Generated by ResEdit 1.6.6
+// Copyright (C) 2006-2015
+// http://www.resedit.net
+
+#include <windows.h>
+#include <commctrl.h>
+#include <richedit.h>
+#include "resource.h"
+
+
+
+
+//
+// Dialog resources
+//
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+IDD_TOOLS_BOX DIALOGEX 0, 0, 137, 125
+STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_POPUP | WS_SYSMENU
+CAPTION "蘭雅 CPG 插件 福利群版"
+FONT 8, "MS Shell Dlg", 135, 0, 1
+{
+    AUTOCHECKBOX    "调试->高级模式", DEBUG_FLG, 142, 8, 70, 8, 0, WS_EX_LEFT
+    CTEXT           "蘭雅 CorelDRAW CPG 插件\n2026.03.05 版", INFO_TEXT, 5, 104, 92, 17, SS_CENTER, WS_EX_LEFT
+    PUSHBUTTON      "方框智能群组", IDC_BOX_GROUP, 69, 2, 56, 20, 0, WS_EX_LEFT
+    PUSHBUTTON      "CQL轮廓色相同", IDC_CQL_OUTLINE, 4, 62, 59, 19, 0, WS_EX_LEFT
+    PUSHBUTTON      "边界画矩形", IDC_DRAW_RECT, 69, 42, 56, 19, 0, WS_EX_LEFT
+    PUSHBUTTON      "批量镜像", IDC_SR_FLIP, 69, 62, 56, 19, 0, WS_EX_LEFT
+    PUSHBUTTON      "CQL颜色相同", IDC_CQL_FILL, 4, 82, 59, 19, 0, WS_EX_LEFT
+    PUSHBUTTON      "CQL尺寸相同", IDC_CQL_SIZE, 69, 82, 56, 19, 0, WS_EX_LEFT
+    PUSHBUTTON      "CDR复制到AI", IDC_CDR2AI, 4, 22, 59, 19, 0, WS_EX_LEFT
+    PUSHBUTTON      "AI粘贴到CDR", IDC_AI2CDR, 4, 42, 59, 19, 0, WS_EX_LEFT
+    LTEXT           "容差:(mm)", EXP_LT, 66, 28, 41, 8, SS_LEFT, WS_EX_LEFT
+    EDITTEXT        EXP_TEXT, 102, 25, 22, 14, NOT WS_TABSTOP | ES_AUTOHSCROLL, WS_EX_LEFT
+    PUSHBUTTON      "异形群组", ID_BOUNDARY_GROUP, 4, 2, 59, 20, 0, WS_EX_LEFT
+    PUSHBUTTON      "∨", RENEW_TOOLS, 125, 23, 12, 17, BS_NOTIFY, WS_EX_LEFT
+    PUSHBUTTON      "∧", MIN_TOOLS, 125, 6, 12, 17, BS_NOTIFY, WS_EX_LEFT
+    PUSHBUTTON      ">", EXPAND_TOOLS, 125, 57, 12, 28, BS_NOTIFY, WS_EX_LEFT
+    PUSHBUTTON      "保存X4 CDR版", IDC_SAVEX4CDR, 142, 23, 56, 19, 0, WS_EX_LEFT
+    PUSHBUTTON      "极速矩阵复制", IDC_Copy1KOBJ, 200, 23, 56, 19, 0, WS_EX_LEFT
+    PUSHBUTTON      "统一中英字体", IDC_SetFontCN, 143, 45, 56, 19, 0, WS_EX_LEFT
+}
+
+
+
+//
+// Icon resources
+//
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+IDI_ICON1          ICON           ".\\LYVBA.ico"

+ 57 - 0
src/WinData.cpp

@@ -0,0 +1,57 @@
+// WinData.c
+#include "WinData.h"
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+#define MAX_PATH_LENGTH 260
+
+char dirPath[MAX_PATH_LENGTH];
+char* GetUserDir(const char* dirName) {
+  char userProfile[MAX_PATH_LENGTH];
+
+  if (GetEnvironmentVariable("USERPROFILE", userProfile, MAX_PATH_LENGTH) == 0) {
+    return NULL;
+  }
+  // 构建指定目录的完整路径
+  snprintf(dirPath, sizeof(dirPath), "%s\\%s", userProfile, dirName);
+
+  // 检查目录是否存在
+  DWORD ftyp = GetFileAttributes(dirPath);
+  if (ftyp == INVALID_FILE_ATTRIBUTES) {
+    if (CreateDirectory(dirPath, NULL) ||
+        GetLastError() == ERROR_ALREADY_EXISTS) {
+      printf("目录 '%s' 创建成功或已经存在。\n", dirPath);
+    } else {
+      return NULL;
+    }
+  }
+  return dirPath;
+}
+
+void saveWinData(const char *filename, const WinData *win) {
+  char* dir = GetUserDir("lyvba");
+  char bufile[MAX_PATH_LENGTH];
+  sprintf(bufile, "%s\\%s", dir, filename);
+  FILE *file = fopen(bufile, "wb");
+  if (!file) {
+    //  perror("无法打开文件进行写入");
+    return;
+  }
+  fwrite(win, sizeof(WinData), 1, file);
+  fclose(file);
+}
+
+WinData loadWinData(const char *filename, WinData win) {
+  char* dir = GetUserDir("lyvba");
+  char bufile[MAX_PATH_LENGTH];
+  sprintf(bufile, "%s\\%s", dir, filename);
+
+  FILE *file = fopen(bufile, "rb");
+  if (!file) {
+    return win; 
+  }
+  fread(&win, sizeof(WinData), 1, file);
+  fclose(file);
+  return win;
+}

+ 19 - 0
src/WinData.h

@@ -0,0 +1,19 @@
+// WinData.h
+#ifndef WINDATA_H
+#define WINDATA_H
+
+#include <stdio.h>
+
+typedef struct {
+    int x;  // x 坐标
+    int y;  // y 坐标
+    int w;  // 宽度
+    int h;  // 高度
+    double exp; // 容差值
+} WinData;
+
+// 函数声明
+void saveWinData(const char* filename, const WinData* win);
+WinData loadWinData(const char *filename, WinData win);
+
+#endif // WINDATA_H

+ 248 - 0
src/boxAutoGroup.cpp

@@ -0,0 +1,248 @@
+#include "cdrapp.h"
+
+// 扩展边界框
+void expand_bounding_boxes(std::vector<BoundingBox>& boxes, double exp) {
+    for (auto& box : boxes) {
+        // 扩展宽度和高度
+        box.w += 2 * exp; // 左右各扩展
+        box.h += 2 * exp; // 上下各扩展
+        // 调整左下角坐标
+        box.x -= exp; // 向左扩展
+        box.y -= exp; // 向下扩展
+    }
+}
+
+double get_bounding_box_area(BoundingBox box) { return box.w * box.h; }
+
+// 自定义比较函数,按 BoundingBox 的面积大小进行排序
+bool compare_bounding_boxes(const std::pair<int, BoundingBox> &a,
+                            const std::pair<int, BoundingBox> &b) {
+  return get_bounding_box_area(a.second) > get_bounding_box_area(b.second);
+}
+
+// 查找父节点
+int find(std::vector<int>& parent, int x) {
+    if (parent[x] != x) {
+        parent[x] = find(parent, parent[x]);
+    }
+    return parent[x];
+}
+
+// 合并两个集合
+void unionSet(std::vector<int>& parent, int x, int y) {
+    int xroot = find(parent, x);
+    int yroot = find(parent, y);
+    parent[xroot] = yroot;
+}
+// 检查两个矩形是否重叠
+bool isOverlapped(const BoundingBox &a, const BoundingBox &b) {
+  return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
+} // 函数使用AABB(Axis-Aligned Bounding Box)碰撞检测
+
+bool BBox_DrawRectangle(corel *cdr, double exp) {
+  BoundingBox box;
+  auto sr = cdr->ActiveSelectionRange; // 获得选择范围
+  auto al = cdr->ActiveVirtualLayer;          // 虚拟物件虚拟层
+  if (!sr || !al) return false;
+  
+  BeginOpt(cdr);
+  auto srs = cdr->CreateShapeRange();
+
+  // CorelDRAW Shapes 物件 Item 编号从1开始
+  for (auto i = 0; i != sr->Count; i++) {
+    sr->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box); // 获得Shapes的BoundingBox,赋值到box
+    if (fabs(exp) > 0.02 ) { box.w += 2 * exp; box.h += 2 * exp; box.x -= exp; box.y -= exp; }
+    
+    auto s = al->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC); // 使用BoundingBox box 创建一个矩形
+    s->Outline->Color->RGBAssign(0, 255, 0);
+    srs->Add(s);
+  }
+
+  cdr->ActiveDocument->LogCreateShapeRange(srs);  // 虚拟物件添加到文档中
+  srs->CreateSelection();
+  
+  sprintf(infobuf, "提示: 标记画框数量: %d 个\n容差值请使用小键盘输入", srs->Count);
+  EndOpt(cdr);
+  return true;
+}
+
+bool AutoMakeSelection(corel *cdr) {
+  auto sr = cdr->ActiveSelectionRange; 
+  if (0 == sr->Count) {
+    auto all = cdr->ActiveDocument->ActivePage->Shapes->All();
+    all->CreateSelection();
+  }
+  return true;
+}
+
+// 快速分组重叠的区域, 使用算法"Union-Find" 算法。这个算法可以有效地处理这种并集问题。
+// 算法的时间复杂度为 O(n^2),其中 n 是矩形的数量。如果矩形数量较多,可以考虑使用更高效的算法,
+// 例如使用四叉树(Quadtree)或者区间树(Interval Tree)等数据结构来加速计算。
+bool Box_AutoGroup(corel *cdr, double exp) {
+  BoundingBox box;
+
+  auto sr = cdr->ActiveSelectionRange; // 获得选择范围
+  auto al = cdr->ActiveLayer;          // 获得当前层
+  if (!sr || !al) return false;
+
+  auto start = std::chrono::high_resolution_clock::now(); // 开始时间
+  BeginOpt(cdr);
+
+  std::vector<BoundingBox> boxes;
+  std::vector<int> parent;
+
+  // CorelDRAW Shapes 物件 Item 编号从1开始
+  for (auto i = 0; i != sr->Count; i++) {
+    sr->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box);
+    boxes.push_back(box);
+    parent.push_back(i);
+  }
+
+  // 扩展边界框,或者收缩边界框
+  if (fabs(exp) > 0.02 ) {
+    expand_bounding_boxes(boxes, exp);
+  }
+
+  // 实现 Union-Find 算法来合并重叠的区域
+  for (int i = 0; i < boxes.size(); i++) {
+    for (int j = i + 1; j < boxes.size(); j++) {
+      if (isOverlapped(boxes[i], boxes[j])) {
+        unionSet(parent, i, j);
+      }
+    }
+  }
+
+  double runtime[2] = {0,0};
+  auto end = std::chrono::high_resolution_clock::now(); 
+  std::chrono::duration<double> duration = end - start;
+  runtime[0] = duration.count();
+
+ // 输出分组结果到文件
+  // std::ofstream output_file("D:\\group.txt");
+  // if (output_file.is_open()) {
+  //     std::map<int, std::vector<int>> groups;
+  //     for (int i = 0; i < parent.size(); i++) {
+  //         int root = find(parent, i);
+  //         groups[root].push_back(i + 1); // CorelDRAW Shapes 物件 Item 编号从1开始
+  //     }
+
+  //     for (const auto& group : groups) {
+  //         output_file << "Group: ";
+  //         for (int index : group.second) {
+  //             output_file << index << " ";
+  //         }
+  //         output_file << std::endl;
+  //     }
+
+  //   auto end = std::chrono::high_resolution_clock::now(); // 结束时间
+  //   // 计算持续时间
+  //   std::chrono::duration<double> duration = end - start;
+  //   output_file << "Execution time: " << duration.count() << " seconds\n";
+
+  //   output_file.close();
+  // } 
+
+  // 输出分组结果
+  std::map<int, std::vector<int>> groups;
+  for (int i = 0; i < parent.size(); i++) {
+    int root = find(parent, i);
+    groups[root].push_back(i + 1); // CorelDRAW Shapes 物件 Item 编号从1开始
+  }
+
+  auto srgp = cdr->CreateShapeRange();
+  auto srs = cdr->CreateShapeRange();
+
+  cdr->ActiveDocument->ClearSelection();
+// 原来 没有取消选择 最初速度
+// Execution time: 63.0305 seconds
+
+// srgp->GET_BOUNDING_BOX(box); 
+// al->CreateRectangle2(box.x, box.y, box.w, box.h, ZERO_4PC); // 使用边界 创建一个矩形
+// box边界 转左上和右下坐标 box.x, box.y + box.h, box.x + box.w, box.y
+// auto sh = cdr->ActivePage->SelectShapesFromRectangle(box.x, box.y + box.h, box.x + box.w, box.y, false);
+// sh->Group();
+// 使用 SelectShapesFromRectangle 框选的形状进行群组
+// Execution time: 2.44753 seconds
+
+// cdr->ActiveDocument->ClearSelection(); // 使用取消选择
+// Execution time: 1.7432 seconds
+
+// srgp->CreateSelection();
+// cdr->ActiveSelectionRange->Group();
+// Execution time: 1.87662 seconds
+
+  // 分组分别进行群组
+  for (const auto& group : groups) {
+      for (int index : group.second) 
+        srgp->Add(sr->Shapes->Item[index]);
+      
+      if(sr->Count >1)
+        srs->Add(srgp->Group());
+      else
+        srs->AddRange(srgp);  
+
+      srgp->RemoveAll();
+  }
+  srs->CreateSelection();
+
+  // 计算持续时间
+  duration = std::chrono::high_resolution_clock::now() - start;
+  runtime[1] = duration.count();
+
+  sprintf(infobuf, "选择物件: %d 个, 分组: %.2f秒\n总共群组: %d 组, 总时间: %.2f秒", sr->Count, runtime[0] + 0.01, srs->Count, runtime[1] + 0.02);
+  EndOpt(cdr);
+  return true;
+}
+
+// 按矩形框范围分组,供其他功能调用 
+bool BoxGrouping(corel *cdr, IVGShapeRange *sr, IVGShapeRange *srs, double exp ) {
+  BoundingBox box;
+  auto al = cdr->ActiveLayer;          // 获得当前层
+  if (!sr || !al) return false;
+
+  std::vector<BoundingBox> boxes;
+  std::vector<int> parent;
+
+  // CorelDRAW Shapes 物件 Item 编号从1开始
+  for (auto i = 0; i != sr->Count; i++) {
+    sr->Shapes->Item[i + 1]->GET_BOUNDING_BOX(box);
+    boxes.push_back(box);
+    parent.push_back(i);
+  }
+
+  // 扩展边界框,或者收缩边界框
+  if (fabs(exp) > 0.02 ) {
+    expand_bounding_boxes(boxes, exp);
+  }
+
+  // 实现 Union-Find 算法来合并重叠的区域
+  for (int i = 0; i < boxes.size(); i++) {
+    for (int j = i + 1; j < boxes.size(); j++) {
+      if (isOverlapped(boxes[i], boxes[j])) {
+        unionSet(parent, i, j);
+      }
+    }
+  }
+
+  // 输出分组结果
+  std::map<int, std::vector<int>> groups;
+  for (int i = 0; i < parent.size(); i++) {
+    int root = find(parent, i);
+    groups[root].push_back(i + 1);
+  }
+
+  auto srgp = cdr->CreateShapeRange();
+  // 分组分别进行群组
+  for (const auto& group : groups) {
+      for (int index : group.second) 
+        srgp->Add(sr->Shapes->Item[index]);
+      
+      if(sr->Count >1)
+        srs->Add(srgp->Group());
+      else{
+        srs->AddRange(srgp); 
+      }
+      srgp->RemoveAll();
+  }
+  return true;
+}

+ 180 - 0
src/cdrPDF2Clip.cpp

@@ -0,0 +1,180 @@
+#include "cdrapp.h"
+#include <stdio.h>
+#include <windows.h>
+#include <thread>
+#include <chrono>
+
+
+
+#define CUSTOM_FORMAT RegisterClipboardFormatA("Portable Document Format")
+
+bool pdf_to_clipboard(const char *pdffile)
+{
+    // 打开剪贴板
+    if (!OpenClipboard(NULL)) {
+        // printf("Failed to open clipboard.\n");
+        return false;
+    }
+
+    // 清空剪贴板
+    EmptyClipboard();
+
+    // 读取PDF文件到内存
+    FILE *file = fopen(pdffile, "rb");
+    if (!file) {
+        // printf("Failed to open file.\n");
+        CloseClipboard();
+        return false;
+    }
+
+    // 获取文件大小
+    fseek(file, 0, SEEK_END);
+    size_t fileSize = ftell(file);
+    fseek(file, 0, SEEK_SET);
+
+    // 分配内存并读取文件内容
+    void *pdfData = malloc(fileSize);
+    if (!pdfData) {
+        // printf("Failed to allocate memory.\n");
+        fclose(file);
+        CloseClipboard();
+        return false;
+    }
+
+    fread(pdfData, 1, fileSize, file);
+    fclose(file);
+
+    // 将二进制数据写入剪贴板
+    HGLOBAL hGlobal = GlobalAlloc(GHND, fileSize);
+    if (!hGlobal) {
+        // printf("Failed to allocate global memory.\n");
+        free(pdfData);
+        CloseClipboard();
+        return false;
+    }
+
+    memcpy(GlobalLock(hGlobal), pdfData, fileSize);
+    GlobalUnlock(hGlobal);
+
+    if (!SetClipboardData(CUSTOM_FORMAT, hGlobal)) {
+        // printf("Failed to set clipboard data.\n");
+        GlobalFree(hGlobal);
+        free(pdfData);
+        CloseClipboard();
+        return false;
+    }
+    // 关闭剪贴板
+    CloseClipboard();
+
+    // printf("PDF binary data copied to clipboard using custom format.\n");
+    // 不要忘记释放内存
+    free(pdfData);
+    return true;
+}
+
+bool clipboard_to_pdf(const char *outputFile)
+{
+    // 打开剪贴板
+    if (!OpenClipboard(NULL)) {
+        // printf("Failed to open clipboard.\n");
+        return false;
+    }
+
+    // 获取剪贴板中的PDF数据
+    HANDLE hData = GetClipboardData(CUSTOM_FORMAT);
+    if (!hData) {
+        // printf("Failed to get clipboard data.\n");
+        CloseClipboard();
+        return false;
+    }
+
+    // 锁定内存并获取指针
+    void *pdfData = GlobalLock(hData);
+    if (!pdfData) {
+        // printf("Failed to lock global memory.\n");
+        CloseClipboard();
+        return false;
+    }
+
+    // 获取PDF数据的大小
+    size_t fileSize = GlobalSize(hData);
+
+    // 将PDF数据写入文件
+    FILE *file = fopen(outputFile, "wb");
+    if (!file) {
+        // printf("Failed to open output file.\n");
+        GlobalUnlock(hData);
+        CloseClipboard();
+        return false;
+    }
+
+    fwrite(pdfData, 1, fileSize, file);
+    fclose(file);
+
+    // 解锁内存并关闭剪贴板
+    GlobalUnlock(hData);
+    CloseClipboard();
+
+    // printf("PDF binary data from clipboard saved to file: %s\n", outputFile);
+
+    return true;
+}
+
+bool cdr_savepdf(corel *cdr, const char *outputFile)
+{
+    DeleteFile(_bstr_t(outputFile));
+    auto pdfst = cdr->ActiveDocument->PDFSettings;
+    pdfst->BitmapCompression = pdfLZW;
+    pdfst->ColorMode = pdfCMYK;
+    pdfst->EmbedBaseFonts = cdrFalse;
+    pdfst->EmbedFonts = cdrFalse;
+    pdfst->FileInformation = cdrFalse;
+    pdfst->Hyperlinks = cdrFalse;
+    pdfst->IncludeBleed = cdrFalse;
+    pdfst->Linearize = cdrTrue;
+    pdfst->MaintainOPILinks = cdrTrue;
+    pdfst->Overprints = cdrTrue;
+    pdfst->PutpdfVersion(pdfVersion14); //'pdfVersion14 : pdfVersion13;
+    pdfst->PublishRange = pdfSelection;
+    pdfst->RegistrationMarks = cdrFalse;
+    pdfst->SpotColors = cdrTrue;
+    pdfst->Startup = pdfPageOnly;
+    pdfst->SubsetFonts = cdrFalse;
+    pdfst->TextAsCurves = cdrTrue;
+    pdfst->Thumbnails = cdrFalse;
+    cdr->ActiveDocument->PublishToPDF(_bstr_t(outputFile));
+
+    return true;
+}
+
+void CdrCopy_to_AdobeAI(corel *cdr)
+{
+    char path[MAX_PATH] = {0};
+    GetTempPath(MAX_PATH, path);
+    char *f = strcat(path, "CDR2AI.pdf");
+    if (cdr_savepdf(cdr, f))
+        pdf_to_clipboard(f);
+}
+
+bool pdf_ImportCdr(corel *cdr, const char *pdffile)
+{
+   auto si = cdr->CreateStructImportOptions();
+   si->MaintainLayers = true;
+   
+   auto impflt = cdr->ActiveLayer->ImportEx(_bstr_t(pdffile), cdrPDF , si);
+   impflt->Finish();
+   return true;
+}
+
+void AdobeAI_Copy_ImportCdr(corel *cdr)
+{
+    char path[MAX_PATH] = {0};
+    GetTempPath(MAX_PATH, path);
+    char *f = strcat(path, "CDR2AI.pdf");
+    if (clipboard_to_pdf(f)){
+        // 延时 0.5 秒
+        std::this_thread::sleep_for(std::chrono::milliseconds(500));
+        pdf_ImportCdr(cdr, f);
+    }
+
+}

+ 48 - 0
src/cdrapi.cpp

@@ -0,0 +1,48 @@
+#include <windows.h>
+#include <stdio.h>
+#include "cdrapi.h"
+
+void BeginOpt(corel *cdr)
+{
+  auto name = _bstr_t("Undo");
+  cdr->EventsEnabled = false;
+  cdr->ActiveDocument->BeginCommandGroup(name);
+  cdr->ActiveDocument->Unit = cdrMillimeter;
+  cdr->Optimization = true;
+}
+
+void EndOpt(corel *cdr)
+{
+  cdr->EventsEnabled = true;
+  cdr->Optimization = false;
+  cdr->EventsEnabled = true;
+  cdr->ActiveDocument->ReferencePoint = cdrBottomLeft;
+  cdr->Application->Refresh();
+  cdr->ActiveDocument->EndCommandGroup();
+}
+
+void Active_CorelWindows(HWND hDlg)
+{                
+  // 将焦点返回到父窗口 关闭对话框窗口
+  SetFocus(GetParent(hDlg));
+}
+
+double GetTextValue(HWND hDlg, int IDITEM) {
+  char ibuf[64];
+  memset(ibuf, 0, sizeof(ibuf));
+
+  // 获取文本
+  if (GetWindowText(::GetDlgItem(hDlg, IDITEM), ibuf, sizeof(ibuf)) == 0) {
+      return 0.0; 
+  }
+
+  double exp = 0.0;
+  if (sscanf_s(ibuf, "%lf", &exp) != 1) {
+      return 0.0; 
+  }
+
+  return exp;
+}
+void PutTextValue(HWND hDlg, int IDITEM, char *buf) {
+  SetWindowText(::GetDlgItem(hDlg, IDITEM), buf);
+}

+ 33 - 0
src/cdrapi.h

@@ -0,0 +1,33 @@
+#ifndef CDRAPI_H_INCLUDED
+#define CDRAPI_H_INCLUDED
+
+#define _CRT_SECURE_NO_WARNINGS
+#include <string.h>
+#include <algorithm>
+#include <cstdio>
+#include <map>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <chrono>
+#include <math.h>
+#include "WinData.h"
+
+#import "VGCoreAuto.tlb" \
+rename("GetCommandLine", "VGGetCommandLine") \
+rename("CopyFile", "VGCore") \
+rename("FindWindow", "VGFindWindow")
+
+#define corel VGCore::IVGApplication
+using namespace VGCore;
+
+
+
+void BeginOpt(corel *cdr);
+void EndOpt(corel *cdr);
+void Active_CorelWindows(HWND hDlg);
+double GetTextValue(HWND hDlg, int IDITEM);
+void PutTextValue(HWND hDlg, int IDITEM, char *buf);
+
+
+#endif // CDRAPI_H_INCLUDED

+ 136 - 0
src/cdrapp.cpp

@@ -0,0 +1,136 @@
+#include "cdrapp.h"
+
+// sr.ApplyUniformFill CreateCMYKColor(0, 100, 100, 0)
+bool fill_red(corel *cdr)
+{
+    auto sr = cdr->ActiveSelectionRange;
+    auto red = cdr->CreateCMYKColor(0, 100, 100, 0);
+    sr->ApplyUniformFill(red);
+
+    return true;
+}
+
+bool cql_OutlineColor(corel *cdr)
+{
+    auto col = cdr->CreateCMYKColor(0, 100, 100, 0);
+    auto s = cdr->ActiveShape;
+    col-> CopyAssign(s->Outline->Color);
+    col->ConvertToRGB();
+
+    auto r = col->RGBRed;
+    auto g = col->RGBGreen;
+    auto b = col->RGBBlue;
+
+    char buf[256] = { 0 };
+    sprintf(buf, "@Outline.Color.rgb[.r='%d' And .g='%d' And .b='%d']", r, g, b);
+    auto cql = _bstr_t(buf);
+    // MessageBox(NULL, cql, "cql 轮廓颜色", MB_ICONSTOP);
+    auto sr = cdr->ActivePage->Shapes->FindShapes(_bstr_t(), cdrNoShape, VARIANT_TRUE, cql);
+    sr->CreateSelection();
+
+    strcpy(infobuf , buf);
+    return true;
+}
+
+bool cql_FillColor(corel *cdr)
+{
+    auto col = cdr->CreateCMYKColor(0, 100, 100, 0);
+    auto s = cdr->ActiveShape;
+    col-> CopyAssign(s->Fill->UniformColor);
+    col->ConvertToRGB();
+
+    auto r = col->RGBRed;
+    auto g = col->RGBGreen;
+    auto b = col->RGBBlue;
+
+    char buf[256] = { 0 };
+    sprintf(buf, "@Fill.Color.rgb[.r='%d' And .g='%d' And .b='%d']", r, g, b);
+    auto cql = _bstr_t(buf);
+
+    auto sr = cdr->ActivePage->Shapes->FindShapes(_bstr_t(), cdrNoShape, VARIANT_TRUE, cql);
+    sr->CreateSelection();
+
+    strcpy(infobuf , buf);
+    return true;
+}
+
+bool cql_SameSize(corel *cdr, double exp)
+{
+    cdr->ActiveDocument->Unit = cdrMillimeter;
+    auto s = cdr->ActiveShape;
+
+    exp += 0.01;
+    char buf[256] = { 0 };
+    sprintf(buf, "(@com.SizeWidth - %lf).abs() <  %lf and (@com.SizeHeight - %lf).abs() <  %lf", s->SizeWidth, exp, s->SizeHeight, exp);
+    auto cql = _bstr_t(buf);
+
+    //  MessageBox(NULL, cql, "cql 尺寸相同", MB_ICONSTOP);
+    auto sr = cdr->ActivePage->Shapes->FindShapes(_bstr_t(), cdrNoShape, VARIANT_TRUE, cql);
+    sr->CreateSelection();
+
+    strcpy(infobuf , buf);
+    return true;
+}
+
+bool Shapes_Filp(corel *cdr)
+{
+    BeginOpt(cdr);
+    auto sr = cdr->ActiveSelectionRange;
+    // CorelDRAW Shapes 物件 Item 编号从1开始
+    for (auto i = 0; i != sr->Count; i++)
+        sr->Shapes->Item[i + 1]->Flip(VGCore::cdrFlipHorizontal);
+
+    EndOpt(cdr);
+    return true;
+}
+
+bool  Clear_Fill(corel *cdr)
+{
+    cdr->ActiveSelection->Fill->ApplyNoFill();
+    return true;
+}
+
+//  1- A program that will copy a selected object 1000 times
+bool Copy_1K_Objects(corel *cdr, double distance)
+{
+  BeginOpt(cdr);
+
+  auto sr = cdr->ActiveSelectionRange; // Get the selection range
+  double sw = sr->SizeWidth;
+  double sh = sr->SizeHeight;
+  int n = 32;
+  auto dup = sr->StepAndRepeat(n - 1, sw + distance, 0.0 , cdrModeOffset, cdrRight, cdrModeOffset, cdrDown);
+  sr->AddRange(dup);
+  auto dup_all = sr->StepAndRepeat(n - 1, 0.0 , sh + distance, cdrModeOffset, cdrRight, cdrModeOffset, cdrDown);
+  sr->AddRange(dup_all);
+  sr->CreateSelection();
+
+  EndOpt(cdr);
+  return true;
+}
+
+// 最高版本 CorelDRAW 2020 保存  CDR X4 格式
+bool SaveAs_X4CDR(corel *cdr, const char *filePath)
+{
+   
+    auto SaveOptions = cdr->CreateStructSaveAsOptions();
+    SaveOptions->EmbedVBAProject = cdrTrue;
+    SaveOptions->Filter = cdrCDR;
+    SaveOptions->IncludeCMXData = cdrFalse;
+    SaveOptions->Range = cdrAllPages;
+    SaveOptions->EmbedICCProfile = cdrFalse;
+    SaveOptions->Version = cdrVersion14;
+
+    cdr->ActiveDocument->SaveAs(_bstr_t(filePath), SaveOptions);
+    return true;
+}
+
+// CorelDRAW CPG 统一中英文字体 C++ 源码
+bool setFontChinese(corel *cdr) {
+  auto sr = cdr->ActiveSelectionRange;
+  auto s = sr->FirstShape;
+  s->Text->Story->LanguageID = cdrSimplifiedChinese;
+  s->Text->Story->Font = L"Microsoft YaHei";
+  s->Text->Story->Size = 18;
+  return true;
+}

+ 50 - 0
src/cdrapp.h

@@ -0,0 +1,50 @@
+#ifndef CDRAPP_H_INCLUDED
+#define CDRAPP_H_INCLUDED
+#include "cdrapi.h"
+
+
+bool fill_red(corel *cdr);
+bool cql_OutlineColor(corel *cdr);
+bool cql_FillColor(corel *cdr);
+bool cql_SameSize(corel *cdr, double exp);
+bool Shapes_Filp(corel *cdr);
+bool Shapes_Filp(corel *cdr);
+bool Clear_Fill(corel *cdr);
+
+void CdrCopy_to_AdobeAI(corel *cdr);
+void AdobeAI_Copy_ImportCdr(corel *cdr);
+
+bool AutoMakeSelection(corel *cdr);
+bool Box_AutoGroup(corel *cdr, double exp = 0.0);
+bool BBox_DrawRectangle(corel *cdr, double exp = 0.0);
+
+void run_BoundaryGroup(corel *cdr);
+
+// A program that will copy a selected object 1000 times
+bool Copy_1K_Objects(corel *cdr, double distance);
+// 最高版本 CorelDRAW 2020 保存  CDR X4 格式
+bool SaveAs_X4CDR(corel *cdr, const char *filePath);
+// CorelDRAW CPG 统一中英文字体 C++ 源码
+bool setFontChinese(corel *cdr);
+
+
+
+extern char infobuf[];
+extern bool debug_flg;
+
+#define GET_BOUNDING_BOX(box)                                                  \
+  GetBoundingBox(&(box).x, &(box).y, &(box).w, &(box).h, false)
+
+#define ZERO_4PC 0, 0, 0, 0
+ // 左下角坐标 x,y  w,h 宽高
+typedef struct {
+  double x;
+  double y; 
+  double w; 
+  double h; 
+} BoundingBox;
+
+bool isOverlapped(const BoundingBox &a, const BoundingBox &b);
+bool BoxGrouping(corel *cdr, IVGShapeRange *sr, IVGShapeRange *srs, double exp );
+
+#endif // CDRAPP_H_INCLUDED

+ 64 - 0
src/lycpg64.cbp

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+	<FileVersion major="1" minor="6" />
+	<Project>
+		<Option title="lycpg64" />
+		<Option pch_mode="2" />
+		<Option compiler="microsoft_visual_c_2022" />
+		<Build>
+			<Target title="Debug">
+				<Option output="bin/Debug/lycpg64" prefix_auto="1" extension_auto="1" />
+				<Option object_output="obj/Debug/" />
+				<Option type="3" />
+				<Option compiler="microsoft_visual_c_2022" />
+				<Option createDefFile="1" />
+				<Option createStaticLib="1" />
+				<Compiler>
+					<Add option="/Zi" />
+					<Add option="/D_DEBUG" />
+				</Compiler>
+				<Linker>
+					<Add option="/debug" />
+				</Linker>
+			</Target>
+			<Target title="Release">
+				<Option output="bin/Release/lycpg64" prefix_auto="1" extension_auto="1" />
+				<Option object_output="obj/Release/" />
+				<Option type="3" />
+				<Option compiler="microsoft_visual_c_2022" />
+				<Option createDefFile="1" />
+				<Option createStaticLib="1" />
+				<Compiler>
+					<Add option="/Ox" />
+					<Add option="/DNDEBUG" />
+					<Add directory="../TypeLibs" />
+				</Compiler>
+			</Target>
+		</Build>
+		<Compiler>
+			<Add option="/W3" />
+			<Add option="/EHsc" />
+		</Compiler>
+		<Unit filename="BoundaryGroup.cpp" />
+		<Unit filename="LYVBA.ico" />
+		<Unit filename="Makefile" />
+		<Unit filename="ToolsBox.cpp" />
+		<Unit filename="ToolsBox.rc">
+			<Option compilerVar="WINDRES" />
+		</Unit>
+		<Unit filename="WinData.cpp" />
+		<Unit filename="WinData.h" />
+		<Unit filename="boxAutoGroup.cpp" />
+		<Unit filename="cdrPDF2Clip.cpp" />
+		<Unit filename="cdrapi.cpp" />
+		<Unit filename="cdrapi.h" />
+		<Unit filename="cdrapp.cpp" />
+		<Unit filename="cdrapp.h" />
+		<Unit filename="lycpg64.cbp" />
+		<Unit filename="resource.h" />
+		<Unit filename="vbadll.cpp" />
+		<Extensions>
+			<lib_finder disable_auto="1" />
+		</Extensions>
+	</Project>
+</CodeBlocks_project_file>

+ 25 - 0
src/resource.h

@@ -0,0 +1,25 @@
+#ifndef IDC_STATIC
+#define IDC_STATIC (-1)
+#endif
+
+#define IDD_TOOLS_BOX                           100
+#define IDI_ICON1                               101
+#define IDC_DRAW_RECT                           40000
+#define IDC_CQL_FILL                            40001
+#define IDC_CQL_OUTLINE                         40002
+#define IDC_CQL_SIZE                            40003
+#define IDC_SR_FLIP                             40004
+#define IDC_SAVEX4CDR                           40005
+#define IDC_CDR2AI                              40006
+#define IDC_AI2CDR                              40007
+#define EXP_LT                                  40008
+#define EXP_TEXT                                40009
+#define INFO_TEXT                               40010
+#define IDC_BOX_GROUP                           40011
+#define ID_BOUNDARY_GROUP                       40012
+#define DEBUG_FLG                               40013
+#define MIN_TOOLS                               40014
+#define EXPAND_TOOLS                            40015
+#define RENEW_TOOLS                             40016
+#define IDC_Copy1KOBJ                           40017
+#define IDC_SetFontCN                           40018

+ 68 - 0
src/vbadll.cpp

@@ -0,0 +1,68 @@
+
+#include "cdrapi.h"
+#include "cdrapp.h"
+
+extern corel *cdr;
+void open_lycpg();
+extern "C" __declspec(dllexport)
+int __stdcall vbadll(int code, double x =0.0){
+
+try {
+    switch(code){
+        case 1:
+            AdobeAI_Copy_ImportCdr(cdr);
+        break;
+        
+        case 2:
+            CdrCopy_to_AdobeAI(cdr);
+        break;
+
+        case 3:
+            Clear_Fill(cdr);
+        break;
+
+        case 4:
+            Shapes_Filp(cdr);
+        break;
+
+        case 5:
+            cql_FillColor(cdr);
+        break;
+
+        case 6:
+            cql_OutlineColor(cdr);
+        break;
+
+        case 7:
+            cql_SameSize(cdr, x);
+        break;
+
+        case 8:
+            fill_red(cdr);
+        break;
+
+        case 9:
+            BBox_DrawRectangle(cdr, x);
+        break;
+
+        case 10:
+            Box_AutoGroup(cdr, x);
+        break;
+
+        case 11:
+            run_BoundaryGroup(cdr);
+        break;
+
+        case 888:
+            open_lycpg();
+        break;
+
+        default:
+            return 0;
+    }
+} catch (_com_error &e) {
+    MessageBox(NULL, e.Description(), "Error", MB_ICONSTOP);
+    EndOpt(cdr);
+}
+    return code;
+}