Generate more than one PDF in memory and export it in a compressed file

Asked

Viewed 1,305 times

2

Currently the code below exports and compresses the PDF one at a time and need to export multiple PDF in one compressed file

public ActionResult PDFTodosMesAtual(ProcessamentoRegistros _processamento)
        {
            try
            {
                string _nomeArquivo = string.Empty;

                //AQUI RETORNO UM LISTA DE DOCUMENTOS HTML QUE SERÁ CONVERTIDO EM PDF
                IEnumerable<ProcessamentoRegistros> _todosHtmlMesAtual = _IRepositorio.ObterTodosHTMLMesAtual(); 

                if (_todosHtmlMesAtual != null)
                {
                    //TENTEI FAZE ALGO ASSIM, MAS SEM SUCESSO:                    
                    //foreach (var item in _todosHtmlMesAtual)

                        #region :: converte arquivo html para pdf ::
                        _nomeArquivo = "Documento_Fiscal_" + DateTime.Now.ToString().Replace(" ", "_").Replace("/", "_").Replace(":", "_") + ".zip";
                        MemoryStream file = null;
                        var pechkin = Factory.Create(new GlobalConfig());
                        var _pdf = pechkin.Convert(new ObjectConfig()
                                                    .SetLoadImages(true).SetZoomFactor(1)
                                                    .SetPrintBackground(true)
                                                    .SetScreenMediaType(true)
                                                    .SetCreateExternalLinks(true)
                                                    .SetIntelligentShrinking(true).SetCreateInternalLinks(true)
                                                    .SetAllowLocalContent(true), item.DocumentoHtml.ToString());
                        file = new MemoryStream();
                        file.Write(_pdf, 0, _pdf.Length);                       

                        byte[] arquivo = _pdf;
                        #endregion

                        #region :: compacta e faz o download do arquivo pdf ::
                        using (var compressedFileStream = new MemoryStream())
                        {
                            using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false))
                            {
                                var zipEntry = zipArchive.CreateEntry("documento.pdf");
                                using (var originalFileStream = new MemoryStream(file.ToArray()))
                                {
                                    using (var zipEntryStream = zipEntry.Open())
                                    {
                                        originalFileStream.CopyTo(zipEntryStream);
                                    }
                                }
                            }
                            return new FileContentResult(compressedFileStream.ToArray(), "application/zip") { FileDownloadName = _nomeArquivo };//return RedirectToAction("Index", "Documento");
                        }
                        #endregion

                }
                else
                {
                    return RedirectToAction("Index", "Documento");
                }
            }
            catch (Exception ex)
            {
                ViewBag.MsgErro = string.Format("Download não efetuado! " + ex.Message.ToString());
                return RedirectToAction("Index", "Documento");
            }
        }

I started this post here insert link description here with credits from Geroge Wurthmann

1 answer

2


The code is very similar to the of that answer.

Important to say that you are using System.IO.Compression for native compression with C#.

This should work in your code:

public ActionResult PDFTodosMesAtual(ProcessamentoRegistros _processamento)
{
    try
    {
        string _nomeArquivo = string.Empty;

        //AQUI RETORNO UM LISTA DE DOCUMENTOS HTML QUE SERÁ CONVERTIDO EM PDF
        IEnumerable<ProcessamentoRegistros> _todosHtmlMesAtual = _IRepositorio.ObterTodosHTMLMesAtual();

        if (_todosHtmlMesAtual != null)
        {
            #region :: converte arquivo html para pdf ::
            List<byte[]> meusPDFs = new List<byte[]>();
            foreach (var item in _todosHtmlMesAtual)
            {
                _nomeArquivo = "Documento_Fiscal_" + DateTime.Now.ToString().Replace(" ", "_").Replace("/", "_").Replace(":", "_") + ".zip";
                MemoryStream file = null;
                var pechkin = Factory.Create(new GlobalConfig());
                var _pdf = pechkin.Convert(new ObjectConfig()
                                            .SetLoadImages(true).SetZoomFactor(1)
                                            .SetPrintBackground(true)
                                            .SetScreenMediaType(true)
                                            .SetCreateExternalLinks(true)
                                            .SetIntelligentShrinking(true).SetCreateInternalLinks(true)
                                            .SetAllowLocalContent(true), item.DocumentoHtml.ToString());
                file = new MemoryStream();
                file.Write(_pdf, 0, _pdf.Length);
                meusPDFs.Add(_pdf);
            }

            #endregion

            #region :: compacta e faz o download do arquivo pdf ::
            using (var compressedFileStream = new MemoryStream())
            {
                //Informações sobre o GetEncoding: https://msdn.microsoft.com/en-us/library/system.text.encodinginfo.getencoding(v=vs.110).aspx
                Encoding nomeArquivoEncoding = Encoding.GetEncoding(850);
                //Cria um arquivo ZIP e armazena na memória (memory stream) com enconding 850
                using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false, nomeArquivoEncoding))
                {
                    int i = 1; //Só uso essa variável para dar nome diferente pra todos PDFs
                    foreach (var pdf in meusPDFs)
                    {
                        //Criar uma entrada para cada anexo a ser "Zipado"
                        var zipEntry = zipArchive.CreateEntry("MeuPDF"+i);

                        //Pegar o stream do anexo
                        using (var originalFileStream = new MemoryStream(pdf))
                        {
                            using (var zipEntryStream = zipEntry.Open())
                            {
                                //Copia o anexo na memória para a entrada ZIP criada
                                originalFileStream.CopyTo(zipEntryStream);
                            }
                        }
                        i++;
                    }
                }
                return new FileContentResult(compressedFileStream.ToArray(), "application/zip") { FileDownloadName = "MeusPDFs_" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss") + ".zip" };
            }
            #endregion

        }
        else
        {
            return RedirectToAction("Index", "Documento");
        }
    }
    catch (Exception ex)
    {
        ViewBag.MsgErro = string.Format("Download não efetuado! " + ex.Message.ToString());
        return RedirectToAction("Index", "Documento");
    }
}

I didn’t test the code above, but the important part for you is to compress several Pdfs in a single ZIP. That part below that does that:

using (var compressedFileStream = new MemoryStream())
{
    //Informações sobre o GetEncoding: https://msdn.microsoft.com/en-us/library/system.text.encodinginfo.getencoding(v=vs.110).aspx
    Encoding nomeArquivoEncoding = Encoding.GetEncoding(850);
    //Cria um arquivo ZIP e armazena na memória (memory stream) com enconding 850
    using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false, nomeArquivoEncoding))
    {
        int i = 1; //Só uso essa variável para dar nome diferente pra todos PDFs
        foreach (var pdf in meusPDFs)
        {
            //Criar uma entrada para cada anexo a ser "Zipado"
            var zipEntry = zipArchive.CreateEntry("MeuPDF"+i);

            //Pegar o stream do anexo
            using (var originalFileStream = new MemoryStream(pdf))
            {
                using (var zipEntryStream = zipEntry.Open())
                {
                    //Copia o anexo na memória para a entrada ZIP criada
                    originalFileStream.CopyTo(zipEntryStream);
                }
            }
            i++;
        }
    }
    return new FileContentResult(compressedFileStream.ToArray(), "application/zip") { FileDownloadName = "MeusPDFs_" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss") + ".zip" };
}
  • 1

    worked perfectly !

  • Hello @George Wurthmann ! It is acceptable to download 1000 pdf files with 30kb each compressed file in 7 minutes ?

  • 1

    @Front, of course it will depend on your environment and you should do this analysis based on this, but it should be considered that it is 30MB (1000x30kb) and in addition there is processing to compress the 1000 files in a zip. Analysis also how the system is used: will the download be performed several times? Will it be impactful for users to wait for these 7min? Depending on the answers can be considered different approaches.

  • The download will not be performed several times a day and I know it is difficult to opine on these specific points, but as I do not have a parameter to argue the delay with the customer I get half sold rs.

  • 1

    Maybe it’s interesting a progress bar pro user follow up. We can give different suggestions for similar results, but if the customer insists on the other way will know the impacts. Be careful, In addition to processing, it is 30mb of file that is getting in memory. Not writing to disk makes the process faster, but in this case probably the virtual memory is being used (unless the server is very robust).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.