What this is about
A report often needs pictures: the customer’s logo, a signature, photos of an inspection, a diagram. CRMS never loads anything from the network or the file system. A picture reaches the document in exactly one of three ways.
The three ways
| Asset | Attachment | SVG | |
|---|---|---|---|
| Belongs to | the template's revision | the one request | the payload, as text |
| In the template | asset:<name> | attachment:<name> | ${crms.svg(field)} |
| Allowed kinds | what the template approved, e.g. logo, font | image/png, image/jpeg | SVG within the allow-list |
| Formats | HTML, PDF, DOCX | PDF only | HTML, PDF, DOCX |
| With FINAL | yes | no | yes |
You upload assets with the template, see How a template is built. The two namespaces asset: and attachment: stay apart. An attachment can never replace an asset of the approved revision, not even with the same name.
Attachments: pictures of this one request
An attachment is a picture that exists only for this call. Which picture the template shows is usually decided by the payload: the template writes <img src="attachment:${signature}"/>, and you put the name into the payload.
POST /crms/render
Content-Type: application/json
Content-Encoding: gzip
{
"template": "inspection-report",
"format": "PDF",
"mode": "TRANSIENT",
"data": { "signature": "signature-inspector.png" },
"attachments": [
{ "name": "signature-inspector.png",
"contentType": "image/png",
"content": "iVBORw0KGgo…" }
]
}HTTP 200
Content-Type: application/pdf
%PDF-1.7 … ← the signature is in the PDFOver REST, each attachment comes with name, contentType and content in Base64. Base64 makes the data a third larger. With Content-Encoding: gzip you get almost all of it back; crms-client compresses requests with attachments by itself. Embedded, you pass the bytes directly as a RenderAttachment.
CRMS checks the attachments together with the payload and reports all violations in one answer (422 payload-rejected). The field is attachments[<i>], the position in the list, or attachments for a limit.
| Rule | When |
|---|---|
attachments-too-many|<max> | more attachments than allowed (default 200, CODAMAI_CRMS_ATTACHMENTS_MAX_COUNT) |
attachments-too-large|<max> | together larger than allowed (default 50 MiB, CODAMAI_CRMS_ATTACHMENTS_MAX_BYTES) |
name-invalid | not a plain file name: letters, digits, ., _, - are allowed, at most 128 characters, not starting with . |
name-duplicate | an earlier attachment of this request already has the same name |
type-not-allowed | neither image/png nor image/jpeg |
empty | no bytes |
content-mismatch | the bytes do not start like a PNG or JPEG file, as declared |
Beyond a limit, CRMS no longer looks at the attachments one by one.
| Attachments present? | Mode | Format | Result |
|---|---|---|---|
| no | – | – | no check of attachments |
| yes | FINAL | – | 422 attachments-not-for-final |
| yes | PREVIEW or TRANSIENT | HTML, DOCX, XLSX, CSV, ODS | 422 attachments-not-for-format|<format> |
| yes | PREVIEW or TRANSIENT | attachments are checked and drawn |
If the template names an attachment:<name> the request does not bring, the PDF fails with render-resource-refused. CRMS does not hand out a document with holes where pictures should be.
SVG from the payload: crms.svg
A diagram your application draws itself, for example a topology, you send as SVG text in the payload. Normally a template always writes text from the payload as text, never as markup: ${diagram} shows the angle brackets. It only reaches the document as a graphic through the function crms.svg, which every template has:
<div class="figure">${crms.svg(diagram)}</div>
crms belongs to CRMS. A payload field named crms does not replace the function.
CRMS reads the SVG as XML, without DTD and without entities other than the five predefined ones, and checks it against an allow-list:
| What | Allowed | Not allowed |
|---|---|---|
| Root | <svg> in the SVG namespace | anything else |
| Elements | svg, g, defs, symbol, use, path, rect, circle, ellipse, line, polyline, polygon, text, tspan, textPath, linearGradient, radialGradient, stop, marker, clipPath, title, desc, style | among others script, foreignObject, image, a, animations, filter, metadata |
| Attributes | geometry, fill and stroke, text, gradients, markers, id, class, style, aria-*, plus xlink:href, xml:space, xml:lang | any on… attribute, attributes from other namespaces |
| References | only to a place in the same SVG: href="#id", url(#id) | any address outside |
| CSS | in style attributes and <style> | @import, CSS escapes with \ |
CRMS removes an XML declaration at the start. The rest goes into the document exactly as it was checked. If something is not allowed, rendering fails with 422 template-svg-rejected. CRMS cleans nothing out, because a diagram with silently removed parts would be a wrong diagram. A value that is not text, for example a number, is also template-svg-rejected.
| Output type | What crms.svg makes of it |
|---|---|
DOCUMENT | HTML shows the SVG inline. PDF draws it as vector graphics, without scripts and without external resources. If it cannot be drawn, that is render-pdf-failed |
WORD | The function writes a placeholder that must stand where a run stands in Word, that is inside a <w:p>. CRMS checks the SVG once more, converts it into a PNG and inserts it as a picture at its declared size. The SVG’s <title> becomes the picture description |
TABLE | refused: template-svg-not-for-output-type|table |
For DOCX, CRMS reads the size from width and height of the root (px, pt, pc, mm, cm, in). If they are missing, it uses the viewBox, otherwise 300 × 150 pixels. The PNG has twice the pixels so it stays sharp in print, at most 4096 pixels per side.