DWG to PDF conversion & Block Insertion

Hi,

I am trying to create a utility for converting DWG file to PDF & Block Insertion of a DWG signature into another DWG drawing. I am facing 2 issues: 1. In DWG to PDF conversion, it is not converting as per CTB file I am providing the program & 2. Whenever I am saving the resultant file after block insertion, it is getting corrupted.

Please help me resolve these issues.

@osmanrabbani

Can you please provide more details about the code you are using for DWG to PDF conversion and block insertion? Additionally, what specific CTB file settings are you trying to apply?

@osmanrabbani,
Hi.
Please provide code samples and all files so we can reproduce the issue.

using System;
using System.Collections.Generic;
using System.IO;
using Aspose.CAD;
using Aspose.CAD.ImageOptions;

class Program
{
static void Main(string[] args)
{
// Ensure you set the correct path to your DWG file and provide streams for CTB or CTP files
string dwgFilePath = “/Users/ozzierabbani/Downloads/input.dwg”;
string pdfOutputPath = “/Users/ozzierabbani/Downloads/output.pdf”;
string ctbFilePath = “/Users/ozzierabbani/Downloads/MYSTD CTB.ctb”;

    try
    {
        // Load the DWG file
        using (var image = Image.Load(dwgFilePath))
        {
            // Create an instance of CadRasterizationOptions
            var rasterizationOptions = new CadRasterizationOptions
            {
                PageWidth = 1600,
                PageHeight = 1600,
                AutomaticLayoutsScaling = true,
                BackgroundColor = Color.Transparent,
                NoScaling = true,
                Margins = new Margins { Left = 5, Right = 5, Top = 5, Bottom = 5 }
            };

            // Prepare streams for CTB or CTP files
            rasterizationOptions.CtbSources = new Dictionary<string, Stream>
            {
                { "CTB1", File.OpenRead(ctbFilePath) }
            };

            // Create an instance of PdfOptions
            var pdfOptions = new PdfOptions
            {
                VectorRasterizationOptions = rasterizationOptions
            };

            // Save the DWG as PDF
            image.Save(pdfOutputPath, pdfOptions);
        }

        Console.WriteLine("DWG file has been successfully converted to PDF.");
    }
    catch (Exception ex)
    {
        Console.WriteLine("An error occurred: " + ex.Message);
    }
}

}

using Aspose.CAD;
using Aspose.CAD.FileFormats.Cad;
using Aspose.CAD.FileFormats.Cad.CadObjects;
using Aspose.CAD.FileFormats.Cad.CadTables;
using System;
using System.Collections.Generic;
using System.IO;

namespace NewSignInsert;

class DWGInsertionProgram
{
static void Main(string[] args)
{
try
{
// Load the larger DWG file (testSI.dwg)
string largerDwgPath = “/Users/ozzierabbani/Downloads/larger.dwg”;
if (!File.Exists(largerDwgPath))
{
Console.WriteLine("Larger DWG file not found: " + largerDwgPath);
return;
}
CadImage largerDwgImage = (CadImage)Image.Load(largerDwgPath);
Console.WriteLine("Loaded larger DWG file: " + largerDwgPath);

        // Create a new insert object
        CadInsertObject newInsert = new CadInsertObject
        {
            Name = "foreground",
            ObjectHandle = Guid.NewGuid().ToString(), // Generate a unique ID
            LayerName = "0",
            InsertionPoint = new Cad3DPoint(124.2197, 54.0834, 0) // Assuming Z = 0 for 2D
        };
        Console.WriteLine("Created new insert object.");

        // Load the smaller DWG file (1228626.dwg)
        string smallerDwgPath = "/Users/ozzierabbani/Downloads/DIGITAL SIGNATURE/KAPP User Signatures/1228626.dwg";
        if (!File.Exists(smallerDwgPath))
        {
            Console.WriteLine("Smaller DWG file not found: " + smallerDwgPath);
            return;
        }
        CadImage smallerDwgImage = (CadImage)Image.Load(smallerDwgPath);
        Console.WriteLine("Loaded smaller DWG file: " + smallerDwgPath);

        // Create a new block entity and set the XRef path
        CadBlockEntity newBlock = new CadBlockEntity
        {
            XRefPathName = "1228626.dwg"
        };
        Console.WriteLine("Created new block entity.");

        // Add the block entity to the block dictionary
        if (largerDwgImage.BlockEntities == null)
        {
            Console.WriteLine("BlockEntities is null in the larger DWG image.");
            return;
        }
        CadBlockDictionary allBlocks = largerDwgImage.BlockEntities;
        allBlocks.Add(newInsert.Name, newBlock);
        largerDwgImage.BlockEntities = allBlocks;
        Console.WriteLine("Added block entity to block dictionary.");

        // Add the insert object to the entities list
        if (largerDwgImage.Entities == null)
        {
            Console.WriteLine("Entities is null in the larger DWG image.");
            return;
        }
        List<CadEntityBase> entities = new List<CadEntityBase>(largerDwgImage.Entities)
        {
            newInsert
        };
        largerDwgImage.Entities = entities.ToArray();
        Console.WriteLine("Added insert object to entities list.");

        // Find the block table object reference
        if (largerDwgImage.BlocksTables == null)
        {
            Console.WriteLine("BlocksTables is null in the larger DWG image.");
            return;
        }
        CadBlockTableObject? blockTableObjectReference = null;
        foreach (CadBlockTableObject tableObject in largerDwgImage.BlocksTables)
        {
            if (string.Equals(tableObject.HardPointerToLayout, largerDwgImage.Layouts["Model"].ObjectHandle))
            {
                blockTableObjectReference = tableObject;
                break;
            }
        }
        if (blockTableObjectReference == null)
        {
            Console.WriteLine("Block table object reference not found.");
            return;
        }
        Console.WriteLine("Found block table object reference.");

        // If found, update the entities of the referenced block entity
        if (blockTableObjectReference != null && largerDwgImage.BlockEntities.ContainsKey(blockTableObjectReference.BlockName))
        {
            CadBlockEntity cadBlockEntity = largerDwgImage.BlockEntities[blockTableObjectReference.BlockName];
            if (cadBlockEntity == null || cadBlockEntity.Entities == null)
            {
                Console.WriteLine("Referenced block entity or its entities are null.");
                return;
            }
            List<CadEntityBase> blockEntities = new List<CadEntityBase>(cadBlockEntity.Entities)
            {
                newInsert
            };
            cadBlockEntity.Entities = blockEntities.ToArray();
            Console.WriteLine("Updated entities of the referenced block entity.");
        }

        // Check if the output file exists and delete if it does
        string newDwgPath = "/Users/ozzierabbani/Downloads/test_file.dwg";
        if (File.Exists(newDwgPath))
        {
            File.Delete(newDwgPath);
            Console.WriteLine("Existing output file deleted.");
        }

        // Save the modified larger DWG image as a new file using FileStream
        // using (FileStream fs = new FileStream(newDwgPath, FileMode.Create))
        // {
        //     largerDwgImage.Save(fs);
        // }
        // Console.WriteLine("DWG file has been successfully created: " + newDwgPath);
        using (MemoryStream ms = new MemoryStream())
        {
            largerDwgImage.Save(ms);

            // Write the MemoryStream to a file
            File.WriteAllBytes(newDwgPath, ms.ToArray());
        }
        Console.WriteLine("DWG file has been successfully created: " + newDwgPath);
    }
    catch (Exception ex)
    {
        Console.WriteLine("An error occurred: " + ex.Message);
        if (ex.InnerException != null)
        {
            Console.WriteLine("Inner exception: " + ex.InnerException.Message);
        }
        Console.WriteLine("Stack Trace: " + ex.StackTrace);
    }
}

}

@osmanrabbani,
thank you, please attach the initial DWG and CTB file also.

Hi please find attached the ctb file. I can’t provide you the dwg at the moment as I will need to get some permissions ,but you can use it in any dwg file for ProgeCAD or AutoCAD. In the meantime I will try to get you a dwg file as well.

MyCTB.zip (3.4 KB)

Can you please also help me with the block insertion code?

I want to be able to insert a small drawing (dwg) file into a larger drawing (dwg).

Thanks.

Hi, can you please also help me with the block insertion code?

I want to be able to insert a small drawing (dwg) file into a larger drawing (dwg).

Thanks.

@osmanrabbani,
please note that DWG file refers to CTB file by name. That’s why we need both original files to see this relation and check it. You may also simplify the content of the initial DWG and remove some content, we need only that part of it that is affected by CTB for this case.

Okay. I will be providing you with the dwg file shortly.

Can you please help me with the block insertion code?

@oleksii.gorokhovatskyi

@osmanrabbani,
Here is the basic example that should work in common, but currently works for saving to PDF. We have created CADNET-9887 to investigate why it doesn’t work for export to DWG.

using (CadImage cadImage = (CadImage)Aspose.CAD.Image.Load("Larger.dwg"))
{
	string newObjectID = "FFFFFF";

	if (cadImage.Header.HeaderProperties.ContainsKey(CadHeaderAttribute.HANDSEED))
	{
		newObjectID = ((CadStringParameter)cadImage.Header.HeaderProperties[CadHeaderAttribute.HANDSEED][0]).Value;

		int nextAvailableID = int.Parse(newObjectID, System.Globalization.NumberStyles.HexNumber) + 1;

		((CadStringParameter)cadImage.Header.HeaderProperties[CadHeaderAttribute.HANDSEED][0]).Value = nextAvailableID.ToString("X");
	}

	// inserts dwg inside dwg
	CadInsertObject newInsert = new CadInsertObject();
	newInsert.Name = "smaller";
	newInsert.ObjectHandle = newObjectID;
	newInsert.LayerName = "0";
	newInsert.InsertionPoint.X = 20;
	newInsert.InsertionPoint.Y = 30;

	CadBlockDictionary allBlocks = cadImage.BlockEntities;
	CadBlockEntity newBlock = new CadBlockEntity();
	newBlock.XRefPathName = "Smaller.dwg";
	newBlock.BlockHandle = "66";
	allBlocks.Add(newInsert.Name, newBlock);
	cadImage.BlockEntities = allBlocks;


	List<CadEntityBase> entities = new List<CadEntityBase>(cadImage.Entities);
	entities.Add(newInsert);
	cadImage.Entities = entities.ToArray();

	CadBlockTableObject blockTableObjectReference = null;
	CadBlockEntity cadBlockEntity = null;

	foreach (CadBlockTableObject tableObject in cadImage.BlocksTables)
	{
		if (string.Equals(
			tableObject.HardPointerToLayout,
			cadImage.Layouts["Model"].ObjectHandle))
		{
			blockTableObjectReference = tableObject;
			break;
		}
	}

	if (blockTableObjectReference != null
		&& cadImage.BlockEntities.ContainsKey(blockTableObjectReference.BlockName))
	{
		cadBlockEntity = cadImage.BlockEntities[blockTableObjectReference.BlockName];
	}

	List<CadEntityBase> blockEntities = new List<CadEntityBase>(cadBlockEntity.Entities);
	blockEntities.Add(newInsert);
	cadBlockEntity.Entities = blockEntities.ToArray();

	cadImage.UpdateSize();
	cadImage.Save("oneInsideOther.dwg");
}

Please consider another opportunity to create empy block before and replace its content:

using (CadImage cadImage = (CadImage)Aspose.CAD.Image.Load("LargerWithEmpty.dwg"))
{
    CadInsertObject insert = null;

    foreach (CadEntityBase cadEntityBase in cadImage.Entities)
    {
        if (cadEntityBase is CadInsertObject)
        {
            CadInsertObject cadInsert = (CadInsertObject)cadEntityBase;

            if (cadInsert.Name == "Empty")
            {
                insert = cadInsert;
                break;
            }
        }
    }

    insert.InsertionPoint.X = 20;
    insert.InsertionPoint.Y = 30;

    CadBlockDictionary allBlocks = cadImage.BlockEntities;

    CadBlockEntity block = cadImage.BlockEntities["Empty"];
    block.XRefPathName = "Smaller.dwg";

    using (CadImage cadImage2 = (CadImage)Aspose.CAD.Image.Load("Smaller.dwg"))
    {
        block.Entities = new List<CadEntityBase>(cadImage2.Entities);
    }

   cadImage.Save("oneInsideOther.dwg");
}

Test files.zip (99.2 KB)

@oleksii.gorokhovatskyi
@Professionalize.Discourse

Hi please find attached the ctb & test dwg file for PDF conversion. The issue that is arising is that the CTB logic is not being implemented in the final pdf & certain areas are completely blacked out.
A0_85090_4G_13XX TEST PRINT.zip (353.5 KB)

MyCTB.zip (3.4 KB)

A0_85090_4G_13XX_TEST_PRINT.pdf (1.5 MB)

this is the pdf.

@osmanrabbani,
Hello,
The DWG refers to “NPCIL STD CTB.ctb” so this file name should be used. Please find the example below and attached result. Could you please clarify which areas are not correct?

// I have put this file near the initial DWG
string ctbFilePath = "NPCIL STD CTB.ctb";

using (CadImage cadImage = (CadImage)Aspose.CAD.Image.Load("A0_85090_4G_13XX TEST PRINT.dwg"))
{
  CadRasterizationOptions options = new CadRasterizationOptions();

  options.CtbSources = new Dictionary<string, Stream>
  {
	  { "NPCIL STD CTB.ctb", File.OpenRead(ctbFilePath) }
  };

  // color mode is set up
  options.DrawType = CadDrawTypeMode.UseObjectColor;

  PdfOptions pdfOptions = new PdfOptions();
  pdfOptions.VectorRasterizationOptions = options;

  cadImage.Save("A0_85090_4G_13XX TEST PRINT.dwg.pdf", pdfOptions);

  foreach (KeyValuePair<string, Stream> streamSource in options.CtbSources)
  {
	  streamSource.Value.Dispose();
  }
}

A0_85090_4G_13XX TEST PRINT.dwg.pdf (1.7 MB)

@oleksii.gorokhovatskyi

Hi. Should all the dwgs that need to be converted have the “ctb” attached in the dwg files itself?

Also,

Here:
// I have put this file near the initial DWG
string ctbFilePath = “NPCIL STD CTB.ctb”;

Do I need to give the path to the ctb file in my local PC?

@oleksii.gorokhovatskyi
New_A0_85090_4G_13XX TEST PRINT.pdf (488.5 KB)

The resultant pdf is very light, some areas are blacked out & others are faded.
The pdf I have attached is the kind of result that I need. Will it be possible with Aspose.

@osmanrabbani,
Hi,
the drawing may not use CTB files, e.g., you can put None there like in this picture.
PlotStyleTable.png (9.3 KB)

If the drawing contains CTB table we try to search .ctb file near the drawing file by default. You can test the example above - it should produce the same result without using options.CtbSources. If you need to use CTB from some other path please load it here from ctbFilePath:

...
options.CtbSources = new Dictionary<string, Stream>
  {
	  { "NPCIL STD CTB.ctb", File.OpenRead(ctbFilePath) }
  };
...

The key in options.CtbSources dictionary should correspond to the filename the drawing refers to. You can find this useful to get this filename:

System.Console.WriteLine(cadImage.Layouts["Model"].CurrentStyleSheet);

Is this black area incorrect? Which else are not correct?

BlackArea.png (22.1 KB)

How did you get the desired result?