Вставка PDF в Модель

Автор Тема: Вставка PDF в Модель  (Прочитано 14915 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Вставка PDF в Модель
« : 27-01-2016, 11:38:18 »
Добрый день!
В AutoCAD возможно вставить подложку из PDF.
В acad 2012 я это смог сделать вручную через меню как пользователь.

А как вставить автоматически программно.
В AutoCAD API есть ли какие либо функции для решения этой задачи?
И для случая вставки PDF файла, состоящего из нескольких листов
передается ли в функции какой либо аргумент с номером листа?

Нашел в интернете. Класс, который работает с этим Autodesk.AutoCAD.DatabaseServices.PdfDefinition
Только вот не могу найти свойство, которое отвечает за номер листа в PDF файле.

« Последнее редактирование: 27-01-2016, 12:32:18 от Алексей (IdeaSoft) »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Вставка PDF в Модель
« Ответ #1 : 27-01-2016, 13:02:11 »
А как вставить автоматически программно.
В AutoCAD API есть ли какие либо функции для решения этой задачи?
Есть. Пример: http://adndevblog.typepad.com/autocad/2012/04/how-to-create-a-pdf-reference-in-autocadnet.html
И для случая вставки PDF файла, состоящего из нескольких листов
передается ли в функции какой либо аргумент с номером листа?
Нет. Конечно не передаётся. pdf-файл вставляется только целиком. Так что если нужен только один лист, то нужно сохранить его как отдельный pdf-файл и вставлять его. (Я был неправ) Есть еще второй вариант - подрезка (т.е. подрезать всё, кроме этого листа) при помощи метода SetClipBoundary. Но программно это сделать сложно, так как размеры листа (и всех предыдущих листов) могут быть разными и нужно будет подсчитать куда (в какую точку) вставлять pdf-файл и как подрезать.
« Последнее редактирование: 27-01-2016, 19:59:16 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Вставка PDF в Модель
« Ответ #2 : 27-01-2016, 13:32:18 »
Нет. Конечно не передаётся. pdf-файл вставляется только целиком.
В алгоритме не нашел свойства, но вручную у меня получается выбрать номер листа.
Вот на картинке 2 вставки PDF у каждой в свойствах есть номер страницы





У меня есть мнение, что скорее AutoCAD использует внутренний API PDF, который дает фрагменты листов.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Вставка PDF в Модель
« Ответ #3 : 27-01-2016, 14:00:07 »
Мне тоже так кажется. Но для уверенности я задам вопрос в ADN DevHelp.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение Алексей (IdeaSoft) 29-01-2016, 02:00:06

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Вставка PDF в Модель
« Ответ #4 : 27-01-2016, 19:00:06 »
Оказалось всё проще. И даже вопросы в ADN DevHelp задавать не пришлось.
Ниже код, который позволяет выбрать pdf-файл для вставки и номер страницы и вставляет её.

Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.EditorInput;
  7.  
  8. // This line is not mandatory, but improves loading performances
  9. [assembly: CommandClass(typeof(Rivilis.PDFUtils))]
  10.  
  11. namespace Rivilis
  12. {
  13.   public class PDFUtils
  14.   {
  15.     [CommandMethod("pdfInsert")]
  16.     static public void DoPdfInsert()
  17.     {
  18.       Document doc = Application.DocumentManager.MdiActiveDocument;
  19.       if (doc == null) return;
  20.       Database db = doc.Database;
  21.       Editor ed = doc.Editor;
  22.  
  23.       // Запрашиваем имя pdf-файла
  24.       PromptOpenFileOptions pfo = new PromptOpenFileOptions("Выберите pdf-файл: ");
  25.       pfo.Filter = "pdf-файлы (*.pdf)|*.pdf";
  26.       PromptFileNameResult pfr = ed.GetFileNameForOpen(pfo);
  27.       if (pfr.Status != PromptStatus.OK) return;
  28.  
  29.       // Запрашиваем номер страницы
  30.       PromptIntegerOptions pio = new PromptIntegerOptions("Укажите номер страницы ");
  31.       pio.AllowNegative = false;
  32.       pio.AllowZero = false;
  33.       pio.DefaultValue = 1;
  34.       pio.UseDefaultValue = true;
  35.       PromptIntegerResult pir = ed.GetInteger(pio);
  36.       if (pir.Status != PromptStatus.OK) return;
  37.  
  38.       PromptPointResult pr = ed.GetPoint("\nУкажите точку вставки: ");
  39.       if (pr.Status != PromptStatus.OK) return;
  40.  
  41.       using (Transaction t = doc.TransactionManager.StartTransaction()) {
  42.         DBDictionary nod =
  43.           (DBDictionary)t.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
  44.         string defDictKey =
  45.           UnderlayDefinition.GetDictionaryKey(typeof(PdfDefinition));
  46.  
  47.         if (!nod.Contains(defDictKey)) {
  48.           using (DBDictionary dict = new DBDictionary()) {
  49.             nod.SetAt(defDictKey, dict);
  50.             t.AddNewlyCreatedDBObject(dict, true);
  51.           }
  52.         }
  53.  
  54.         ObjectId idPdfDef = ObjectId.Null;
  55.  
  56.         DBDictionary pdfDict =
  57.           (DBDictionary)t.GetObject(nod.GetAt(defDictKey), OpenMode.ForWrite);
  58.  
  59.         using (PdfDefinition pdfDef = new PdfDefinition()) {
  60.           pdfDef.SourceFileName = pfr.StringResult; // Путь к pdf-файлу
  61.           pdfDef.ItemName = pir.Value.ToString(); // Номер страницы
  62.           // Заменяем недопустимые символы
  63.           string name = ReplaceStrings(pfr.StringResult, @"\/ :.|", "______");
  64.           idPdfDef = pdfDict.SetAt(name + "_" + pdfDef.ItemName, pdfDef);
  65.           t.AddNewlyCreatedDBObject(pdfDef, true);
  66.         }
  67.  
  68.         BlockTable bt = (BlockTable)t.GetObject(db.BlockTableId, OpenMode.ForRead);
  69.  
  70.         BlockTableRecord btr =
  71.           (BlockTableRecord)t.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
  72.  
  73.         using (PdfReference pdf = new PdfReference()) {
  74.           pdf.Position = pr.Value; // Точка вставки
  75.           // Здесь же можно задать и размеры (масштаб)
  76.           pdf.ScaleFactors = new Scale3d(1, 1, 1);
  77.           // и угол поворота и т.д.
  78.           pdf.Rotation = 0;
  79.           pdf.DefinitionId = idPdfDef;
  80.           btr.AppendEntity(pdf);
  81.           t.AddNewlyCreatedDBObject(pdf, true);
  82.         }
  83.         t.Commit();
  84.       }
  85.     }
  86.     static string ReplaceStrings(string str, string aOldChars, string aNewChars)
  87.     {
  88.       string RetStr = str;
  89.       if (aOldChars.Length != aNewChars.Length) return str;
  90.       for (int i = 0; i < aOldChars.Length; i++) {
  91.         RetStr = RetStr.Replace(aOldChars[i], aNewChars[i]);
  92.       }
  93.       return RetStr;
  94.     }
  95.   }
  96. }

Ну и видео как это работает:



Наверное нужно поместить на сайт статью об этом, так как ни в документации, ни в интернете мне такая информация не попадалась.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Вставка PDF в Модель
« Ответ #5 : 29-01-2016, 02:01:21 »
Саша, спасибо большое!
Все же это простое свойство pdfDef.ItemName
отвечающее за номер страницы. Все просто! Ура!

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Вставка PDF в Модель
« Ответ #6 : 29-01-2016, 02:16:15 »
Все же это простое свойство pdfDef.ItemName
Да. Я был первоначально неправ, так как не работал с многостраничными pdf/dwf-подложками. Видимо не я один, так как в интернете не нашлось информации по этой теме. На мысль, что это может сработать, меня натолкнул MGDDBG (http://adn-cis.org/assets/gallery/AutoCAD/MgdDbg.zip), которым я часто пользуюсь.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Вставка PDF в Модель
« Ответ #8 : 29-01-2016, 07:48:00 »
Что еще интересного заметил.
Взял специально допустил ошибку в своем алгоритме и
в PdfDefinition записал несуществующий номер листа.
К примеру всего в PDF файле листов 7, а я записал больший номер = 8
Алгоритм отработал и файл сохранился на диске.

Когда я его захотел открыть в AutoCAd 2012.
Сразу при открытии фатальная ошибка.
В результате я просто сломал файл и не могу открыть его в AutioCAD,
по крайней мере в AutoCAd 2012. 

Стоит выложить на форум больной файл?

Вот в алгоритме выше в переменную pir пользователь вводит номер листа.
А если он введет не тот номер - получается, файл будет испорчен.
Или по другому к источнику имени файла подсунуть файл с таким же именем но с меньшим количеством листов в PDF.
И получается файл dwg уже не отрыть в AutoCAD.
Мне интересно что будет. Я хочу это проверить. 

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Вставка PDF в Модель
« Ответ #9 : 29-01-2016, 12:12:32 »
Взял специально допустил ошибку в своем алгоритме и
в PdfDefinition записал несуществующий номер листа.

Добавил проверку на валидность листа. Запрос точки вставки перенёс в более подходящее место, т.к. нет смысла запрашивать её для неверно указанного номера.

Код - C# [Выбрать]
  1. [CommandMethod("pdfInsert")]
  2. static public void DoPdfInsert() {
  3.         Document doc = Application.DocumentManager.MdiActiveDocument;
  4.         if (doc == null) return;
  5.         Database db = doc.Database;
  6.         Editor ed = doc.Editor;
  7.  
  8.         PromptOpenFileOptions pfo = new PromptOpenFileOptions(
  9.                 "Select PDF file: ");
  10.         pfo.Filter = "pdf-files (*.pdf)|*.pdf";
  11.         PromptFileNameResult pfr = ed.GetFileNameForOpen(pfo);
  12.         if (pfr.Status != PromptStatus.OK) return;
  13.  
  14.         PromptIntegerOptions pio = new PromptIntegerOptions(
  15.                 "PDF page number ");
  16.         pio.AllowNegative = false;
  17.         pio.AllowZero = false;
  18.         pio.DefaultValue = 1;
  19.         pio.UseDefaultValue = true;
  20.         PromptIntegerResult pir = ed.GetInteger(pio);
  21.         if (pir.Status != PromptStatus.OK) return;
  22.  
  23.         using (Transaction t = doc.TransactionManager.StartTransaction()) {
  24.                 DBDictionary nod =
  25.                   (DBDictionary)t.GetObject(db.NamedObjectsDictionaryId,
  26.                   OpenMode.ForWrite);
  27.                 string defDictKey =
  28.                   UnderlayDefinition.GetDictionaryKey(typeof(PdfDefinition));
  29.  
  30.                 if (!nod.Contains(defDictKey)) {
  31.                         using (DBDictionary dict = new DBDictionary()) {
  32.                                 nod.SetAt(defDictKey, dict);
  33.                                 t.AddNewlyCreatedDBObject(dict, true);
  34.                         }
  35.                 }
  36.  
  37.                 ObjectId idPdfDef = ObjectId.Null;
  38.  
  39.                 DBDictionary pdfDict =
  40.                   (DBDictionary)t.GetObject(nod.GetAt(defDictKey),
  41.                   OpenMode.ForWrite);
  42.  
  43.                 using (PdfDefinition pdfDef = new PdfDefinition()) {
  44.                         // PDF file full name
  45.                         pdfDef.SourceFileName = pfr.StringResult;
  46.                         // PDF page number
  47.                         pdfDef.ItemName = pir.Value.ToString();
  48.  
  49.                         if (!pdfDef.Loaded) {
  50.                                 ed.WriteMessage(
  51.                                         "The {0} page is not exist in that PDF file.",
  52.                                         pir.Value.ToString());
  53.                                 t.Commit();
  54.                                 return;
  55.                         }
  56.  
  57.                         string name = ReplaceStrings(pfr.StringResult,
  58.                                 @"\/ :.|", "______");
  59.                         idPdfDef = pdfDict.SetAt(name + "_" + pdfDef.ItemName,
  60.                                 pdfDef);
  61.                         t.AddNewlyCreatedDBObject(pdfDef, true);
  62.                 }
  63.  
  64.                 BlockTable bt = (BlockTable)t.GetObject(db.BlockTableId,
  65.                         OpenMode.ForRead);
  66.  
  67.                 BlockTableRecord btr =
  68.                   (BlockTableRecord)t.GetObject(bt[BlockTableRecord.ModelSpace],
  69.                   OpenMode.ForWrite);
  70.  
  71.                 PromptPointResult pr = ed.GetPoint("\nInsert point: ");
  72.                 if (pr.Status != PromptStatus.OK) return;
  73.  
  74.                 using (PdfReference pdf = new PdfReference()) {
  75.                         pdf.Position = pr.Value;
  76.                         pdf.ScaleFactors = new Scale3d(1, 1, 1);
  77.                         pdf.Rotation = 0;
  78.                         pdf.DefinitionId = idPdfDef;
  79.                         btr.AppendEntity(pdf);
  80.                         t.AddNewlyCreatedDBObject(pdf, true);
  81.                 }
  82.                 t.Commit();
  83.         }
  84. }
« Последнее редактирование: 29-01-2016, 16:26:00 от Андрей Бушман »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Вставка PDF в Модель
« Ответ #10 : 29-01-2016, 14:07:18 »
Когда я его захотел открыть в AutoCAd 2012.
Сразу при открытии фатальная ошибка.
В результате я просто сломал файл и не могу открыть его в AutioCAD,
по крайней мере в AutoCAd 2012. 
Если убрать pdf-файл, так чтобы AutoCAD его не нашёл, то AutoCAD обычно пишет в рамке на месте подложки об этом. Подложку можно удалить.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Вставка PDF в Модель
« Ответ #11 : 29-01-2016, 15:03:22 »
Если убрать pdf-файл, так чтобы AutoCAD
Да это так если файл удалить, то все хорошо AutoCAD ссылки не находит и в рамке пишет что файл не найден.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Вставка PDF в Модель
« Ответ #12 : 29-01-2016, 15:19:27 »
Да это так если файл удалить, то все хорошо AutoCAD ссылки не находит и в рамке пишет что файл не найден.
Т.е. проблема с этим файлом решена?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Re: Вставка PDF в Модель
« Ответ #13 : 29-01-2016, 16:23:35 »
Т.е. проблема с этим файлом решена?

Ну тут какая ситуация. Если файл pdf принудительно переименовать, то файл откроется без проблем.
Но это мы - программисты знаем об этом. А обычный пользователь может и не догадываться об этом.

Такая ситуация не в пользу AutoCAD. Потому что реально в работе такая ситуация может быть, т.к.
алгоритм изначально сделает все верно - запишет существующий номер страницы.
Если файл подменится (программой или человеком), то будет фатальная ошибка.

Я думаю что Autodesk должны до конца разобраться с этой, пусть и редкостной.
Пользователю же не в радость, когда файл не может открыться.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Вставка PDF в Модель
« Ответ #14 : 29-01-2016, 16:27:14 »