This is going to be a brief post in case someone else also ran into this issue and wanted a head-start on it.
The AutoCAD DXF format is documented here (AutoCAD "About the DXF Format (DXF)"). I'm going to assume you are already familiar with the basics if you have arrived at this page.
The goal
My program is a CAD software so it is important that it outputs drawings it creates in an industry standard format. My goal was to take a client's exported DXF file template and make it so my program could export a new drawing using the template.
My program is written in Cakelisp and I'm writing the DXF import/exporter completely from scratch with no libraries.
The problem
Things were going fine until I tried to place the client's company logo at an arbitrary position. The logo is in an OLE2FRAME entity, which has normal entity fields like position XYZ and so on. It then has a large hexadecimal encoded binary blob which I assumed was just uncompressed pixel data based on how many FFFFFF (RGB white) and other apparent colors there were.
The image positions in the drawing were supposed to be set by groups 10, 20, 30 for the upper left XYZ and 11, 21, 31 for the lower right XYZ. When I changed these numbers, however, the image stayed at the position it was in the client's template, not my newly generated position.
Reverse engineering the format
I inspected the image in the AutoCAD viewer and found the image position exactly matched the position the image was in when I received it from the client. I then searched the plain-text DXF for that exact float position in my generated file, and it couldn't be found.
I realized then that the old position must still be encoded in the OLE2FRAME, and that it must be in hexadecimal format if it isn't in decimal format.
I used Float.exposed as a quick way to get the hex value. One could easily print this value with e.g. printf("%llx", theDouble) (ll prints long long, i.e. 64 bits, and x prints in hexadecimal).
Here's what I got for the positions (Z omitted because it's 0):
| Name | Group | Value | Hex |
|---|---|---|---|
| X Upper left | 10 | 17.20987461443136 | 0x403135ba57bd3e4a |
| Y | 20 | 14.8413702134881 | 0x402daec8139d8515 |
| X Lower right | 11 | 18.14878881972419 | 0x40322617062ab9d0 |
| Y | 21 | 14.46577988633638 | 0x402cee7ab385e611 |
Here's the OLE2FRAME start:
0
OLE2FRAME
5
18E
330
18B
100
AcDbEntity
8
0
100
AcDbOle2Frame
70
2
3
Paintbrush Picture
10
17.20987461443136
20
14.8413702134881
30
0.0
11
18.14878881972419
21
14.46577988633638
31
0.0
71
2
72
0
73
2
90
982168Here's the start of the 310 binary data (notice it is little endian):
310 [0]
Position 10 Position 20 Position Z Position 11
8055 4A3EBD57BA353140 16859D13C8AE2D40 0000000000000000 D2B92A061726
310 [1]
11 Position 20 Position Z Position 11 Pos 21 again
3240 16859D13C8AE2D40 0000000000000000 D2B92A0617263240 11E685B37AEE
310 [2]
21 Position Z Position 10 Position 21 Position Z
2C40 0000000000000000 4A3EBD57BA353140 11E685B37AEE2C40 000000000000
310 [3]
Z (rest not yet decoded)
0000 000000000100000000010000040000000100000000000100000000FC0E00
310 [4]
D0CF11E0A1B11AE1000000000000000000000000000000003E000300FEFF0900
310 [5]
0600000000000000000000000F00000001000000000000000010000002000000
310 [6]
01000000FEFFFFFF000000000000000004000000050000000600000007000000
310 [7]
08000000090000000A0000000B0000000C0000000D0000000E0000000F000000
310 [8]
1000000011000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFI have labeled the 310 hex-encoded binary blob with what I found: the exact doubles I was looking for, in little-endian encoding.
I then write a structure which (assuming a little-endian machine) could replace the first three 310 lines to position the image:
typedef struct DxfVec3
{
double x;
double y;
double z;
} DxfVec3;
// It is necessary to pack it to avoid extra padding after
// mysteryValue, which would be padded to align the doubles.
// We are outputting this structure directly to the DXF so we
// need it to match exactly.
typedef struct __attribute__((packed)) DxfOle2FrameHeader
{
unsigned short mysteryValue;
DxfVec3 upperLeft;
DxfVec3 upperRight;
DxfVec3 lowerRight;
DxfVec3 lowerLeft;
} DxfOle2FrameHeader;I can fill out that structure and overwrite the first three 310 lines with the new positions. This results in the logo being placed where I intended. I only write the first 310 lines even though the fourth line has 2 bytes of lowerLeft.z because I know the Z will be zero.
Conclusion
I'm disappointed that 1) this OLE2FRAME binary blob doesn't seem to be documented and 2) the 10, 20, 30 positions are apparently just ignored. On point 2, it is worse because it wastes my time double and triple checking that I am changing them correctly, when they don't actually seem to matter at all.
If you are aware of documentation for the OLE2FRAME 310 section, please let me know. I hope this post helps those rare few who are writing their own DXF exporters.