Русский
Русский
English
Статистика
Реклама

Postscript

Перевод Пугающие эксперименты с PDF запускаем Арканоид в документе

06.01.2021 12:20:45 | Автор: admin

Подробнее об этом хаке и особенностях его работы можно узнать из доклада на !!con 2020 Playing Breakout inside a PDF!!

Если вы его не смотрели, то попробуйте открыть файл breakout.pdf в Chrome.

Как и многие из вас, я всегда считал PDF довольно безопасным форматом: автор создаёт текст и графику, после чего он открывается в программе просмотра PDF, больше ничего не делая. Несколько лет назад я мимоходом слышал об уязвимостях Adobe Reader, но особо не задумывался о том, как они могут возникать.

Изначально Adobe сделала PDF именно для этого, но мы уже выяснили, что сегодня это совсем не так. В 1310-страничной спецификации PDF (на самом деле довольно понятном и интересном чтиве) описывается безумное количество возможностей, в том числе:


но самое интересное для нас


Разумеется, большинство программ для чтения PDF (кроме Adobe Reader) не реализует основную часть этих возможностей. Однако Chrome реализует JavaScript! Если вы откроете подобный файл PDF в Chrome, то он запустит скрипт. Я выяснил, повторив действия из этого поста о создании PDF с JS.

Однако здесь есть хитрость. Chrome реализует только крошечное подмножество огромной поверхности Acrobat JavaScript API. Реализация API в PDFium браузера Chrome в основном состоит из подобных заглушек:

FX_BOOL Document::addAnnot(IJS_Context* cc,                           const CJS_Parameters& params,                           CJS_Value& vRet,                           CFX_WideString& sError) {  // Not supported.  return TRUE;}FX_BOOL Document::addField(IJS_Context* cc,                           const CJS_Parameters& params,                           CJS_Value& vRet,                           CFX_WideString& sError) {  // Not supported.  return TRUE;}FX_BOOL Document::exportAsText(IJS_Context* cc,                               const CJS_Parameters& params,                               CJS_Value& vRet,                               CFX_WideString& sError) {  // Unsafe, not supported.  return TRUE;}

И я понимаю опасения разработчиков этот Adobe JavaScript API имеет совершенно огромную площадь поверхности. Предположительно, скрипты могут выполнять такие действия, как соединение с произвольными базами данных, распознавание подключенных мониторов, импорт внешних ресурсов и манипулирование 3D-объектами.

Поэтому в Chrome получилась такая странная ситуация: мы можем выполнять произвольные вычисления, однако имеем эту странную, ограниченную поверхность API, при которой ввод-вывод и передачу данных между программой и пользователем реализовывать очень неудобно.

Вероятно, можно встроить в PDF компилятор C, скомпилировав его в JS, например, с помощью Emscripten, но тогда компилятор C должен будет получать ввод из формы простого текста (plain text), а вывод выполнять снова в поле формы.

На самом деле, я заинтересовался PDF пару недель назад из-за PostScript; я читал посты Дона Хопкинса о NeWS напоминающей AJAX системе, но реализованной в 80-х на PostScript.

Забавно, что PDF стал реакцией на PostScript, который был слишком выразительным (являясь полнофункциональным языком программирования), слишком сложным в анализе и восприятии. Наверно, PDF по-прежнему остаётся в этом плане шагом вперёд, но всё равно смешно, что он разросся всеми этими возможностями.

Ещё один любопытный момент: как любой долгоживущий цифровой формат (лично я испытываю нежные чувства к файловой системе FAT), PDF сам по себе является своего рода историческим документом. Мы можем отследить, как поколения инженеров добавляли нужные им в своё время функции, пытаясь при этом не поломать уже существующие.

Я не совсем понимаю, зачем разработчики Chrome вообще заморачивались поддержкой JS. Они взяли код программы чтения PDF из Foxit; возможно, у Foxit был какой-то клиент, использовавший валидацию форм через JavaScript?

Кроме того, Chrome использует тот же рантайм, что и в браузере, хоть и не раскрывает браузерных API. Насколько я понимаю, это значит, что можно использовать такие возможности ES6, как стрелочные функции и прокси.

Breakout


Так что же мы можем сделать с предоставляемой нам Chrome поверхностью API?

Кстати, должен извиниться за неидеальное распознавание коллизий и непостоянную скорость игры. БОльшую часть игры я содрал с туториала.

Первые доступные пользователю точки ввода-вывода, которые я смог найти в реализации PDF API браузера Chrome, находились в Field.cpp.

Мы не можем менять цвет заливки текстового поля во время выполнения, зато можем менять прямоугольник его границ и задавать стиль границ. Мы не можем считывать точное положение мыши, однако можем при создании PDF привязать к полям скрипты mouse-enter и mouse-leave. Также во время выполнения нельзя добавлять поля: придётся ограничиться тем, что мы поместили в PDF в момент создания. Любопытно, почему разработчики выбрали именно эти методы? Это похоже на какой-то стереотип о программировании на олдскульном FORTRAN: необходимо объявлять все переменные заранее, чтобы компилятор мог статически выделить под них память.

Итак, файл PDF генерируется скриптом, заранее создающим набор текстовых полей, в том числе и игровых элементов:

  • Ракетку
  • Кирпичи
  • Мяч
  • Очки
  • Жизни

Но для правильной работы игры мы также внесём некоторые хаки.

Во-первых, мы создаём тонкую длинную полосу текстового поля для каждого столбца нижней половины экрана. Полосы получают событие mouse-enter, когда игрок перемещает мышь по оси X, поэтому ракетка может перемещаться при движении мыши.

Во-вторых, мы создаём поле под названием whole, закрывающее всю верхнюю половину экрана. Chrome не ожидает, что отображение PDF будет меняться, поэтому если перемещать поля в JS, то получатся довольно сильные артефакты. Это поле whole решает данную проблему мы включаем/отключаем его во время рендеринга кадра. Этот трюк заставляет Chrome подчищать артефакты.

Кроме того, при перемещении поля, похоже, сбрасывается его поток внешнего отображения. Выбранный вами красивый внешний вид из произвольной PDF-графики слетает и заменяется простым залитым прямоугольником с границей. Поэтому в моей игре используется упрощённый словарь характеристик внешнего вида. В самом крайнем случае указанный там цвет заливки при перемещении виджета остаётся неизменным.

Полезные ресурсы






На правах рекламы


Закажите сервер и сразу начинайте работать! Создание VDS любой конфигурации в течение минуты, в том числе серверов для хранения большого объёма данных до 4000 ГБ. Эпичненько :)

Подробнее..

Перевод Создание PDF-документа на Python с помощью pText

19.05.2021 18:19:31 | Автор: admin

Один из самых гибких и привычных способов сгенерировать pdf написать код на LaTeX и воспользоваться соответствующей программой. Но есть и другие способы, которые могут оказаться проще и понятнее, чем LaTeX. Специально к старту курса Fullstack-разработчик на Python представляем перевод статьи о том, как для генерации PDF можно воспользоваться библиотекой pText; эта статья написана Йорисом Схеллекенсом разработчиком pText.


В этом руководстве мы будем использовать pText библиотеку Python, предназначенную для чтения, обработки и создания PDF-документов. Он предлагает как низкоуровневую (позволяющую получить доступ к точным координатам и макету, если вы решите их использовать), так и высокоуровневую модель (где вы можете делегировать точные расчёты полей, позиций и т. д.). Мы рассмотрим, как создавать и проверять PDF-документ в Python, используя pText, а также как использовать некоторые LayoutElement [элементы макета] для добавления штрих-кодов и таблиц.

Portable Document Format (PDF) не является форматом WYSIWYG (что видишь, то и получаешь). Он был разработан как платформенно-независимый, не зависящий от базовой операционной системы и механизмов рендеринга.

Чтобы добиться этого, PDF был создан взаимодействовать с помощью чего-то, больше похожего на язык программирования, и полагается на серию инструкций и операций для достижения результата. Фактически PDF основан на языке сценариев PostScript, который был первым независимым от устройства языком описания страниц. В нём есть операторы, которые изменяют графические состояния, на высоком уровне они выглядят примерно так:

  • Установить шрифт Helvetica.

  • Установить чёрный цвет обводки.

  • Перейти к (60,700).

  • Нарисовать глиф "H".

Это объясняет несколько вещей:

  • Почему так сложно точно извлечь текст из PDF.

  • Почему сложно редактировать PDF-документ.

  • Почему большинство библиотек PDF применяют очень низкоуровневый подход к созданию контента (вы должны указать координаты, в которых следует отображать текст, поля и т. д.).

Установка pText

pText можно загрузить c GitHub или установить через pip:

$ pip install ptext-joris-schellekens

Примечание. На момент написания статьи в версии 1.8.6 по умолчанию не устанавливаются внешние зависимости, такие как python-barcode и qrcode. Если появится сообщение об ошибке, установите их вручную:

$ pip install qrcode python-barcode requests

Создание PDF-документа на Python с помощью pText

pText имеет два интуитивно понятных ключевых класса Document и Page, которые представляют документ и страницы в нём. Это основная структура для создания PDF-документов. Кроме того, класс PDF представляет собой API для загрузки и сохранения создаваемых нами документов. Имея это в виду, давайте создадим пустой файл PDF:

from ptext.pdf.document import Documentfrom ptext.pdf.page.page import Pagefrom ptext.pdf.pdf import PDF# Create an empty Documentdocument = Document()# Create an empty pagepage = Page()# Add the Page to the Documentdocument.append_page(page)# Write the Document to a filewith open("output.pdf", "wb") as pdf_file_handle:    PDF.dumps(pdf_file_handle, document)

Большая часть кода здесь говорит сама за себя. Мы начинаем с создания пустого документа, затем добавляем пустую страницу в документ с помощью функции append() и, наконец, сохраняем файл с помощью PDF.dumps().

Стоит отметить, что мы использовали флаг "wb" для записи в двоичном режиме, поскольку мы не хотим, чтобы Python кодировал этот текст. Это даёт нам пустой PDF-файл с названием output.pdf в вашей файловой системе:

Создание документа Hello World с помощью pText

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

Подобно двум классам, описанным ранее, чтобы добавить контент на страницу, мы добавим PageLayout, указывающий на тип макета, который мы хотели бы видеть, и добавим один или несколько абзацев в этот макет.

С этой целью Document является экземпляром самого низкого уровня в иерархии объектов, а Paragraph экземпляром самого высокого уровня, размещённым поверх PageLayout и, следовательно, страницы. Давайте добавим абзац на нашу страницу:

from ptext.pdf.document import Documentfrom ptext.pdf.page.page import Pagefrom ptext.pdf.pdf import PDFfrom ptext.pdf.canvas.layout.paragraph import Paragraphfrom ptext.pdf.canvas.layout.page_layout import SingleColumnLayoutfrom ptext.io.read.types import Decimaldocument = Document()page = Page()# Setting a layout manager on the Pagelayout = SingleColumnLayout(page)# Adding a Paragraph to the Pagelayout.add(Paragraph("Hello World", font_size=Decimal(20), font="Helvetica"))document.append_page(page)with open("output.pdf", "wb") as pdf_file_handle:    PDF.dumps(pdf_file_handle, document)

Вы заметите, что мы добавили 2 дополнительных объекта:

  • Экземпляр PageLayout, более конкретный через его подкласс SingleColumnLayout: этот класс отслеживает, где контент добавляется на страницу, какие области доступны для будущего контента, каковы поля страницы и какие ведущие (пространство между объектами Paragraph) должно быть.

Поскольку здесь мы работаем только с одним столбцом, мы используем SingleColumnLayout. В качестве альтернативы мы можем использовать MultiColumnLayout.

  • Экземпляр Paragraph: этот класс представляет блок текста. Вы можете установить такие свойства, как шрифт, font_size, font_color, и многие другие. Дополнительные примеры вы можете найти в документации.

Код генерирует файл output.pdf, содержащий наш абзац:

Проверка созданного PDF с помощью pText.

Примечание: этот раздел является необязательным, если вас не интересует внутренняя работа PDF-документа.

Но может быть очень полезно немного узнать о формате (например, при отладке классической проблемы почему мой контент теперь отображается на этой странице). Обычно программа для чтения PDF читает документ, начиная с последних байтов:

xref0 110000000000 00000 f0000000015 00000 n0000002169 00000 n0000000048 00000 n0000000105 00000 n0000000258 00000 n0000000413 00000 n0000000445 00000 n0000000475 00000 n0000000653 00000 n0000001938 00000 ntrailer<</Root 1 0 R /Info 2 0 R /Size 11 /ID [<61e6d144af4b84e0e0aa52deab87cfe9><61e6d144af4b84e0e0aa52deab87cfe9>]>>startxref2274%%EOF

Здесь мы видим маркер конца файла (%% EOF) и таблицу перекрестных ссылок (обычно сокращённо xref).

Внешняя ссылка ограничена токенами startxref и xref.

Внешняя ссылка (в документе может быть несколько) действует как справочная таблица для программы чтения PDF-файлов.

Он содержит байтовое смещение (начиная с верхней части файла) каждого объекта в PDF. Первая строка внешней ссылки (0 11) говорит, что в этой внешней ссылке 11 объектов и что первый объект начинается с номера 0.

Каждая последующая строка состоит из байтового смещения, за которым следует так называемый номер поколения и буква f или n:

  • Объекты, отмеченные буквой f, являются свободными, их рендеринг не ожидается.

  • Объекты, отмеченные буквой n, используются.

Внизу xref мы находим словарь трейлеров. Словари в синтаксисе PDF разделяются символами << и >>. В этом словаре есть следующие пары:

  • /Root 1 0 R

  • /Info 2 0 R

  • /Size 11

  • /ID [<61e6d144af4b84e0e0aa52deab87cfe9> <61e6d144af4b84e0e0aa52deab87cfe9>]

Словарь трейлеров является отправной точкой для программы чтения PDF-файлов и содержит ссылки на все другие данные. В этом случае:

  • /Root: это ещё один словарь, который ссылается на фактическое содержание документа.

  • /Info: это словарь, содержащий метаинформацию документа (автор, название и так далее).

Строки типа 1 0 R в синтаксисе PDF называются ссылками. И здесь нам пригодится таблица xref. Чтобы найти объект, связанный с 1 0 R, мы смотрим на объект 1 (номер поколения 0). Таблица поиска xref сообщает нам, что мы можем ожидать найти этот объект в 15-м байте документа. Если проверить это, то обнаружим:

1 0 obj<</Pages 3 0 R>>endobj

Обратите внимание, что тот объект начинается с 1 0 obj и заканчивается endobj. Это ещё одно подтверждение того, что мы на самом деле имеем дело с объектом 1. Этот словарь говорит нам, что мы можем найти страницы документа в объекте 3:

3 0 obj<</Count 1 /Kids [4 0 R] /Type /Pages>>endobj

Это словарь /Pages, и он сообщает нам, что в этом документе одна страница (запись /Count). Запись для /Kids обычно представляет собой массив с одной ссылкой-объектом на страницу. Мы можем ожидать найти первую страницу в объекте 4:

4 0 obj<</Type /Page /MediaBox [0 0 595 842] /Contents 5 0 R /Resources 6 0 R /Parent 3 0 R>>endobj

Этот словарь содержит несколько интересных записей:

  • /MediaBox: физические размеры страницы (в данном случае страница формата A4).

  • /Contents: ссылка на (обычно сжатый) поток операторов содержимого PDF.

  • /Resources: ссылка на словарь, содержащий все ресурсы (шрифты, изображения и так далее), используемые для рендеринга этой страницы.

Давайте проверим объект 5, чтобы узнать, что на самом деле отображается на этой странице:

5 0 obj<</Filter /FlateDecode /Length 85>>streamxR@\<`aw3T0!K3Benl7'999E9)!Y(!8yT*endstreamendobj

Как упоминалось ранее, этот поток содержимого сжимается. Вы можете определить, какой метод сжатия использовался, с помощью записи /Filter. Если мы применим распаковку (unzip) к объекту 5, то мы должны получить фактические операторы содержимого:

5 0 obj<</Filter /FlateDecode /Length 85>>stream            q            BT            0.000000 0.000000 0.000000 rg            /F1 1.000000 Tf                        20.000000 0 0 20.000000 60.000000 738.000000 Tm                        (Hello world) Tj            ET                        Qendstreamendobj

Наконец, мы находимся на уровне, где можем декодировать контент. Каждая строка состоит из аргументов, за которыми следует их оператор. Быстро пройдёмся по операторам:

  • q: сохранить текущее графическое состояние (помещая его в стек);

  • BT: начать текст;

  • 0 0 0 rg: установить текущий цвет обводки на (0,0,0) rgb. Это чёрный;

  • /F1 1 Tf: установить текущий шрифт на /F1 (это запись в словаре ресурсов, упомянутом ранее) и размер шрифта на 1.

  • 20.000000 0 0 20.000000 60.000000 738.000000 Tm: установить текстовую матрицу, что требует отдельного руководства. Достаточно сказать, что эта матрица регулирует размер шрифта и положение текста. Здесь мы масштабируем шрифт до размера 20 и устанавливаем курсор для рисования текста на 60 738. Система координат PDF начинается в нижнем левом углу страницы. Итак, 60 738 находится где-то рядом с левым верхом страницы (с учётом того, что высота страницы составляет 842 единицы).

  • (Hello world) Tj: строки в синтаксисе PDF разделяются ( и ). Эта команда указывает программе чтения PDF-файлов отобразить строку Hello world в позиции, которую мы указали ранее с помощью текстовой матрицы, в шрифте, размере и цвете, которые мы указали в командах перед этим.

  • ET: конец текста.

  • Q: извлечь состояние графики из стека (таким образом восстанавливая состояние графики).

Добавление других элементов макета pText на страницы

pText поставляется с широким спектром объектов LayoutElement. В предыдущем примере мы кратко исследовали Paragraph. Но есть и другие элементы, такие как UnorderedList, OrderedList, Image, Shape, Barcode и Table. Давайте создадим чуть более сложный пример с таблицей и штрих-кодом. Таблицы состоят из TableCells, которые мы добавляем в экземпляр Table. Штрих-код может быть одним из многих типов штрих-кода мы будем использовать QR-код:

from ptext.pdf.document import Documentfrom ptext.pdf.page.page import Pagefrom ptext.pdf.pdf import PDFfrom ptext.pdf.canvas.layout.paragraph import Paragraphfrom ptext.pdf.canvas.layout.page_layout import SingleColumnLayoutfrom ptext.io.read.types import Decimalfrom ptext.pdf.canvas.layout.table import Table, TableCellfrom ptext.pdf.canvas.layout.barcode import Barcode, BarcodeTypefrom ptext.pdf.canvas.color.color import X11Colordocument = Document()page = Page()# Layoutlayout = SingleColumnLayout(page)# Create and add headinglayout.add(Paragraph("DefaultCorp Invoice", font="Helvetica", font_size=Decimal(20)))# Create and add barcodelayout.add(Barcode(data="0123456789", type=BarcodeType.QR, width=Decimal(64), height=Decimal(64)))# Create and add tabletable = Table(number_of_rows=5, number_of_columns=4)# Header rowtable.add(TableCell(Paragraph("Item", font_color=X11Color("White")), background_color=X11Color("SlateGray")))table.add(TableCell(Paragraph("Unit Price", font_color=X11Color("White")), background_color=X11Color("SlateGray")))table.add(TableCell(Paragraph("Amount", font_color=X11Color("White")), background_color=X11Color("SlateGray")))table.add(TableCell(Paragraph("Price", font_color=X11Color("White")), background_color=X11Color("SlateGray")))# Data rowsfor n in [("Lorem", 4.99, 1), ("Ipsum", 9.99, 2), ("Dolor", 1.99, 3), ("Sit", 1.99, 1)]:    table.add(Paragraph(n[0]))    table.add(Paragraph(str(n[1])))    table.add(Paragraph(str(n[2])))    table.add(Paragraph(str(n[1] * n[2])))# Set paddingtable.set_padding_on_all_cells(Decimal(5), Decimal(5), Decimal(5), Decimal(5))layout.add(table)# Append pagedocument.append_page(page)# Persist PDF to filewith open("output4.pdf", "wb") as pdf_file_handle:    PDF.dumps(pdf_file_handle, document)

Некоторые детали реализации:

  • pText поддерживает различные цветовые модели, в том числе RGBColor, HexColor, X11Color и HSVColor.

  • Вы можете добавлять объекты LayoutElement непосредственно в объект Table, но вы также можете обернуть их объектом TableCell, это даёт вам некоторые дополнительные параметры, такие как col_span и row_span или, в данном случае, background_color.

  • Если font, font_size или font_color не указаны, Paragraph примет значение по умолчанию Helvetica, размер 12, чёрный.

Код сгенерирует такой документ:

Заключение

В этом руководстве мы рассмотрели pText библиотеку для чтения, записи и управления файлами PDF. Мы рассмотрели ключевые классы, такие как Document и Page, а также некоторые элементы, такие как Paragraph, Barcode и PageLayout. Наконец, мы создали несколько PDF-файлов с различным содержимым, а также проверили, как PDF-файлы хранят данные под капотом.

Документ PDF приятен глазу и достаточно удобен для того, чтобы использовать его в электронном документообороте, для генерации разнообразных счетов и отчётов, особенно актуальных в крупных организациях и в их внутренней сети, поэтому разработка крупных и сложных веб-проектов часто сопряжена с генерацией PDF. Если вам интересна работа со сложными веб-проектами и не хочется выбирать между бэком или фронтом, то вы можете присмотреться к курсу Fullstack-разработчик на Python.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Рисуем молекулы с помощью PostScript

18.04.2021 18:19:42 | Автор: admin

Векторная графика очень удобна для иллюстраций. Молекулы состоят из атомов соединённых связями. Хочется, чтобы операции редактирования рисунка химической структуры осуществлялись согласно физическому устройству молекул: выделил атом, перенес его, повернул фрагмент молекулы, подписал Практически все визуализаторы атомных структур экспортируют вид в растр, что усложняет подготовку иллюстраций. В этой заметке я расскажу о способе отрисовки 3D структур в векторном формате, а также о том, как в этом поможет язык PostScript.

Вместо красивой растровой картинки (слева) получим винтажную иллюстрацию (справа).Вместо красивой растровой картинки (слева) получим винтажную иллюстрацию (справа).

Достаточно много программ умеют экспортировать структуру в векторную графику: SVG, PDF, EPS. Однако, часто это сделано лишь формально - полученные изображения состоят из множества примитивов, разобрать их по атомам и связям практически невозможно. Размер такого векторного файла тоже большой, словом, беда. Из множества молекулярных конструкторов лишь два удовлетворяют по качеству кода векторной картинки: GaussView и Molden. Последняя программа доступна всем желающим, так что примеры построены с её помощью, тем не менее, все приведенные ниже рецепты применимы (с некоторыми модификациями) и к векторным иллюстрациям сделанными программой GaussView. Итак, Molden!

MoldenMolden

Открываем файл со структурой, сохраняем в PostScript.

PostScript

В файле видим человеческий текст:

%!PS-Adobe-2.0 EPSF-2.0%%Title: Molden%%For: Schaft%%Creator: Drs G Schaftenaar%%DocumentFonts: Courier%%Pages (atend)%%BoundingBox: 0 0 612 792%%EndComments%%###### User Preferences ############%%---- SIZE AND ORIENTATION OF THE PLOT ---%/size    {  0.24 } def%---- These number can be negative -------/originx {  39.0 } def/originy { 753.0 } def/angle   { -90.0 } def%For Portrait use%/originx { 40.0 } def%/originy { 240.0 } def%/angle   { 0.0 } def%and BoundingBox: 25 255 535 765

За отрисовку сфер-атомов отвечает процедура \doatom, за стержни - \dorod. Сначала отключим вывод логотипа Molden.

%---- Include Tabel & Logo, Fontsize -----/tabel {true} def/titleandlogo {true} def % ставим здесь false!

Без дальнейших модификаций рисунок будет таким, 4082 графических примитива. Несколько неудобно.

4082 примитива4082 примитива

Число примитивов можно значительно сократить небольшой правкой.

%---- SET BOND RENDERING:  ---------------%---- shadedrod, whiterod, blackrod  -----%/doatom { dosketchysmoothatom } def /dorod  { sketchyshadedrod }    def%% облегченные версии (меньше примитивов)/dosketchysmoothatom  % вместо прежнего doatom{ gsave  rx ry translate  90 -15 1 % вместо прежнего цикла 90 1 1 - это единственное изменение  { gsave    dup cos hue exch satu exch sethsbcolor sin dup scale    newpath    0 0 rad 0 360 arc    closepath fill grestore } for    grestore } def/sketchyshadedrod{ gsave  x1 y1 translate  x2 x1 neg add  y2 y1 neg add  {atan neg rotate} stopped not {  85 -15 0 % вместо 87 -3 0 - это единственное изменение  {dup  gsave  newpath   cos 1.0 cosb 0.5 mul neg add mul   hue exch satu exch sethsbcolor   sin 1.0 scale   1 cosb scale   0 0 hd 0 180 arcn   x2 x1 neg add dup mul   y2 y1 neg add dup mul   add sqrt  0 cosb eq {/cosb 1.0 def} if 0 exch cosb div translate   0 0 hd 180 360 arc  closepath fill  grestore } for  } if  grestore } def
Здесь уже 410 примитивов вместо 4082.Здесь уже 410 примитивов вместо 4082.

Пойдем дальше и напишем на сей раз свои собственные процедуры!

/doatom { docirclecoloratom } def/dorod { dostick } def% ширина связи, цвет её линии, толщина штриха/stickwidth {16} def/stickgreycolor  {0} def/strokelinewidth {4} def/docirclecoloratom{ gsave    strokelinewidth setlinewidth    rx ry translate    newpath 0 0 rad 0 360 arc closepath    gsave    hue satu 1.0 sethsbcolor fill    grestore    stroke    0 0 rad 0.75 mul -60 0 arc    stroke    grestore} def% процедура dostick уже создана Molden

Этот код произведет такую картинку:

Это очень простой рисунок, легковесный. Каждый атом - 3 примитива. Окружность, окрашенный круг, дуга. Связь - одна линия. Легко разобрать на запчасти и сделать всё что угодно.

/docircleatom{ gsave    strokelinewidth setlinewidth    rx ry translate    newpath 0 0 rad 0 360 arc closepath    gsave    1 setgray fill    grestore    stroke    gsave    1.00 0.55 scale    0 0 rad 0 180 arc    stroke    grestore    0.55 1.00 scale    0 0 rad -90 90 arcn    stroke    grestore} def

Этот код радикально сведет рисунок к черному и белому. Как в старых книгах.

Я добавил подпись - длину водородной связи. Я добавил подпись - длину водородной связи.

Заключение

PostScript удивительно хорош в создании иллюстраций. Он лёгок в освоении. В этой заметке я привёл способ как сделать простые, но подчас очень и очень нужные вещи при подготовке публикации или постера на конференцию. Однако, можно пойти дальше! Очень рекомендую книгу Mathematical Illustrations.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru