소스 정보
- 저장소
- hebackus/c3d-api-plugin
- 최근 소스 활동
- 2026년 4월 9일 01:53
- 감지된 SKILL.md 언어
- 영어
- 스타
- 3
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/hebackus/c3d-api-plugin --skill acad-images-ole명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | acad-images-ole |
| description | Raster images, PDF/DWF/DGN underlays, OLE objects, wipeouts, image clipping |
Use this skill when inserting or manipulating raster images, PDF/DWF/DGN underlays, OLE embedded objects, or wipeout masking entities in AutoCAD drawings.
Every raster image requires a RasterImageDef stored in the ACAD_IMAGE_DICT dictionary. The definition holds the source file path and resolution; multiple RasterImage entities can reference the same definition.
public static ObjectId GetOrCreateImageDef(Database db, Transaction tr,
string imagePath, string dictKey)
{
ObjectId imageDictId = RasterImageDef.GetImageDictionary(db);
if (imageDictId.IsNull)
imageDictId = RasterImageDef.CreateImageDictionary(db);
DBDictionary imageDict = (DBDictionary)tr.GetObject(
imageDictId, OpenMode.ForWrite);
if (imageDict.Contains(dictKey))
return imageDict.GetAt(dictKey);
RasterImageDef imageDef = new RasterImageDef();
imageDef.SourceFileName = imagePath;
imageDef.Load(); // reads file to get resolution and pixel dimensions
ObjectId defId = imageDict.SetAt(dictKey, imageDef);
tr.AddNewlyCreatedDBObject(imageDef, true);
return defId;
}
A RasterImageDefReactor keeps an image definition alive while RasterImage entities reference it. Without a reactor, the definition can be purged prematurely.
RasterImageDefReactor reactor = new RasterImageDefReactor();
reactor.ImageDefId = imageDefId;
btr.AppendEntity(reactor);
tr.AddNewlyCreatedDBObject(reactor, true);
rasterImage.ReactorId = reactor.ObjectId;
public static ObjectId InsertRasterImage(Database db, ObjectId imageDefId,
Point3d insertionPt, double widthInDrawingUnits)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
RasterImageDef imageDef = (RasterImageDef)tr.GetObject(
imageDefId, OpenMode.ForRead);
RasterImage image = new RasterImage();
image.SetDatabaseDefaults();
image.ImageDefId = imageDefId;
// U/V vectors represent FULL width and height in drawing units
Vector2d pixelSize = imageDef.Size;
double height = widthInDrawingUnits * (pixelSize.Y / pixelSize.X);
image.Orientation = new CoordinateSystem3d(insertionPt,
Vector3d.XAxis * widthInDrawingUnits,
Vector3d.YAxis * height);
btr.AppendEntity(image);
tr.AddNewlyCreatedDBObject(image, true);
// Attach reactor to keep definition alive
RasterImageDefReactor reactor = new RasterImageDefReactor();
reactor.ImageDefId = imageDefId;
btr.AppendEntity(reactor);
tr.AddNewlyCreatedDBObject(reactor, true);
image.ReactorId = reactor.ObjectId;
// Associate image with its definition for xref-style tracking
image.AssociateRasterDef(imageDef);
tr.Commit();
return image.ObjectId;
}
}
Clip boundaries are specified in image pixel coordinates (origin at bottom-left corner of the image).
// Rectangular clip — exactly 2 points (lower-left, upper-right)
Point2dCollection rectPts = new Point2dCollection();
rectPts.Add(new Point2d(100, 100)); // lower-left in pixels
rectPts.Add(new Point2d(400, 300)); // upper-right in pixels
rasterImage.SetClipBoundary(ClipBoundaryType.Rectangle, rectPts);
rasterImage.IsClipped = true;
// Polygonal clip — 3+ vertices, first and last must match to close
Point2dCollection polyPts = new Point2dCollection();
polyPts.Add(new Point2d(50, 50));
polyPts.Add(new Point2d(300, 50));
polyPts.Add(new Point2d(300, 250));
polyPts.Add(new Point2d(150, 300));
polyPts.Add(new Point2d(50, 50)); // close
rasterImage.SetClipBoundary(ClipBoundaryType.Poly, polyPts);
rasterImage.IsClipped = true;
// Reset clip to full image
rasterImage.SetClipBoundaryToWholeImage();
rasterImage.IsClipped = false;
// Read existing clip boundary
ClipBoundary clip = rasterImage.GetClipBoundary();
// clip.ClipPoints — 2 points for rectangle, N+1 for polygon
// Use the inverse of PixelToModelTransform to convert WCS points to pixels
Matrix3d pixelToModel = rasterImage.PixelToModelTransform;
Matrix3d modelToPixel = pixelToModel.Inverse();
Point3d wcsPoint = new Point3d(50.0, 25.0, 0.0);
Point3d pixelPoint = wcsPoint.TransformBy(modelToPixel);
Point2d clipPt = new Point2d(pixelPoint.X, pixelPoint.Y);
Drawing-wide image display settings stored in the named object dictionary.
ObjectId rvId = RasterVariables.GetRasterVariables(db);
if (rvId.IsNull)
rvId = RasterVariables.CreateRasterVariables(db);
RasterVariables rv = (RasterVariables)tr.GetObject(rvId, OpenMode.ForWrite);
rv.ImageFrame = ImageFrameType.DisplayedNotPlotted;
// ImageFrameType: None=0, DisplayedAndPlotted=1, DisplayedNotPlotted=2
rv.ImageQuality = ImageQualityType.High; // Draft=0, High=1
rv.UserScale = 1.0;
PDF underlays use a definition/reference pair: PdfDefinition + PdfReference. The definition lives in the ACAD_PDFDEFINITIONS named dictionary.
public static ObjectId InsertPdfUnderlay(Database db, string pdfPath,
int pageNumber, Point3d insertionPt, double scale)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
// Get or create the PDF definitions dictionary
ObjectId pdDictId = UnderlayDefinition.GetDictionaryId(db,
new PdfDefinition().GetType());
if (pdDictId.IsNull)
pdDictId = UnderlayDefinition.CreateDictionary(db,
new PdfDefinition().GetType());
DBDictionary pdfDict = (DBDictionary)tr.GetObject(
pdDictId, OpenMode.ForWrite);
PdfDefinition pdfDef = new PdfDefinition();
pdfDef.SourceFileName = pdfPath;
pdfDef.ItemName = pageNumber.ToString(); // 1-based page number
ObjectId pdfDefId = pdfDict.SetAt(
"MyPdf_Page" + pageNumber, pdfDef);
tr.AddNewlyCreatedDBObject(pdfDef, true);
PdfReference pdfRef = new PdfReference();
pdfRef.SetDatabaseDefaults();
pdfRef.DefinitionId = pdfDefId;
pdfRef.Position = insertionPt;
pdfRef.ScaleFactors = new Scale3d(scale, scale, scale);
pdfRef.Rotation = 0.0;
btr.AppendEntity(pdfRef);
tr.AddNewlyCreatedDBObject(pdfRef, true);
tr.Commit();
return pdfRef.ObjectId;
}
}
DWF and DGN underlays follow the identical definition/reference pattern with swapped types:
| Format | Definition | Reference | Dictionary | ItemName |
|---|---|---|---|---|
PdfDefinition | PdfReference | ACAD_PDFDEFINITIONS | Page number | |
| DWF | DwfDefinition | DwfReference | ACAD_DWFDEFINITIONS | Sheet name |
| DGN | DgnDefinition | DgnReference | ACAD_DGNDEFINITIONS | Model name |
// Clip underlay — 2 points = rectangle, 3+ = polygon (in underlay space)
Point2dCollection clipPts = new Point2dCollection();
clipPts.Add(new Point2d(0, 0));
clipPts.Add(new Point2d(500, 350));
pdfRef.SetClipBoundary(clipPts);
pdfRef.IsClipped = true;
// Filter underlay layers
for (int i = 0; i < pdfRef.UnderlayLayerCount; i++)
{
UnderlayLayer layer = pdfRef.GetUnderlayLayer(i);
string name = layer.Name;
layer.State = UnderlayLayerState.Off; // On or Off
}
OLE objects embed or link external documents (Excel, Word, images) in the drawing. The .NET API cannot create new OLE objects programmatically; use COM automation or SendStringToExecute with the INSERTOBJ command instead.
foreach (ObjectId entId in btr)
{
Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForRead);
if (ent is Ole2Frame ole)
{
ed.WriteMessage("\nOLE: {0}, Linked={1}", ole.UserType, ole.IsLinked);
if (ole.IsLinked)
ed.WriteMessage(", Path={0}", ole.LinkPath);
// Reposition an OLE object
ole.UpgradeOpen();
ole.Location = new Point3d(100, 200, 0);
ole.WcsWidth = 50.0;
ole.WcsHeight = 30.0;
}
}
A Wipeout masks entities behind it with the background color. It inherits from RasterImage.
public static ObjectId CreateWipeout(Database db, Point2dCollection boundary)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
Wipeout wipeout = new Wipeout();
wipeout.SetDatabaseDefaults();
wipeout.SetFrom(boundary, Vector3d.ZAxis);
btr.AppendEntity(wipeout);
tr.AddNewlyCreatedDBObject(wipeout, true);
tr.Commit();
return wipeout.ObjectId;
}
}
// Boundary must be a closed polygon (first point = last point)
Point2dCollection pts = new Point2dCollection();
pts.Add(new Point2d(0, 0));
pts.Add(new Point2d(100, 0));
pts.Add(new Point2d(100, 50));
pts.Add(new Point2d(0, 50));
pts.Add(new Point2d(0, 0));
// Frame visibility: 0=hidden, 1=displayed+plotted, 2=displayed not plotted
Application.SetSystemVariable("WIPEOUTFRAME", 2);
// Draw order — wipeout must be behind text but in front of hidden entities
DrawOrderTable dot = (DrawOrderTable)tr.GetObject(
btr.DrawOrderTableId, OpenMode.ForWrite);
ObjectIdCollection ids = new ObjectIdCollection { wipeoutId };
dot.MoveBelow(ids, entityAboveId);
RasterImageDef.Load() throws if the image file does not exist — verify the path or wrap in try/catchOrientation on RasterImage uses U and V vectors representing the FULL width and height in drawing units, NOT unit vectors — setting unit vectors produces a 1x1 unit imageRasterImageDefReactor is required to prevent image definitions from being purged — always create and attach one per image entityRasterImageDef.GetImageDictionary() returns ObjectId.Null if no images exist yet — always check and call CreateImageDictionary() if nullPixelToModelTransform to convert from WCSClipBoundaryType.Rectangle requires exactly 2 points (lower-left, upper-right) — ClipBoundaryType.Poly requires 3+ points with first = last to closeItemName must be a valid page number string (e.g., "1") — invalid values throw eInvalidValue or eOutOfRangeOle2Frame cannot be created programmatically via the .NET API — use COM automation or SendStringToExecute("INSERTOBJ\n") to embed new OLE contentUnderlayDefinition.GetDictionaryId() and CreateDictionary() require the concrete type (e.g., typeof(PdfDefinition)) to locate the correct named dictionaryAssociateRasterDef() must be called AFTER the RasterImage is added to the database — it establishes the reactor connection between image and definitionacad-blocks — images and underlays inserted inside block definitionsacad-layers — layer assignment for image, underlay, wipeout, and OLE entitiesacad-geometry — CoordinateSystem3d orientation vectors and Matrix3d transforms for image positioningacad-xrefs — underlays vs xrefs: underlays are display-only while xrefs bring full DWG geometry