Сохранение прокручиваемой панели в формате PDF с использованием .NET - PullRequest
4 голосов
/ 20 апреля 2011

У меня есть панель, заполненная множеством элементов управления для пользователей.К ним относятся текстовые поля, флажки, радиокнопки и т. Д. Это длинная форма для заполнения, поэтому элементы управления находятся на прокручиваемой панели.Что мне нужно, это сохранить всю панель в формате PDF.Я думаю, что PDFsharp - хорошая библиотека, позволяющая сохранять любой текст или изображение в виде файла PDF, но я не хочу писать код для каждого элемента управления внутри панели.Однажды я написал класс для создания PDF-файла из объекта Control.Он перебирает все внутренние элементы управления (и их внутренние элементы управления до тех пор, пока не останется никакого внутреннего элемента управления) данного элемента управления и записывает их свойство Text (да / нет для проверяемых элементов управления) в pdf, используя их свойства Location и Size.Я не мог найти его сейчас, но помню, что у него были проблемы с некоторыми элементами управления DevExpress, которые я использую, поэтому я не стал писать его снова. (Редактировать: мне пришлось, вы можете найти его ниже.) Я думаю, было бы неплохо сделать снимок экрана и сохранить это изображение в формате pdf, но я не мог найти, как этого добиться. Этот вопрос кажется, но ответа на этот вопрос нет удовлетворительного.

Итак, скриншот или нет, я открыт для любых советов.Там должно быть много случаев, когда пользователи должны заполнять длинные формы и иметь возможность сохранить его в формате PDF.Опять же, любые советы или обходные пути будут оценены.(Я думаю о создании формы с использованием html, отображении ее в элементе управления WebBrowser и использовании html to pdf библиотеки, но я действительно предпочитаю использовать мою существующую форму)

Большое спасибо.


Редактировать: Мне пришлось написать что-то итерирующее внутренние элементы управления контейнерного элемента управления (например, панели) и записать каждый внутренний элемент управления в pdf, используя их свойства Location, Size и Font, хотя я не рекомендую использоватьэто (по крайней мере, как есть) из-за них:

  1. Он устанавливает размер страницы в соответствии с размером элемента управления и использует только одну (обычно огромную) страницу PDF.Вы можете добавить логику, чтобы разделить ее на страницы, если вам нужно.(Я этого не сделал, но, думаю, вам, вероятно, понадобится ваш PDF-файл, более дружественный к принтеру).
  2. Метод Cheeso (использующий FlowDocument) является гораздо более «законным» способом для такой задачи, как эта.Я предпочитаю использовать это, но у меня не было выбора в этом случае.

Я использовал PDFsharp в этом коде.Вы можете найти его в это hompage или это страница CodePlex .

PdfReport class:

    private PdfDocument Document;
    public Control Control { get; private set; }        

    public PdfReport(Control control) { Control = control; }

    public PdfDocument CreatePdf(PdfDocument document = null)
    {
        Document = document != null ? document : new PdfDocument();
        PdfPage page = Document.AddPage();
        page.Height = Control.Height;
        page.Width = Control.Width;

        XGraphics gfx = XGraphics.FromPdfPage(page);
        foreach (PdfItem item in CreatePdf(new Point(0, 0), Control.Controls))
        {
            XStringFormat format = item.IsContainer ? XStringFormats.TopLeft : item.TextAlign == ContentAlignment.BottomCenter ? XStringFormats.BottomCenter : item.TextAlign == ContentAlignment.TopLeft ? XStringFormats.TopLeft : item.TextAlign == ContentAlignment.TopCenter ? XStringFormats.TopCenter : XStringFormats.Center;
            gfx.DrawString(item.Text, item.Font, item.Brush, new XRect(item.Location, item.Size), format);
        }
        return Document;
    }
    private IEnumerable<PdfItem> CreatePdf(Point location, Control.ControlCollection controls)
    {
        List<PdfItem> items = new List<PdfItem>();
        foreach (Control control in controls)
        {
            if (control.Controls.Count > 0)
                items.AddRange(CreatePdf(control.Location, control.Controls));
            items.Add(new PdfItem(control, location));
        }
        return items;
    }

    public void SaveAsPdf(string path, bool open = false)
    {
        CreatePdf().Save(path);
        if (open)
            Process.Start(path);
    }

PdfItem класс:

    public string Text { get; set; }
    public Point Location { get; set; }
    public Size Size { get; set; }
    public Font Font { get; set; }
    public bool IsContainer { get; set; }
    public ContentAlignment TextAlign { get; set; }
    public Color ForeColor { get; set; }
    public XBrush Brush { get { return new SolidBrush(ForeColor); } }

    public PdfItem() { }
    public PdfItem(string text, Point location, Font font, Color foreColor, Size size, bool isContainer = false, ContentAlignment alignment = ContentAlignment.MiddleCenter)
    {
        Text = text;
        Location = location;
        Size = size;
        Font = new Font(font.FontFamily, font.Size, font.Style, GraphicsUnit.World);
        TextAlign = alignment;
        ForeColor = foreColor;
        IsContainer = isContainer;
    }
    public PdfItem(string text, Point location, Size size)
        : this(text, location, new Font("Calibri", 12), Color.Black, size) { }
    public PdfItem(Control control, Point parentLocation)
        : this(control.Text, control.Location, control.Font, control.ForeColor, control.Size, control.Controls.Count > 0)
    {
        Location = new Point(Location.X + parentLocation.X, Location.Y + parentLocation.Y);
        IEnumerable<PropertyInfo> properties = control.GetType().GetProperties();
        if (properties.FirstOrDefault(p => p.Name == "TextAlign" && p.PropertyType == typeof(ContentAlignment)) != null)
            TextAlign = (control as dynamic).TextAlign;
        if (properties.FirstOrDefault(p => p.Name == "Checked" && p.PropertyType == typeof(bool)) != null)
        {
            string title = control.Text != null && control.Text.Length > 0 ? string.Format("{0}: ", control.Text) : string.Empty;
            Text = string.Format("{0}{1}", title, (control as dynamic).Checked ? "Yes" : "No");
        }
    }

Ответы [ 3 ]

2 голосов
/ 21 апреля 2011

Относительно

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

Доступен инструмент под названием " cropper "на codeplex.com.Он предназначен для использования в качестве пользовательского инструмента, который может делать скриншоты.Это управляемый код с открытым исходным кодом.

Я могу представить себе, как можно внедрить в ваше приложение некоторые элементы магии обрезки, чтобы вы могли сделать этот снимок экрана.Я также могу предположить, что это было бы полезно для сбора диагностического изображения экрана во время проблемы.

С другой стороны ... если вы заинтересованы в создании печатной формы, которая воспроизводит содержимое на экране, то я думаю, что вы должны использовать WPF, и в этом случае делать то, что вы хотите, довольно легко.Например, этот вопрос описывает, как выполнить предварительный просмотр для FlowDocument.С этого момента ваш пользователь может печатать в PDF (если у него установлен принтер PDF) или печатать в XPS, или печатать на физическом устройстве вывода и т. Д.

1 голос
/ 21 апреля 2011

Я не знаю, поможет ли это вам или нет, но DocRaptor.com pdf api может быть встроен, так что он сделает это за вас, независимо от того, что пользователь вводит. Он использует базовый HTML.

0 голосов
/ 04 апреля 2016

Как вы можете использовать ниже:)

YourPanel.AutoSize = true;


        int width = YourPanel.Size.Width;
        int height = YourPanel.Size.Height;

        Bitmap bm = new Bitmap(width, height);
        YourPanel.DrawToBitmap(bm, new Rectangle(0, 0, width, height));

        string outputFileName = @"C:\YourDirectory/myimage.bmp";
        using (MemoryStream memory = new MemoryStream())
        {
            using (FileStream fs = new FileStream(outputFileName, FileMode.Create, FileAccess.ReadWrite))
            {
                bm.Save(memory, ImageFormat.Bmp);
                Clipboard.SetImage(bm);
                byte[] bytes = memory.ToArray();
                fs.Write(bytes, 0, bytes.Length);
            }
        }
        YourPanel.AutoSize = false;

Clipboard.SetImage отправит вам BM в буфер обмена, чтобы вы могли вставить их в PDF-форму или любой другой документ

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

Хитрость здесь в том, что Autosize для вашей панели.Необходимо установить значение true, чтобы панель изменяла размеры всей видимой области, а затем сразу после выполнения работы можно изменить ее на false, чтобы она снова использовала полосы прокрутки для экрана пользователя (вы можете увидеть, что она мигает в течение полсекунды., но этот код работает.

Сохранение в формате PDF. Лично я предпочитаю записывать его там в виде буфера обмена, или вы можете записывать байты. Но ITextSharp - отличная библиотека для расширения, с которым можно работать!

Я действительно надеюсь, что это поможет.

...