From ffdcc2427380f2e59eb60ee7023f64e1f6b9d2e6 Mon Sep 17 00:00:00 2001 From: Marco Wiedemeyer Date: Fri, 28 Nov 2025 14:47:55 +0100 Subject: [PATCH 1/4] Add container support --- Dockerfile | 17 +++++++++++++++++ Dockerfile.windows | 29 +++++++++++++++++++++++++++++ README.md | 17 +++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 Dockerfile create mode 100644 Dockerfile.windows diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dc4ad1c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +#FROM node:24-alpine +FROM ghcr.io/puppeteer/puppeteer:latest + +# Set environment variables for Chromium +ENV XDG_CONFIG_HOME=/tmp/.chromium +ENV XDG_CACHE_HOME=/tmp/.chromium + +WORKDIR /app + +COPY package.json ./ +RUN npm install + +COPY export.js . + +EXPOSE 8000 + +CMD ["npm", "start"] \ No newline at end of file diff --git a/Dockerfile.windows b/Dockerfile.windows new file mode 100644 index 0000000..7ce6e64 --- /dev/null +++ b/Dockerfile.windows @@ -0,0 +1,29 @@ +FROM mcr.microsoft.com/windows/server:ltsc2022 + +# Download and install Node.js +RUN powershell -Command \ + [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12; \ + Invoke-WebRequest -Uri 'https://nodejs.org/dist/v24.11.1/node-v24.11.1-x64.msi' -OutFile 'node-installer.msi'; \ + Start-Process msiexec.exe -ArgumentList '/i', 'node-installer.msi', '/quiet', '/norestart' -NoNewWindow -Wait; \ + Remove-Item 'node-installer.msi' + +# Set working directory +WORKDIR /app + +# Copy package files +COPY package.json ./ + +# Install npm dependencies (including Puppeteer) +RUN npm install + +# Install Puppeteer browser using npx +RUN npx puppeteer browsers install chrome --install-deps + +# Copy application file +COPY export.js . + +# Expose port +EXPOSE 8000 + +# Run the application +CMD ["node", "export.js"] \ No newline at end of file diff --git a/README.md b/README.md index 7f4d40f..80673fb 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,23 @@ The current server-side PNG/PDF export implementation using Node, Puppeteer and Then add export=http://localhost:8000 (hostname and port as needed) as an URL parameter to use that service for development and testing. +### Docker + +* Run `docker build -t draw-image-export .` to build the image +* Run `docker run -it -rm -p 8000:8000 draw-image-export` to start the container and test locally. + +This will run the pupeteer container on Linux. However, because Linux is missing a lot of fonts, the rendered images may not look as expected. To run the container on Windows as a Windows container with better font support, use the `Dockerfile.windows` file: + +* Run `docker build -f Dockerfile.windows -t draw-image-export-windows .` to build the Windows image +* Run `docker run -it -rm -p 8000:8000 c` to start the Windows container and test locally. + +To deploy to Azure App Service for Containers on Windows, follow these steps: + +1. Login to Azure with the Azure CLI: `az login` +2. Login to the Azure Container Registry: `az acr login --name ${your_registry_name}` +3. Build the image with `docker build -t ${your_registry_name}.azurecr.io/draw-image-export-windows -f Dockerfile.windows .` +4. Push the Docker image to the Azure Container Registry: `docker push ${your_registry_name}.azurecr.io/draw-image-export-windows` + ## Updating internal draw.io versions (internal only) * su chrome From d3e401c27afaf5b08c6731696a0be5c921a5a63b Mon Sep 17 00:00:00 2001 From: Marco Wiedemeyer Date: Mon, 1 Dec 2025 14:10:33 +0100 Subject: [PATCH 2/4] update readme --- README.md | 99 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 80673fb..c8f132a 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,24 @@ # draw-image-export2 + The current server-side PNG/PDF export implementation using Node, Puppeteer and Chrome headless ## Running the service (this is your instructions, not the next section) -* npm install -* npm start + +- npm install +- npm start Then add export=http://localhost:8000 (hostname and port as needed) as an URL parameter to use that service for development and testing. ### Docker -* Run `docker build -t draw-image-export .` to build the image -* Run `docker run -it -rm -p 8000:8000 draw-image-export` to start the container and test locally. +- Run `docker build -t draw-image-export .` to build the image +- Run `docker run -it -rm -p 8000:8000 draw-image-export` to start the container and test locally. This will run the pupeteer container on Linux. However, because Linux is missing a lot of fonts, the rendered images may not look as expected. To run the container on Windows as a Windows container with better font support, use the `Dockerfile.windows` file: -* Run `docker build -f Dockerfile.windows -t draw-image-export-windows .` to build the Windows image -* Run `docker run -it -rm -p 8000:8000 c` to start the Windows container and test locally. +- Run `docker build -f Dockerfile.windows -t draw-image-export-windows .` to build the Windows image +- Run `docker run -it -rm -p 8000:8000 c` to start the Windows container and test locally. To deploy to Azure App Service for Containers on Windows, follow these steps: @@ -27,40 +29,46 @@ To deploy to Azure App Service for Containers on Windows, follow these steps: ## Updating internal draw.io versions (internal only) -* su chrome -* cd ~/draw-image-export2 -* git pull -* npm install -* forever restartall +- su chrome +- cd ~/draw-image-export2 +- git pull +- npm install +- forever restartall ## Usage + This service accepts the following (url encoded) parameters provided via a HTTP (GET or POST) request. All parameters are optional except where emboldened. `data-string` means a string of data that has been: + 1. deflated _then_ 2. base64 encoded _then_ 3. url-encoded There are 2 available modes for the service: + 1. _(mode 1)_ Render some html that is provided 2. _(mode 2)_ Render a diagram from some html (which can be provided or retrieved from a given url) ### Mode 1: Provide some html to render -| Argument | Type | Purpose | Default | Example | -| ---- | ---- | ---- | ---- | ---- | -| **html** | data-string | html to render | | - | -| w | number | Set the view port height | 0 | 10 | -| h | number | Set the view port width | 0 | 10 | +| Argument | Type | Purpose | Default | Example | +| -------- | ----------- | ------------------------ | ------- | ------- | +| **html** | data-string | html to render | | - | +| w | number | Set the view port height | 0 | 10 | +| h | number | Set the view port width | 0 | 10 | Note: Format is fixed to `png` for this mode. ### Mode 2: Render a diagram + To render a diagram, the `diagram-data` must be retrieved, this is the draw.io data that can be used to re-render the diagram. There are 2 modes to get this data: + 1. _(mode 2.1)_ Provide a url to a resource 1. _(mode 2.2)_ Provide the data in the request Whichever option is used the following process will be followed to extract the diagram data: + 1. If the data is a XHTML document (well-structured HTML) 1. For the first `div` with the `mxgraph` class defined 1. Use the data in the `data-mxgraph` attribute (if one is present) _OR_ @@ -70,50 +78,55 @@ Whichever option is used the following process will be followed to extract the d #### Mode 2.1: Get `diagram-data` from url -| Argument | Type | Purpose | Default | Example | -| ---- | ---- | ---- | ---- | ---- | -| **url** | string | absolute url to diagram to render | | - | +| Argument | Type | Purpose | Default | Example | +| -------- | ------ | --------------------------------- | ------- | ------- | +| **url** | string | absolute url to diagram to render | | - | #### Mode 2.2: Get `diagram-data` from xml (or svg) + Provide either `xmldata` or `xml`, `xmldata` takes precedence. -| Argument | Type | Purpose | Default | Example | -| ---- | ---- | ---- | ---- | ---- | -| **xmldata** | data-string | Content of the diagram to render | | - | -| **xml** | string (optionally url-encoded) | Content of the diagram to render | | - | +| Argument | Type | Purpose | Default | Example | +| ----------- | ------------------------------- | -------------------------------- | ------- | ------- | +| **xmldata** | data-string | Content of the diagram to render | | - | +| **xml** | string (optionally url-encoded) | Content of the diagram to render | | - | #### Common parameters -| Argument | Type | Purpose | Default | Example | -| ---- | ---- | ---- | ---- | ---- | -| format§ (see below) | string | The renderering format for the diagram | png | pdf | -| w§ | number | Set the view port height | 0 | 10 | -| h§ | number | Set the view port width | 0 | 10 | -| embedXml* | string | Embed the diagram data in the png | | "0" or "1" | -| base64 | string | Whether the response data should be base64 (and png embedded data) encoded | | "0" or "1" | -| bg§ | string | The background colour for the image | | "#ff8888" | -| embedData* | string | Embed `data` in the png with the `dataHeader` key | null | "0" or "1" | -| data* | string | The data to embed into the png | | - | -| dataHeader* | string | The key to use when embedding the `data` into the png | | "myKey" | -| filename | string | The filename to included in the content-disposition header | | "myFile.png" | -| border¶ | number | The size of the border for the page | 0 | 10 | -| from¶ | number | The index of the page to start rendering from | | 1 | -| to¶ | number | The index of the page to finish rendering at | | 2 | -| pageId¶ | string | The id of the page to render | | "page id" | -| allPages¶ | string | Whether all pages should be rendered | "0" | "0" or "1" | -| scale¶ | number | The scale for the rendered diagram | 1 | 1.5 | -| extras¶ | json-string | Additional detail how what should be rendered, e.g. layer-names | | ? | + +| Argument | Type | Purpose | Default | Example | +| ------------------- | ----------- | -------------------------------------------------------------------------- | ------- | ------------ | +| format§ (see below) | string | The renderering format for the diagram | png | pdf | +| w§ | number | Set the view port height | 0 | 10 | +| h§ | number | Set the view port width | 0 | 10 | +| embedXml\* | string | Embed the diagram data in the png | | "0" or "1" | +| base64 | string | Whether the response data should be base64 (and png embedded data) encoded | | "0" or "1" | +| bg§ | string | The background colour for the image | | "#ff8888" | +| embedData\* | string | Embed `data` in the png with the `dataHeader` key | null | "0" or "1" | +| data\* | string | The data to embed into the png | | - | +| dataHeader\* | string | The key to use when embedding the `data` into the png | | "myKey" | +| filename | string | The filename to included in the content-disposition header | | "myFile.png" | +| border¶ | number | The size of the border for the page | 0 | 10 | +| from¶ | number | The index of the page to start rendering from | | 1 | +| to¶ | number | The index of the page to finish rendering at | | 2 | +| pageId¶ | string | The id of the page to render | | "page id" | +| allPages¶ | string | Whether all pages should be rendered | "0" | "0" or "1" | +| scale¶ | number | The scale for the rendered diagram | 1 | 1.5 | +| extras¶ | json-string | Additional detail how what should be rendered, e.g. layer-names | | ? | \* Only applicable when format is `png`. § means property is used by both this service and draw.io (https://www.draw.io/export3.html) to control how the diagram is rendered. ¶ means property is passed to draw.io (https://www.draw.io/export3.html) to control how the diagram is rendered. ### Formats + The following formats can be used + - 'png' (default) - 'jpg' (or 'jpeg') - 'pdf' ## Examples + ### Example 1 (render a diagram in png format from provided diagram data) ``` @@ -127,6 +140,8 @@ format=png&xml=%3Cmxfile+... ### Example 2 (render a diagram in png format from provided url - to a diagram file) +> ⚠️ Export by URL is currently disabled! + ``` GET https://exp-pdf.draw.io/ImageExport4/export?format=png&bg=ffffff&url=https://somewhere/diagram.xml HTTP/1.1 Host: exp-pdf.draw.io From 684a3cad662795bc9e0ec54bedd80d3805e09db7 Mon Sep 17 00:00:00 2001 From: Marco Wiedemeyer Date: Tue, 9 Dec 2025 08:08:23 +0100 Subject: [PATCH 3/4] add health endpoint --- export.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/export.js b/export.js index 856f070..930736f 100644 --- a/export.js +++ b/export.js @@ -260,6 +260,7 @@ else } app.post('/{*splat}', handleRequest); + app.get('/health', handleHealthRequest); app.get('/{*splat}', handleRequest); async function handleRequest(req, res) @@ -770,6 +771,10 @@ else } }; + async function handleHealthRequest(req, res) { + res.status(200).end("OK"); + } + app.listen(PORT, function () { if (NO_CLUSTER) From cc2a1b79ba25a0fdfeb347b2fbb3b8daeaf19bf3 Mon Sep 17 00:00:00 2001 From: Marco Wiedemeyer Date: Tue, 9 Dec 2025 08:33:43 +0100 Subject: [PATCH 4/4] add acr build command to readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index c8f132a..d99cd9b 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,12 @@ To deploy to Azure App Service for Containers on Windows, follow these steps: 3. Build the image with `docker build -t ${your_registry_name}.azurecr.io/draw-image-export-windows -f Dockerfile.windows .` 4. Push the Docker image to the Azure Container Registry: `docker push ${your_registry_name}.azurecr.io/draw-image-export-windows` +> **If you do not have a Windows container setup, you can use the Azure Container Registry Tasks to build the image in the cloud.** + +1. Login to Azure with the Azure CLI: `az login` +2. Login to the Azure Container Registry: `az acr login --name ${your_registry_name}` +3. Run `az acr build -r ${your_registry_name} -t imageexport:latest -f Dockerfile.windows . --platform windows` + ## Updating internal draw.io versions (internal only) - su chrome