Search code examples
c#asp.net-mvcpdfmemorystream

Create Memorystream of type pdf and return to browser


I have to create a blank PDF with a simple text message and return it to the browser. I don't have to use any third-party PDF library like iTextSharp, PDFDocument, etc.

I am using MemoryStream but a corrupted PDF is getting generated.

 MemoryStream ms = new MemoryStream();
 ms.Write(System.Text.Encoding.Unicode.GetBytes("test message"), 0, System.Text.Encoding.Unicode.GetBytes("test message").Length);
 Response.AddHeader("Content-Disposition", "attachment;filename=" + id.ToString() + ".pdf");
 return File(ms.ToArray(), "application/pdf");

What I am missing?


Solution

  • You have basically created a TXT file and sent that to the Browser declaring it as a PDF.

    PDF has its own file format. Old versions of the PDF standard such as PDF 1.2 can be written in a text-like format. The Wayback Machine has a copy of the PDF 1.2 specification.

    You probably want to benefit of newer versions of the PDF standard. And maybe you don't want to invest the time reading and understanding 400 pages. Also, you don't want huge string templates, but a more expressive way of creating PDF files. So, a library can save you a lot of time and effort.

    Anyway, you could read that specification and come up with something like

    string template = @"
    %PDF-1.2 
    4 0 obj << >> 
    stream 
    BT/ 12 Tf({0})' ET 
    endstream 
    endobj
    3 0 obj << /Type /Page /Parent 2 0 R /Contents 4 0 R >> endobj
    2 0 obj << /Kids [3 0 R ] /Count 1 /Type /Pages /MediaBox [ 0 0 99 99 ] >> endobj
    1 0 obj << /Pages 2 0 R /Type /Catalog >> endobj
    trailer << /Root 1 0 R >>
    %%EOF
    ";
    string text = "Text message";
    string pdf = string.Format(template, text);
    

    It has:

    • A %PDF-1.2 header as described in chapter 5.2
    • Various objects as described in chapter 4
    • Dictionaries inside << >> as described in chapter 4.7
    • A stream between stream and endstream as described in chapter 4.8
    • A text object, introduced with BT and ending with ET as described in Figure 8.1
    • Text font manipulation with Tf as described in chapter 8.7.3
    • A text string between ( and ) as described in chapter 4.4. I'm using a .NET {0} placeholder here.
    • A page with the required MediaBox defining the size of the page as described in chapter 6.4
    • A trailer as described in chapter 5.5, ending with %%EOF, containing a mandatory /Root entry.

    You kinda read this PDF "bottom up". The trailer refers to Object 1 0, which refers to the pages 2 0, which refers to one page 3 0, which refers to content 4 0.