컨버터 플러그인
문서를 24가지 대상 형식으로 변환
Converter 플러그인은 Doconut을 문서 변환 서비스로 전환합니다. 공개 DocumentConverter 파사드 뒤의 엔진을 제공하고, 선택적으로 DocImage.axd에서 제공되는 위젯을 삽입하여 C#에서, 위젯에서, 또는 직접 작성한 프런트엔드에서 문서를 변환할 수 있습니다.
패키지 설치
Install-Package Doconut.NETFramework.ConverterDoconut.NETFramework와 동일한 버전으로 Converter 패키지를 유지하십시오.
플러그인 등록
모든 플러그인은 동일한 방식으로 등록됩니다: DoconutHost.Initialize에서 AddPlugin<TPlugin>().
Doconut.DoconutHost.Initialize(options =>
{
options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});활성 라이선스가
Converter기능을 부여하지 않을 경우 — 라이선스가 없거나, 레거시TRIAL파일이 있거나, 해당 기능이 없는 라이선스 —DoconutHost.Initialize는Application_Start에서 예외를 발생시킵니다. System.Web에서는 모든 요청이 빈500응답을 반환하며, 이유는 Windows 이벤트 로그(소스 ASP.NET)에만 기록됩니다. 임시 Demo/NFR 라이선스는 허용됩니다. 라이선스 설정을 참조하십시오.
C#에서 변환
각 변환은 0 위치에 설정된 탐색 가능한 MemoryStream을 반환합니다. DocumentConverter는 상태가 없으며, 필요할 때마다 DoconutHost.Services에서 가져와 자유롭게 재사용할 수 있습니다.
// Resolve DocumentConverter from DoconutHost.Services; its constructor is internal, so never `new` it.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);// 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);Stream html = await converter.WordToHtmlAsync("report.docx", ct);Stream docx = await converter.HtmlToWordAsync(html, ConversionTarget.Docx, ct);실수하기 쉬운 두 가지 세부 사항이 있습니다: 스트림 오버로드의 sourceExtension은 앞에 점(".xlsx"), 즉 "xlsx"가 아니라 점을 포함해야 하며, 그렇지 않으면 해석되지 않습니다. 또한 이름과 달리 WordToHtmlAsync는 Task<string>이 아니라 Task<Stream>을 반환합니다 — HTML 문서(이미지는 Base64로 삽입)가 스트림 형태로 도착하며, 다른 결과와 동일합니다.
MVC 5 컨트롤러에서
액션을 비동기로 만들고 변환을 await하십시오:
[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");
}Web Forms에서: 변환 중 절대 차단하지 않기
Web Forms 페이지는 단일 스레드 요청 컨텍스트에서 실행됩니다. ConvertAsync가 완료되면 해당 컨텍스트에서 다시 실행되므로, 동기적으로 기다리는 페이지(.Result, .Wait(), .GetAwaiter().GetResult())는 변환이 완료되기 위해 필요한 스레드를 점유합니다. 요청이 절대 반환되지 않습니다. 브라우저는 계속 로딩 중이며, IIS는 아무 로그도 남기지 않고, 사이트의 다른 부분은 정상적으로 동작하므로 교착 상태라기보다 느린 변환처럼 보입니다.
페이지에 Async="true"를 지정하고 변환을 페이지 비동기 작업으로 실행하십시오:
<%@ Page Language="C#" Async="true" CodeBehind="Convert.aspx.cs" Inherits="MyApp.Convert" %>// 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();
}
}));
}@Page 지시문에 Async="true"가 없으면 RegisterAsyncTask가 조용히 무시됩니다. await 이후에는 페이지의 Context를 사용하십시오; HttpContext.Current는 여기서 null일 수 있습니다.
대상 형식
Pdf, Docx, Doc, Html, Xlsx, Pptx, Png, Jpeg, Csv, Tiff, Bmp, Gif, Svg, Xml,
Txt, Xls, Jp2, Rtf, Odt, Ods, Odp, Epub, Xps, Webp모든 소스가 모든 대상으로 변환되는 것은 아닙니다: 각 소스의 형식군(Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project, PSD, web document)마다 허용되는 대상이 별도로 정의됩니다. 이 열거형을 UI의 대상 목록에 하드코딩하지 마세요: ?convert=open은 업로드된 파일에 대한 allowedTargets를 반환하며, 이는 선택기에 사용되어야 합니다.
드롭인 위젯
위젯의 ?convert=open|run|download 엔드포인트는 DocImage.axd에 의해 제공되며 기본적으로 비활성화되어 있습니다. 플러그인 등록 옆에서 이를 활성화하세요:
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.<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
Doconut.convert('#doconut-convert', { basePath: '/DocImage.axd', maxUploadMb: 25 });
</script>위젯이 올바르게 동작하지 않을 때 확인해야 할 두 가지:
basePath: '/DocImage.axd'. 위젯의 기본값인/doconut은 ASP.NET Core 엔드포인트입니다. 이 패키지에서는 엔드포인트가Web.config의DocImage.axd핸들러입니다.- 스크립트와 엔드포인트는 독립적입니다. 리소스 모듈은 위젯이 활성화되었는지 여부와 관계없이
doconutConverter.js를 제공합니다.AddConverterWidget()을 사용하지 않으면 위젯이 로드되어 드롭 영역을 표시하고 겉보기에는 정상적으로 보이지만, 첫 번째 동작이404를 반환합니다.
업로드 제한
ASP.NET은 DocImage.axd가 실행되기 전에 전체 요청 본문을 읽습니다. MaxUploadMb를 초과하지만 호스트 제한 이하인 업로드는 위젯 자체의 JSON 413("File is too large.") 응답을 받습니다. 호스트 제한을 초과하는 업로드는 IIS에 의해 먼저 거부되며, 위젯이 읽을 수 없는 오류 페이지가 반환됩니다. 위젯의 제한보다 높은 호스트 제한을 Web.config에 모두 설정하십시오:
<system.web>
<httpRuntime maxRequestLength="30720" /> <!-- KILOBYTES: 30 MB -->
</system.web>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="31457280" /> <!-- BYTES: 30 MB -->
</requestFiltering>
</security>
</system.webServer>위젯 맞춤 설정
Doconut.convert(selector, options)에 전달되는 옵션:
| 옵션 | 타입 | 기본값 | 비고 |
|---|---|---|---|
basePath | string | /doconut | 엔드포인트 URL입니다. 이 패키지에서는 '/DocImage.axd'로 설정합니다 |
resPath | string | /doconut-res | 다른 Doconut 위젯과의 일관성을 위해 허용됩니다; 변환 위젯은 이를 사용해 URL을 생성하지 않습니다 |
maxUploadMb | number | 25 | 클라이언트 측 사전 검사만 수행합니다; 서버는 자체 제한을 적용합니다 |
licenseUrl | string | null | null | 결과 화면의 워터마크 알림을 링크로 변환합니다 |
labels | object | {} | 위젯의 영문 문자열 중 일부를 재정의합니다 |
콜백:
| 콜백 | 발생 시점 | 페이로드 |
|---|---|---|
onReady() | 위젯이 드롭 화면을 렌더링했습니다 | — |
onSourceLoaded({ token, pages, sourceExt, allowedTargets }) | ?convert=open이 성공했을 때 | 소스 토큰, 페이지 수, 소스 확장자(점 없이), 허용된 대상 |
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target }) | ?convert=run이 성공했을 때 | 실행 응답과 요청된 target |
onDownload({ downloadName, downloadToken }) | 사용자가 다운로드를 클릭했을 때 | 브라우저 자체 다운로드와 함께 발생 |
onError({ phase, message }) | open 또는 run 요청이 실패했을 때 | phase는 'open' 또는 'run'; message는 정제된 서버 오류 |
Doconut.convert()는 위젯 인스턴스를 반환합니다: reset()은 드롭 화면으로 돌아가게 하고, loadFile(file)은 File을 사용해 흐름을 시작하며, destroy()는 위젯을 제거합니다.
자체 프론트엔드 구축
위젯은 DocImage.axd에서 이 HTTP 계약을 위한 클라이언트입니다:
| 경로 | 목적 | 성공 응답 |
|---|---|---|
POST /DocImage.axd?convert=open (멀티파트, 필드 file) | 소스 문서를 업로드하고 엽니다 | 200 — { token, pages, sourceExt, allowedTargets } |
POST /DocImage.axd?token=<token>&convert=run&target=<ext> | target으로 업로드된 소스를 변환합니다 | 200 — { downloadToken, resultToken, resultPages, downloadName, watermarked } |
GET /DocImage.axd?convert=download&token=<downloadToken> | 변환된 파일을 스트리밍합니다 | 200 — 파일, Content-Disposition: attachment |
업로드된 소스는 30분 동안 보관됩니다; 그 이후에는 run이 404를 반환하고 파일을 다시 열어야 합니다. 변환이 완료되면 downloadToken은 자체 30분 창을 가집니다. resultToken은 뷰어 세션의 수명에 따라 유지되는 일반 뷰어 토큰입니다.
open 응답의 sourceExt는 앞에 점이 없습니다 ("docx") — ConvertAsync의 sourceExtension 매개변수와는 반대입니다.
| 경로 | 상태 | 조건 | 본문 |
|---|---|---|---|
| any | 404 | 위젯이 활성화되지 않았습니다 (AddConverterWidget()가 호출되지 않음) | 상태만 반환 |
| any | 405 | 잘못된 HTTP 메서드 (open/run은 POST 필요, download는 GET 필요) | 상태만 반환 |
open | 413 | 업로드가 MaxUploadMb를 초과했습니다 (IIS 제한은 초과하지 않음) | { "error": "File is too large." } |
open | 400 | 멀티파트 본문이 없거나 파일이 없거나 변환할 수 없는 유형 | { "error": "..." } |
open | 403 | 파일 유형에 필요한 기능이 라이선스에 포함되지 않음 | { "error": "..." } |
run | 400 | 잘못된 토큰, 알 수 없는 target, 또는 allowedTargets에 없는 대상 | { "error": "..." } |
run | 404 | 업로드가 만료되었거나 열리지 않음 | { "error": "Upload expired — please re-open the file." } |
open, run | 500 | 처리 실패 | { "error": "<sanitized message>" } |
download | 400 / 404 | 잘못되었거나 알 수 없거나 만료된 다운로드 토큰 | 상태만 반환 |
리소스 소유권
호출자는 변환이 반환하는 MemoryStream을 소유하며 복사하거나 반환한 후에 이를 해제해야 합니다 (MVC의 File(stream, …)가 자동으로 해제합니다). DocumentConverter를 직접 생성하거나 해제하지 마세요 — 생성자는 내부입니다.
워터마킹
| 라이선스 상태 | 시작 시점 | 변환 출력 |
|---|---|---|
Converter를 제공하는 유료 뷰어 라이선스 | 시작 | 깨끗함 — watermarked: false |
| 활성 임시/데모 라이선스 | 시작 | 변환, 평가 워터마크 포함 — watermarked: true |
라이선스 없음, 레거시 TRIAL 파일, 또는 Converter가 없는 라이선스 | Application_Start에서 예외 발생; 모든 요청이 빈 500을 반환 | — |
| 만료된 임시/데모 라이선스 | 시작 | 변환, 평가 워터마크 포함 — watermarked: true |
구매 전 평가 라이선스로 통합을 처음부터 끝까지 구축하고 테스트할 수 있습니다 — 출력 바이트만 달라집니다.
문제 해결
| 증상 | 점검 |
|---|---|
플러그인 추가 후 모든 요청이 빈 500을 반환 | 라이선스가 Converter를 제공함 — Windows 이벤트 로그, 소스 ASP.NET |
DocumentConverter 해결 시 예외 발생 | AddPlugin<ConverterPlugin>()가 DoconutHost.Initialize에 있음 |
| Web Forms 변환이 절대 반환되지 않음 | 페이지가 ConvertAsync에서 차단됨 — Async="true"와 RegisterAsyncTask 사용 |
| 스트림 변환이 형식을 지원하지 않음 | sourceExtension에 앞점이 포함됨 |
위젯은 로드되지만 요청이 404를 반환 | AddConverterWidget()가 호출되지 않았거나, basePath가 '/DocImage.axd'가 아님 |
| 대용량 업로드 시 위젯 메시지 대신 IIS 오류 페이지 표시 | maxRequestLength / maxAllowedContentLength가 MaxUploadMb보다 낮음 |
| 대상이 누락됨 | convert=open에서 반환된 allowedTargets 사용 |
| 다운로드가 만료됨 | convert=open / convert=run을 다시 수행; 토큰은 의도적으로 일시적임 |
이 페이지가 도움이 되었나요?