-
-
Notifications
You must be signed in to change notification settings - Fork 125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DWGWriter thumbnail support #558
Comments
Hi @ChrisClems, We can take a look at this feature, the reading part is easy, check how the thumbnail is stored and read it as a byte array or even a bitmap. To write it that's another story, the idea of the user giving the byte array is a good one, if they have the tools to generate the image or want a custom want is just a matter of writing those bytes. The only rule that I would impose is that if the feature needs some external or third party libraries maybe it would be best to create a separated project like I did with I'll take a look when I can and see what we can do. Thanks for your support. |
@DomCR Thanks! So I went a little further into this last week than I'd planned before hearing back from you. I left all my work on this at the office so I won't be able to dig back in until next week but here's a brain dump while it's still fresh in my memory. I believe I've found a bug in the DwgWriter. This was my initial testing process:
For what it's worth, I also managed to cobble together a PNG encoder that takes lines, arcs, ellipses, elliptical arcs, fit splines, and NURBS splines, and rasterizes them with zero external dependencies. It's under 1,000 lines of code. I needed some help from Claude to get the NURBS spline approximation working but the experimental code had a really clean interface. The PNGs it outputs are passing I'll do more cross referencing next week with the section layout in my DWG files and see if I can find where the problem is. If I can't figure it out myself by week's end, I'll dump a bunch of examples here so someone else can check my work. |
The version AC14 and AC15 are quite old, the writer is implemented but is not super stable and the files usually need to be restored, it also needs to be refined to be able to write an obsolete object, VP_ENT_HDR_CTRL_OBJ which it stores and controls all the viewports. The version AC21 is a particular one, Autodesk changed some parts of the encoding, but only for this one, I haven't implemented yet, there is a branch created but the amount is quite high and there are some other priorities before implementing a writer for an older version. AC18, AC27 (recently fixed) and AC32 are the ones that work better and the best to test with, the writer is the most stable.
This should not matter, in the For AC15: ACadSharp/src/ACadSharp/IO/DWG/DwgReader.cs Line 444 in bed9828
For AC18 and after: ACadSharp/src/ACadSharp/IO/DWG/DwgReader.cs Line 953 in bed9828
In the writer for AC18 and after:
Thanks a lot for this input ❤! the 0s where related to the DxfClasses section not being compressed, now the files are much lighter too. |
I've been trying to generate a dxf with a preview image but Autocad doesn't have the feature enabled for some reason, I wanted to try to generate the image from a dxf file which is way more transparent than a dwg. Where do you create the image preview for your dxf? |
I use F3D to generate DXF thumbnails system wide. I hadn't tried working out the ASCII DXF thumbnail section because it's so poorly documented. I might loop back and see if I can craft a working DXF thumbnail section but right now my priority is DWG.
Understood. I will focus my attention on the latest version for the moment. You're obviously lightyears ahead of me on the DWG spec so I'll post what I know so far. You might see something obvious that I'm missing, saving some duplicated work. The attached zip has a few files. An input DXF, an output 1032/2018 DWG from ACadSharp, then the same DWG, opened then saved in AutoCAD 2024. The PNG I am reading and manually injecting into the file in the DwgPreviewWriter with this code for testing: public DwgPreviewWriter(ACadVersion version, Stream stream) : base(version)
{
this._swriter = DwgStreamWriterBase.GetStreamWriter(version, stream, TextEncoding.Windows1252());
}
public void Write()
{
var pngData = File.ReadAllBytes(@"E:\DWGTest\output.png");
// Write start sentinel
this._swriter.WriteBytes(this._startSentinel);
// Calculate overall size:
// Current overhead before PNG file is 99 bytes. Add better computed value later.
int overallSize = 99 + pngData.Length;
this._swriter.WriteRawLong(overallSize);
// Unknown what these are. Current grouping is just my best guess.
this._swriter.WriteByte(2); // In BMP spec this was the image count.
this._swriter.WriteByte(1); // In BMP spec this was the image format identifier
this._swriter.WriteRawLong(487);
this._swriter.WriteRawLong(80);
this._swriter.WriteByte(6);
this._swriter.WriteRawLong(567);
// PNG data size
this._swriter.WriteRawLong(pngData.Length);
// Zero padding? Always 80 bytes in my drawings
this._swriter.WriteBytes(new byte[80]);
// Write the image data
this._swriter.WriteBytes(pngData);
// Write end sentinel
this._swriter.WriteBytes(this._endSentinel);
} I checked the preview offset you referenced in both files and they appear to be set correctly. This is what I've decoded for the PNG preview section layout. The overall size and the PNG size are the only values that seem to need to be changed.
The preview section itself seems to be correct when cross-referencing files with working thumbnails out of AutoCAD. I made sure my PNG data did not have any unknown issues by hand-crafting a preview section with my generated PNG in a hex editor. Saving the file in the hex editor immediately updated the thumbnail in file explorer. The ACadSharp-generated DWG has the preview section at 0x7920 while the one from AutoCAD is at 0x01C0. My only real idea at the moment is there's some overall length not being computed correctly when I add data to the preview section, and it is not reading far enough to get the thumbnail. |
I managed to make it work using the branch linked to the issue, here is the code to test it: CadDocument doc;
DwgPreview preview;
using (DwgReader reader = new DwgReader(_file))
{
doc = reader.Read();
preview = reader.ReadPreview();
}
string output = Path.Combine(Path.GetDirectoryName(_file),
$"{Path.GetFileNameWithoutExtension(_file)}.out.dwg");
using (DwgWriter writer = new DwgWriter(output, new CadDocument()))
{
writer.Preview = preview;
writer.Write();
} I'll try to refine the code and fix the offset positioning. |
I want to say before getting to the point, I know this is nobody's top priority and this is likely a huge amount of work. I'd like to take on the heavy lifting and eventually submit a PR for this if it would be welcome and I can figure it out. I'm starting an issue to 1) see if this functionality could be packaged in a way that would be accepted as a PR in ACadSharp and if so 2) consult the experts to see if they have any information that might save me some time and research.
I process massive amounts of individual AutoCAD files. My library is tens of thousands of drawings and I'm working on up to 1,000 at a time in a single project. It is incredibly useful to me to spot-check thumbnails in folders to see if there are any glaring issues I need to address. I usually export DXF files when I'm working with ACadSharp because I have software on my machine which auto-generates thumbnails for them. It would be beneficial to me to be able to output DWG files with thumbnails.
The way I understand it, DWG thumbnails are generated by AutoCAD and saved in the file header in various formats depending on the DWG version. Currently, the only way to generate a DWG with a thumbnail which was not originally saved with one is to open it in AutoCAD and save it. It looks like there's some information on storing BMP and WMF thumbnails on page 93 of the ODS DWG spec document. There are format changes in R13C3. I think with this document and a bit of work reading how the DwgWriter works I might be able to implement this as an option to pass when writing a DWG file.
I understand the desire to keep this a lightweight library so any sort of rendering dependencies are obviously out. My alternate idea is optionally passing a user-generated byte array representing a BMP to the DwgWriter that would be inserted at the correct spot. There is already some precedent for this as the DwgReader is retrieving what appears to be preview image data as byte arrays when importing BlockRecords.
Or rather than passing a user-generated byte array, I don't think it would be that insane to implement a simple BMP rasterization class. The BMP spec is dead simple and is not exactly going to be undergoing any major breaking changes that would create a maintenance issue for this class. I wrote up a super simple proof of concept that renders vector line and arc data to a BMP and it's working in under 200 lines of code. Obviously expanding that to support more entities would increase the size but I think a BMP raster class could be quite compact. It would only need to support the most basic entities such as lines, arcs, circles, ellipses, polylines, and splines. Polylines can be exploded for the purposes of rasterization to keep things simple. Text, hatching, and other more complex entities are already being ignored in AutoCAD thumbnails so we can as well. NURBS splines are the only thing I'm having difficulty with in quick testing.
If I can create a working version of DwgWriter that generates valid DWG files with thumbnails and make a reasonably small and basic rasterization class that will create a BMP byte array from primitive entities in model space to pass to it, would you be open to a PR for a new feature?
The text was updated successfully, but these errors were encountered: