Plugin převodníku

Převádějte dokumenty do 24 cílových formátů

Plugin Converter promění Doconut na službu pro převod dokumentů. Přispívá k enginu za veřejnou fasádou DocumentConverter a — po zapnutí — k vložitelného widgetu poskytovanému DocImage.axd, takže můžete převádět dokumenty z C#, z widgetu nebo z frontendu, který si vytvoříte sami.

Instalace balíčku

powershell
Install-Package Doconut.NETFramework.Converter

Udržujte balíček Converter ve stejné verzi jako Doconut.NETFramework.

Zaregistrujte plugin

Každý plugin se registruje stejným způsobem: AddPlugin<TPlugin>() v DoconutHost.Initialize.

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

Pokud žádná aktivní licence nepřiděluje schopnost Converter — žádná licence, starý soubor TRIAL nebo licence bez ní — DoconutHost.Initialize vyhodí výjimku z Application_Start. V System.Web to znamená, že každá žádost vrátí prázdný 500 a důvod je pouze v protokolu událostí Windows (zdroj ASP.NET). Dočasné Demo/NFR licence jsou akceptovány. Viz Nastavení licence.

Převod z C#

Každý převod vrací vyhledávatelný MemoryStream nastavený na pozici 0. DocumentConverter je bezstavový: získáte jej z DoconutHost.Services kdekoliv jej potřebujete a můžete jej volně znovu použít.

csharp
// Získejte DocumentConverter z DoconutHost.Services; jeho konstruktor je interní, takže jej nikdy neinstanciujte pomocí `new`.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);
csharp
// sourceExtension obsahuje úvodní tečku. password je null, pokud dokument není chráněn.
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);

Dva detaily, které se snadno špatně pochopí: sourceExtension u přetížení se streamem musí obsahovat úvodní tečku (".xlsx", ne "xlsx"), jinak se nevyřeší. A navzdory názvu WordToHtmlAsync vrací Task<Stream>, nikoli Task<string> — HTML dokument (obrázky vložené jako Base64) přichází jako stream, stejně jako každý jiný výsledek.

V MVC 5 kontroleru

Udělejte akci asynchronní a await převod:

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");
}

Ve Web Forms: nikdy neblokujte převod

Stránka Web Forms běží v jednovláknovém kontextu požadavku. ConvertAsync se po dokončení obnoví v tomto kontextu, takže stránka, která na něj čeká synchronně — .Result, .Wait(), .GetAwaiter().GetResult() — drží právě ten vlákno, které převod potřebuje k dokončení. Požadavek se nikdy nevrátí. Prohlížeč stále otáčí, IIS nic neukládá a zbytek webu funguje, takže to vypadá jako pomalý převod místo zablokování.

Označte stránku Async="true" a spusťte převod jako asynchronní úlohu stránky:

aspx
<%@ Page Language="C#" Async="true" CodeBehind="Convert.aspx.cs" Inherits="MyApp.Convert" %>
csharp
// Web Forms: direktiva @Page vyžaduje Async="true" a převod běží jako asynchronní úloha stránky.
// Blokování na něj místo toho (.Result, .Wait(), .GetAwaiter().GetResult()) způsobí deadlock požadavku:
// nikdy se nevrátí a nic se nezaznamená.
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, ne HttpContext.Current: po await může být ten druhý null.
            Context.ApplicationInstance.CompleteRequest();
        }
    }));
}

Bez Async="true" v direktivě @Page je RegisterAsyncTask tiše ignorováno. Po await použijte Context stránky; HttpContext.Current může být v tomto okamžiku null.

Cílové formáty

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

Ne každý zdroj se převádí na každý cíl: každá rodina formátů zdroje (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project, PSD, webový dokument) má vlastní sadu povolených cílů. Nezakódovávejte tento výčet jako pevný seznam cílů ve vašem UI: ?convert=open vrací allowedTargets pro nahraný soubor a to by mělo řídit výběr.

Vkládací widget

Endpointy widgetu ?convert=open|run|download jsou poskytovány pomocí DocImage.axd a jsou ve výchozím nastavení vypnuté. Povolit je můžete vedle registrace pluginu:

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>

Dvě věci, které je třeba zkontrolovat, když widget nefunguje správně:

  • basePath: '/DocImage.axd'. Výchozí hodnota widgetu, /doconut, je endpoint ASP.NET Core. V tomto balíčku jsou endpointy obsluhovány handlerem DocImage.axd z Web.config.
  • Skript a endpointy jsou nezávislé. Modul zdrojů poskytuje doconutConverter.js bez ohledu na to, zda je widget povolen. Bez AddConverterWidget() se widget načte, vykreslí svou oblast pro přetažení a vypadá naprosto správně — a jeho první akce vrátí 404.

Limity nahrávání

ASP.NET načte celé tělo požadavku před tím, než se spustí DocImage.axd. Nahrání nad MaxUploadMb, ale pod limity hostitele, vrátí widgetu vlastní JSON 413 („Soubor je příliš velký.“). Nahrání nad limity hostitele je nejprve odmítnuto IIS, s chybovou stránkou, kterou widget nedokáže přečíst. Ponechte oba limity hostitele v Web.config nad limitem widgetu:

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>

Přizpůsobení widgetu

Možnosti předávané do Doconut.convert(selector, options):

MožnostTypVýchozíPoznámky
basePathstring/doconutURL endpointu. Na tomto balíčku nastavte '/DocImage.axd'
resPathstring/doconut-resPřijato pro konzistenci s ostatními Doconut widgety; konvertorový widget nevyužívá tuto hodnotu k sestavení žádné URL.
maxUploadMbnumber25Pouze předběžná kontrola na klientovi; server vynutí svůj vlastní limit.
licenseUrlstring | nullnullPřemění upozornění na vodoznak na výsledné obrazovce na odkaz.
labelsobject{}Přepíše libovolnou podmnožinu anglických řetězců widgetu.

Zpětné volání:

Zpětné voláníSpustí se, kdyžData
onReady()Widget vykreslil svou výchozí obrazovku—
onSourceLoaded({ token, pages, sourceExt, allowedTargets })?convert=open uspějeToken zdroje, počet stránek, přípona zdroje (bez úvodní tečky), povolené cíle
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target })?convert=run uspějeOdpověď běhu plus požadovaný target
onDownload({ downloadName, downloadToken })Uživatel klikne na StáhnoutSpustí se spolu s vlastním stažením prohlížeče
onError({ phase, message })Požadavek open nebo run selžephase je 'open' nebo 'run'; message je ošetřená chyba serveru

Doconut.convert() vrací instanci widgetu: reset() vrátí na výchozí obrazovku, loadFile(file) spustí proces s File, a destroy() jej odstraní.

Vytvořte si vlastní frontend

Widget je klientem pro tuto HTTP smlouvu na DocImage.axd:

CestaÚčelÚspěšná odpověď
POST /DocImage.axd?convert=open (multipart, field file)Nahrát a otevřít zdrojový dokument200 — { token, pages, sourceExt, allowedTargets }
POST /DocImage.axd?token=<token>&convert=run&target=<ext>Převést nahraný zdroj na target200 — { downloadToken, resultToken, resultPages, downloadName, watermarked }
GET /DocImage.axd?convert=download&token=<downloadToken>Streamovat převedený soubor200 — soubor, Content-Disposition: attachment

Nahrané zdroje jsou uchovávány po dobu 30 minut; po uplynutí této doby run vrací 404 a soubor je nutné znovu otevřít. downloadToken získá vlastní 30‑minutové okno po dokončení konverze. resultToken je běžný token pro prohlížeč, který platí po celou dobu životnosti relace prohlížeče.

sourceExt v odpovědi open nemá úvodní tečku ("docx") — naopak oproti parametru sourceExtension metody ConvertAsync.

CestaStavKdyTělo
libovolná404Widget není povolen (AddConverterWidget() nebylo nikdy zavoláno)pouze stav
libovolná405Špatná metoda (open/run vyžadují POST, download vyžaduje GET)pouze stav
open413Nahrání překračuje MaxUploadMb (ale ne limity IIS){ "error": "File is too large." }
open400Chybí multipart tělo, soubor nebo typ, který nelze převést{ "error": "..." }
open403Typ souboru vyžaduje schopnost, kterou licence neposkytuje{ "error": "..." }
run400Poškozený token, neznámý target nebo cíl, který není v allowedTargets{ "error": "..." }
run404Nahrání vypršelo nebo nebylo nikdy otevřeno{ "error": "Upload expired — please re-open the file." }
open, run500Zpracování selhalo{ "error": "<sanitized message>" }
download400 / 404Poškozený, neznámý nebo vypršelý token pro staženípouze stav

Vlastnictví zdrojů

Volající vlastní MemoryStream, který konverze vrací, a měl by jej uvolnit po zkopírování nebo vrácení (MVC metoda File(stream, …) jej uvolní za vás). Nevytvářejte ani neuvolňujte DocumentConverter sami — jeho konstruktor je interní.

Vodoznakování

Stav licenceSpuštěníVýstup konverze
Placená licence pro prohlížeč poskytující ConverterSpouští seČistý — watermarked: false
Aktivní dočasná/demo licenceSpouští sePřevádí, s evaluačním vodoznakem — watermarked: true
Žádná licence, starý soubor TRIAL nebo licence bez ConverterApplication_Start vyhodí výjimku; každá žádost vrátí prázdný 500—
Vypršená dočasná/demo licenceSpouští sePřevádí, s evaluačním vodoznakem — watermarked: true

Integraci lze postavit a otestovat od začátku do konce na evaluační licenci před nákupem — mění se pouze výstupní bajty.

Řešení problémů

ProblémKontrola
Každá žádost vrací prázdný 500 po přidání pluginuLicence poskytuje Converter — Windows Event Log, zdrojový ASP.NET
Vyřešení DocumentConverter vyvolá výjimkuAddPlugin<ConverterPlugin>() je v DoconutHost.Initialize
Konverze Web Forms se nikdy nevrátíStránka blokuje na ConvertAsync — použijte Async="true" a RegisterAsyncTask
Streamová konverze uvádí, že formát není podporovánsourceExtension obsahuje úvodní tečku
Widget se načte, ale jeho požadavky vrací 404AddConverterWidget() nebylo zavoláno, nebo basePath není '/DocImage.axd'
Velké nahrání zobrazí chybovou stránku IIS místo zprávy widgetumaxRequestLength / maxAllowedContentLength jsou pod MaxUploadMb
Chybí cílPoužijte allowedTargets z convert=open
Stahování vypršeloOpakujte convert=open / convert=run; tokeny jsou úmyslně dočasné

Byla tato stránka užitečná?