TheSwamp
Code Red => .NET => Topic started by: huiz on June 27, 2010, 02:39:31 PM
-
I tried to get a PNG file into AutoCAD with VB.NET but sofar I did not succeed. There is really little documentation about this so I hope someone of you can help me further.
A raster object is firstly added to an imagedictionary as a RasterImageDef. Then you need to create a RasterImage object and refer to the ObjectID of the RasterImageDef. I have my code till sofar, I do get an ObjectID so the RasterImageDef is added to the dictionary.
But I can't get the RasterImage into AutoCAD. There is no reference in the References Palette, no errors, etc. Does someone have code to put an image object into AutoCAD from which I can learn how to do it? :-)
-
I have this code so far:
Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click
' we have coördinates in pntLinksOnder
' we have a directory from where we want the PNG's in strFilePath
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
Dim acCurDb As Database = acDoc.Database
Dim acBT As BlockTable
Dim acBTR As BlockTableRecord
Dim acImageDefPNG As DatabaseServices.RasterImageDef
Dim acImagePNG As DatabaseServices.RasterImage
' Start a transaction
Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
acBT = acDoc.Database.BlockTableId.GetObject(DatabaseServices.OpenMode.ForRead)
acBTR = acBT(BlockTableRecord.ModelSpace).GetObject(DatabaseServices.OpenMode.ForWrite)
Try
Dim myDI As New IO.DirectoryInfo(strFilePath)
Dim myArrayFI As IO.FileInfo() = myDI.GetFiles("*.png")
For Each myFI In myArrayFI
If Microsoft.VisualBasic.Left(myFI.Name.ToUpper, 2) = "LG" Then
acImageDefPNG = New DatabaseServices.RasterImageDef
acImageDefPNG = AddImageDef(acDoc.Database, acTrans, myFI.FullName.ToString)
If (Not (acImageDefPNG) Is Nothing) Then
acImagePNG = New DatabaseServices.RasterImage
acImagePNG.ImageDefId = acImageDefPNG.ObjectId
acTrans.AddNewlyCreatedDBObject(acImagePNG, True)
acImagePNG.AssociateRasterDef(acImageDefPNG)
Dim acImageOrigin As Geometry.Point3d = pntLinksOnder
acImagePNG.Orientation = New Geometry.CoordinateSystem3d(acImageOrigin, Geometry.Vector3d.XAxis, Geometry.Vector3d.YAxis)
' acImagePNG.Position = pntLinksOnder
acImagePNG.ImageTransparency = True
acTrans.Commit()
End If
End If
Next
Catch ex As Exception
End Try
' Close transaction
acTrans.Dispose()
Me.Close()
End Using
End Sub
' function to load image into dictionary
Public Shared Function AddImageDef(ByVal db As Database, ByVal trans As Transaction, ByVal imageFilespec As String) As RasterImageDef
If Not File.Exists(imageFilespec) Then
Throw New FileNotFoundException(imageFilespec)
End If
Dim idImageDict As ObjectId = RasterImageDef.GetImageDictionary(db)
If idImageDict.IsNull Then
idImageDict = RasterImageDef.CreateImageDictionary(db)
End If
If idImageDict.IsNull Then
Throw New InvalidOperationException("failed to get or create image dictionary")
End If
Dim imageDictionary As DBDictionary = CType(trans.GetObject(idImageDict, DatabaseServices.OpenMode.ForRead), DBDictionary)
If (imageDictionary Is Nothing) Then
Throw New InvalidOperationException("Failed to open image dictionary")
End If
Dim imageDef As RasterImageDef = New RasterImageDef
Try
imageDef.SourceFileName = imageFilespec
imageDef.Load()
Dim name As String = RasterImageDef.SuggestName(imageDictionary, imageFilespec)
imageDictionary.UpgradeOpen()
Dim idEntry As ObjectId = imageDictionary.SetAt(name, imageDef)
If idEntry.IsNull Then
Throw New InvalidOperationException("Failed to add image definition to image dictionary")
End If
trans.AddNewlyCreatedDBObject(imageDef, True)
Return imageDef
Catch
imageDef.Dispose()
Throw
End Try
End Function
There are no errors so I assume I forget something. Unfortunately a RasterImage is not that simple as adding a line and I can't find useful information about this.
-
That looks like code that Tony posted, which I just tested and it works as expected. The difference between Tony's and yours, in the brief glance I gave it, is the insert/position point.
Actually, your problem is that you're not using AppendEntity to add the newly created RasterImage to the ModelSpace block table record...
-
It is indeed the code from Tony, translated to VB. There is hardly any other code example of RasterImages.
I was not able to debug with VB2010 Express so I tried in VB2008 Express (now I can debug) and now I seem to get errors at the second image. I receive an error here:
Dim imageDictionary As DBDictionary = CType(trans.GetObject(idImageDict, DatabaseServices.OpenMode.ForRead), DBDictionary)
Which says that the object reference is not set to an instance of an object.
The first image is not a problem, that will show up (even while I do not use AppendEntity), but the second probably tries to set a new image dictionary or so? And then the code will stop.
-
Second image...??? As far as I can tell, you're only attaching one...
-
Dim myDI As New IO.DirectoryInfo(strFilePath)
Dim myArrayFI As IO.FileInfo() = myDI.GetFiles("*.png")
For Each myFI In myArrayFI
^^ I read all PNG's from a map and I try to load them in the loop. The first one gets loaded, the second one gives the error.
But as far as I understand the function of Tony, it should not give problems but it does so.
-
1. You didn't mention or show the actual code you are using. The code you originally showed does not do a batch insertion, which is now clearly what you are trying to do.
2. You need to use AppendEntity.
-
It is indeed the code from Tony, translated to VB.
blasphemy
-
I think I used Tony's code as a starting point a while back. And after fiddling for a while, I came up with this function which you can call once for each image you want to insert.
Public Function Add_Raster(ByRef ThisDoc As Document, ByVal RasterFile As String, ByVal InsPoint As Point3d, ByVal Scale As Double, ByRef NumInserted As Integer) As RasterImage
Dim RasterEnt As RasterImage, RasterDef As RasterImageDef
Dim ImageDicID, ImageDefID As ObjectId, ImageDic As DBDictionary
Dim Matrix As Geometry.Matrix3d
Dim btr As BlockTableRecord
Dim RasterName As String = ""
RasterName = RasterFile.Substring(RasterFile.LastIndexOf("\") + 1)
RasterName = RasterName.Substring(0, RasterName.IndexOf("."))
Add_Raster = Nothing
If ThisDoc Is Nothing Then Exit Function
Try
Using Trans As Transaction = ThisDoc.TransactionManager.StartTransaction()
RasterEnt = New RasterImage
RasterEnt.Dispose() ' force loading of RasterImage.dbx module (needed for 2009 and earlier)
RasterDef = New RasterImageDef
RasterDef.SourceFileName = RasterFile
RasterDef.ActiveFileName = RasterFile
RasterDef.Load()
ImageDicID = RasterImageDef.GetImageDictionary(ThisDoc.Database)
If ImageDicID.IsNull Then
RasterImageDef.CreateImageDictionary(ThisDoc.Database)
ImageDicID = RasterImageDef.GetImageDictionary(ThisDoc.Database)
End If
If ImageDicID.IsNull Then
MsgBox("Could not create image dictionary", MsgBoxStyle.Critical, "Failed")
'Exit Try
End If
ImageDic = Trans.GetObject(ImageDicID, OpenMode.ForWrite)
If ImageDic Is Nothing Then
MsgBox("Could not open image dictionary", MsgBoxStyle.Critical, "Failed")
Else
If ImageDic.Contains(RasterName) Then
MsgBox("That image name is already in use", MsgBoxStyle.Critical, "Failed")
Else
ImageDic.UpgradeOpen()
ImageDefID = ImageDic.SetAt(RasterName, RasterDef)
Trans.AddNewlyCreatedDBObject(RasterDef, True)
RasterEnt = New RasterImage
RasterEnt.SetDatabaseDefaults(ThisDoc.Database)
RasterEnt.ColorIndex = 256
RasterEnt.Linetype = "ByLayer"
RasterEnt.LineWeight = LineWeight.ByLayer
If IsSTB Then RasterEnt.PlotStyleName = "ByLayer"
Matrix = New Geometry.Matrix3d
Matrix = Geometry.Matrix3d.Scaling(Scale / RasterDef.Size.X, New Point3d(0, 0, 0))
RasterEnt.TransformBy(Matrix)
Matrix = Geometry.Matrix3d.Displacement(New Vector3d(InsPoint.X, InsPoint.Y, InsPoint.Z))
RasterEnt.TransformBy(Matrix)
RasterEnt.ImageDefId = ImageDefID
btr = Trans.GetObject(ThisDoc.Database.CurrentSpaceId, OpenMode.ForWrite)
btr.AppendEntity(RasterEnt)
Trans.AddNewlyCreatedDBObject(RasterEnt, True)
Trans.Commit()
NumInserted = NumInserted + 1
End If
End If
End Using
Add_Raster = RasterEnt
Catch ex As Exception
MsgBox("Error inserting image " & RasterName, MsgBoxStyle.Critical, "Failed")
End Try
End Function
-
1. You didn't mention or show the actual code you are using. The code you originally showed does not do a batch insertion, which is now clearly what you are trying to do.
2. You need to use AppendEntity.
I did mention the complete code and it shows a loop. My code is above Tony's function.
Indeed, AppendEntity did the trick. I thought it was not nessaccary because the RasterImageDef got appended already but the RasterImage should be appended as well. It works! :-)
Just.... only one small thing...
I also tried the cody supplied by GTVic, that works excellent! Thanks :-) But, both codes, no matter which I use, create the RasterImages as Unreferenced. They are visible in AutoCAD though but they are unreferenced. Also, the first file is shown double in the list. See image attached.
-
tr.AddNewlyCreatedDBObject(RasterEnt, true);
RasterEnt.AssociateRasterDef(RasterDef);
-
Indeed! At this same second I just found out that was the last problem :-)
Thanks all! Hope my knowledge will help some other guy one day :-)
-
And a function worth mentioned in the Routines topics: http://www.theswamp.org/index.php?topic=31863.msg392684#msg392684
I took GTVic's code and added transparency and layer option to it. Hope this function will help other people :-)