Plugin Conversor

Converta documentos para 24 formatos de destino

O plugin Conversor transforma o Doconut em um serviço de conversão de documentos. Ele fornece o mecanismo por trás da fachada pública DocumentConverter e — opcionalmente — um widget pronto servido por DocImage.axd, permitindo que você converta documentos a partir de C#, do widget ou de uma interface que você mesmo desenvolva.

Instalar o pacote

powershell
Install-Package Doconut.NETFramework.Converter

Mantenha o pacote Conversor na mesma versão que Doconut.NETFramework.

Registrar o plugin

Todo plugin é registrado da mesma forma: AddPlugin<TPlugin>() em DoconutHost.Initialize.

csharp
Doconut.DoconutHost.Initialize(options =>
{
    options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});

Se nenhuma licença ativa conceder a capacidade Converter — nenhuma licença, um arquivo legado TRIAL ou uma licença sem essa capacidade — DoconutHost.Initialize lança uma exceção a partir de Application_Start. No System.Web isso significa que cada requisição responde com um 500 vazio, e o motivo está apenas no log de eventos do Windows (fonte ASP.NET). Licenças temporárias Demo/NFR são aceitas. Veja Configuração de Licença.

Converter a partir de C#

Cada conversão retorna um MemoryStream buscável posicionado em 0. DocumentConverter é sem estado: obtenha-o de DoconutHost.Services onde precisar e reutilize livremente.

csharp
// Resolve DocumentConverter from DoconutHost.Services; its constructor is internal, so never `new` it.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);
csharp
// sourceExtension includes the leading dot. password is null unless the document is protected.
Stream png = await converter.ConvertAsync(upload, ".xlsx", ConversionTarget.Png, password: null, ct: ct);
csharp
Stream html = await converter.WordToHtmlAsync("report.docx", ct);
csharp
Stream docx = await converter.HtmlToWordAsync(html, ConversionTarget.Docx, ct);

Dois detalhes que são fáceis de errar: sourceExtension na sobrecarga que aceita stream deve incluir o ponto inicial (".xlsx", não "xlsx"), caso contrário não será resolvido. E, apesar do nome, WordToHtmlAsync retorna Task<Stream>, não Task<string> — o documento HTML (imagens incorporadas como Base64) chega como um stream, como todo o resto dos resultados.

Em um controlador MVC 5

Torne a ação assíncrona e await a conversão:

csharp
[HttpPost]
public async Task<ActionResult> ToPdf(HttpPostedFileBase file)
{
    var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();
    Stream pdf = await converter.ConvertAsync(
        file.InputStream, Path.GetExtension(file.FileName), ConversionTarget.Pdf,
        password: null, ct: Response.ClientDisconnectedToken);
    return File(pdf, "application/pdf", Path.GetFileNameWithoutExtension(file.FileName) + ".pdf");
}

Em Web Forms: nunca bloqueie uma conversão

Uma página Web Forms é executada em um contexto de requisição de thread única. ConvertAsync retoma nesse contexto quando termina, portanto uma página que espera por ele de forma síncrona — .Result, .Wait(), .GetAwaiter().GetResult() — ocupa a própria thread que a conversão precisa para concluir. A requisição nunca retorna. O navegador continua carregando, o IIS não registra nada e o restante do site continua funcionando, parecendo uma conversão lenta em vez de um deadlock.

Marque a página com Async="true" e execute a conversão como uma tarefa assíncrona da página:

aspx
<%@ Page Language="C#" Async="true" CodeBehind="Convert.aspx.cs" Inherits="MyApp.Convert" %>
csharp
// Web Forms: the @Page directive needs Async="true", and the conversion runs as a page async task.
// Blocking on it instead (.Result, .Wait(), .GetAwaiter().GetResult()) deadlocks the request:
// it never returns, and nothing is logged.
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack) return;

    RegisterAsyncTask(new PageAsyncTask(async ct =>
    {
        var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();

        using (var pdf = await converter.ConvertAsync(
                   Server.MapPath("~/App_Data/contract.docx"), ConversionTarget.Pdf, ct: ct))
        using (var ms = new MemoryStream())
        {
            if (pdf.CanSeek) pdf.Position = 0;
            await pdf.CopyToAsync(ms);

            Response.ContentType = "application/pdf";
            Response.AddHeader("Content-Disposition", "attachment; filename=contract.pdf");
            Response.BinaryWrite(ms.ToArray());
            // Context, not HttpContext.Current: after an await the latter can be null.
            Context.ApplicationInstance.CompleteRequest();
        }
    }));
}

Sem Async="true" na diretiva @Page, RegisterAsyncTask é silenciosamente ignorado. Após um await, use o Context da página; HttpContext.Current pode ser null nesse caso.

Formatos de destino

text
Pdf, Docx, Doc, Html, Xlsx, Pptx, Png, Jpeg, Csv, Tiff, Bmp, Gif, Svg, Xml,
Txt, Xls, Jp2, Rtf, Odt, Ods, Odp, Epub, Xps, Webp

Nem todo fonte converte para todo alvo: cada família de formato da fonte (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project, PSD, web document) tem seu próprio conjunto de alvos permitidos. Não codifique este enum como a lista de alvos da sua UI: ?convert=open retorna os allowedTargets para o arquivo enviado, e isso é o que deve conduzir um seletor.

Widget incorporável

Os endpoints do widget ?convert=open|run|download são servidos por DocImage.axd e estão desativados por padrão. Habilite-os ao lado do registro do plugin:

csharp
Doconut.DoconutHost.Initialize(options =>
{
    options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddConverterWidget(widget =>
    {
        widget.MaxUploadMb = 25;
    });
});
// System.Web reads the whole upload before Doconut sees it: keep maxRequestLength (KB) and
// maxAllowedContentLength (bytes) in Web.config above the widget's MaxUploadMb.
html
<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
  Doconut.convert('#doconut-convert', { basePath: '/DocImage.axd', maxUploadMb: 25 });
</script>

Duas coisas a verificar quando o widget se comporta de forma inesperada:

  • basePath: '/DocImage.axd'. O padrão do widget, /doconut, é o endpoint ASP.NET Core. Neste pacote, os endpoints são o manipulador DocImage.axd do Web.config.
  • O script e os endpoints são independentes. O módulo de recursos serve doconutConverter.js esteja ou não o widget habilitado. Sem AddConverterWidget(), o widget carrega, pinta sua zona de arraste e parece totalmente correto — e sua primeira ação responde 404.

Limites de upload

ASP.NET lê todo o corpo da requisição antes que DocImage.axd seja executado. Um upload acima de MaxUploadMb mas abaixo dos limites do host gera o JSON 413 do widget ("File is too large."). Um upload acima dos limites do host é rejeitado primeiro pelo IIS, com uma página de erro que o widget não consegue ler. Mantenha ambos os limites do host em Web.config acima do teto do widget:

xml
<system.web>
  <httpRuntime maxRequestLength="30720" />           <!-- KILOBYTES: 30 MB -->
</system.web>
<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="31457280" />  <!-- BYTES: 30 MB -->
    </requestFiltering>
  </security>
</system.webServer>

Personalizar o widget

Opções passadas para Doconut.convert(selector, options):

OpçãoTipoPadrãoObservações
basePathstring/doconutA URL do endpoint. Defina '/DocImage.axd' neste pacote
resPathstring/doconut-resAceito por consistência com outros widgets Doconut; o widget conversor não constrói nenhuma URL a partir dele
maxUploadMbnumber25Apenas verificação prévia no cliente; o servidor impõe seu próprio limite
licenseUrlstring | nullnullTransforma o aviso de marca d'água na tela de resultado em um link
labelsobject{}Substitui qualquer subconjunto das strings em inglês do widget

Callbacks:

CallbackDispara quandoCarga útil
onReady()O widget renderizou sua tela de arrastar—
onSourceLoaded({ token, pages, sourceExt, allowedTargets })?convert=open tem sucessoToken da fonte, contagem de páginas, extensão da fonte (sem ponto inicial), alvos permitidos
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target })?convert=run tem sucessoA resposta da execução mais o target solicitado
onDownload({ downloadName, downloadToken })O usuário clica em DownloadDispara junto ao download próprio do navegador
onError({ phase, message })Uma requisição open ou run falhaphase é 'open' ou 'run'; message é o erro do servidor sanitizado

Doconut.convert() devolve a instância do widget: reset() volta à tela de arraste, loadFile(file) inicia o fluxo com um File, e destroy() o remove.

Construa seu próprio frontend

O widget é um cliente para este contrato HTTP em DocImage.axd:

RotaPropósitoResposta de sucesso
POST /DocImage.axd?convert=open (multipart, field file)Carregar e abrir um documento fonte200 — { token, pages, sourceExt, allowedTargets }
POST /DocImage.axd?token=<token>&convert=run&target=<ext>Converter a fonte carregada para target200 — { downloadToken, resultToken, resultPages, downloadName, watermarked }
GET /DocImage.axd?convert=download&token=<downloadToken>Transmitir o arquivo convertido200 — o arquivo, Content-Disposition: attachment

As fontes carregadas são mantidas por 30 minutos; depois disso, run responde 404 e o arquivo deve ser aberto novamente. downloadToken tem sua própria janela de 30 minutos quando a conversão é concluída. resultToken é um token de visualizador comum que segue a duração da sessão do visualizador.

sourceExt na resposta de open não tem ponto inicial ("docx") — o oposto do parâmetro sourceExtension de ConvertAsync.

RotaStatusQuandoCorpo
qualquer404O widget não está habilitado (AddConverterWidget() nunca foi chamado)apenas status
qualquer405Verbo errado (open/run requerem POST, download requer GET)apenas status
open413O upload excede MaxUploadMb (mas não os limites do IIS){ "error": "File is too large." }
open400Sem corpo multipart, sem arquivo, ou um tipo que não pode ser convertido{ "error": "..." }
open403O tipo de arquivo requer uma capacidade que a licença não concede{ "error": "..." }
run400Um token malformado, um target desconhecido, ou um alvo que não está em allowedTargets{ "error": "..." }
run404O upload expirou ou nunca foi aberto{ "error": "Upload expired — please re-open the file." }
open, run500Processamento falhou{ "error": "<sanitized message>" }
download400 / 404Um token de download malformado, desconhecido ou expiradoapenas status

Propriedade de recursos

O chamador possui o MemoryStream que uma conversão retorna e deve descartá‑lo após copiar ou retorná‑lo (o File(stream, …) do MVC descarta‑o para você). Não construa ou descarte DocumentConverter manualmente — seu construtor é interno.

Marcação d'água

Estado da licençaInicializaçãoSaída da conversão
Licença paga de visualizador concedendo ConverterIniciaLimpo — watermarked: false
Licença Temporária/Demo ativaIniciaConverte, com a marca d'água de avaliação — watermarked: true
Sem licença, um arquivo legado TRIAL, ou uma licença sem ConverterApplication_Start lança exceção; toda requisição responde um 500 vazio—
Licença Temporária/Demo expiradaIniciaConverte, com a marca d'água de avaliação — watermarked: true

Uma integração pode ser construída e testada de ponta a ponta com uma licença de avaliação antes da compra — apenas os bytes de saída mudam.

Solução de problemas

SintomaVerificação
Todas as requisições respondem um 500 vazio após adicionar o pluginA licença concede Converter — log de eventos do Windows, fonte ASP.NET
Resolver DocumentConverter lança exceçãoAddPlugin<ConverterPlugin>() está em DoconutHost.Initialize
Uma conversão Web Forms nunca retornaA página bloqueia em ConvertAsync — use Async="true" e RegisterAsyncTask
A conversão de stream indica que o formato não é suportadosourceExtension inclui o ponto inicial
O widget carrega mas suas requisições retornam 404AddConverterWidget() não foi chamado, ou basePath não é '/DocImage.axd'
Um upload grande mostra uma página de erro do IIS ao invés da mensagem do widgetmaxRequestLength / maxAllowedContentLength estão abaixo de MaxUploadMb
Um alvo está ausenteUse o allowedTargets de convert=open
O download expirouRepita convert=open / convert=run; os tokens são temporários intencionalmente

Esta página foi útil?