squish

Ogni POST di lavoro richiede l'header X-Api-Key; restano aperti /health, la pagina di test e i link condivisi. Il servizio è raggiungibile da Internet senza TLS: non ci sono password o dati riservati negli URL, ma i documenti viaggiano in chiaro.
Due regole che fanno risparmiare ore, per FileMaker:
1) In ingresso il contenuto (immagine, PDF, XML) va sempre referenziato da una variabile — --data-binary @$var — mai incollato dentro la stringa delle opzioni cURL. FileMaker spezza le opzioni sugli spazi, e un < subito dopo un = viene letto come "leggi da file". Un XML o un binario incollati inline non arriveranno mai interi.
2) In uscita, se il Target dell'Insert from URL è una variabile (non un campo container), va aggiunta l'opzione --FM-return-container-variable: senza, FileMaker tratta la risposta binaria come testo e dà errore 507. Con un campo container come Target non serve. Vale per tutti gli endpoint che restituiscono un file (immagini, PDF, PNG).

squish

Ottimizzazione immagini (imgservice, porta 3002)  ·  http://squish.cmisolutions.it:3002

Comprime e ridimensiona immagini. In ingresso: BMP, JPEG, PNG, WebP, AVIF e HEIC/HEIF (le foto iPhone). In uscita: JPEG, WebP, AVIF (il più compresso), PNG. Nasce per aggirare il limite di GetThumbnail di FileMaker, che sa solo ridimensionare producendo JPEG e non sa ricomprimere a qualità controllata mantenendo la risoluzione. Usa Pillow (+ pillow-heif per l'HEIC): nessuna dipendenza di sistema, tutto dentro /app.

POST/fontsX-Api-Key

Carica un font (TTF/OTF)

Aggiunge un font per la filigrana di testo (wm_font=nome), oltre a quelli preinstallati. Via programmatica con la chiave normale, o a mano dal pannello di amministrazione. Il file va nel corpo grezzo, il nome nella query.

Input accettati. corpo grezzo = il .ttf/.otf  •  oppure multipart file

parametrovaloridefaultnote
nometestoobbligatoriolettere/cifre/-/_; stesso nome = sovrascrive

cURL

curl -X POST -H "X-Api-Key: LA_TUA_CHIAVE" \
  --data-binary @MioFont.ttf "http://squish.cmisolutions.it:3002/fonts?nome=aziendale"

curl -H "X-Api-Key: LA_TUA_CHIAVE" "http://squish.cmisolutions.it:3002/fonts"    # elenco (nome, formato, bytes)

Risposta

JSON {"ok": true, "nome": "aziendale"}. GET /fonts/<nome> scarica il font; DELETE /fonts/<nome> lo elimina.

Da sapere

  • ~57 font già preinstallati da Google Fonts (OFL/Apache): elenco con GET /fonts. Coprono sans, serif, titoli/display, monospace e script.
  • Solo TTF/OTF, max 10 MB. Carica font di cui hai la licenza d'uso: il servizio non può verificarlo.

POST/optimizeX-Api-Key

Ottimizza un'immagine

Alias: /optimize/image

Riceve l'immagine come binario grezzo nel corpo della richiesta e restituisce la versione ottimizzata, sempre binaria, pronta per un campo container. Accetta anche i HEIC/HEIF delle foto iPhone (trasparente: mandi il .heic e scegli il formato di uscita). Gestisce l'orientamento EXIF, converte CMYK in RGB e appiattisce la trasparenza su bianco quando l'uscita è JPEG (l'AVIF invece la conserva). Guardia anti decompression-bomb a 120 megapixel.

parametrovaloridefaultnote
formatjpeg | webp | avif | png | autojpegauto = png se c'è trasparenza, altrimenti jpeg. avif = più compresso (~−49% vs jpeg)
quality1-10082ignorato per png, che è lossless
maxwpx—larghezza massima; mantiene le proporzioni e non ingrandisce mai
maxhpx—altezza massima
strip0 | 11rimuove i metadati EXIF/ICC
filenametesto(nome originale)nome del file restituito; l'estensione la mette il servizio in base al formato
wmtesto—filigrana di testo: se presente, sovrappone questo testo
wm_fontnome font(default)font per il testo: un preinstallato o uno caricato nel pannello (vedi sotto)
wm_imagenome preset—filigrana logo PNG: usa un PNG caricato nel pannello di amministrazione. Ha priorità sul testo
wm_posbr | bl | tr | tl | center | tilebrangoli, centro, o tile = ripetuto su tutta l'immagine
wm_size1-506altezza del testo in % della larghezza dell'immagine
wm_color#rrggbb o nome CSS#ffffffcolore del testo
wm_opacity0-100500 = invisibile, 100 = pieno
wm_rotategradi045 per la classica diagonale

cURL

# comprimi e ridimensiona
curl -X POST \
  -H "X-Api-Key: LA_TUA_CHIAVE" \
  --data-binary @foto.bmp \
  "http://squish.cmisolutions.it:3002/optimize?format=jpeg&quality=80&maxw=1600" \
  -o ottimizzata.jpg

# filigrana diagonale al centro, con un font preinstallato (Oswald)
curl -X POST -H "X-Api-Key: LA_TUA_CHIAVE" --data-binary @foto.jpg \
  "http://squish.cmisolutions.it:3002/optimize?wm=COPIA+NON+VALIDA&wm_font=oswald&wm_pos=center&wm_rotate=25&wm_size=11&wm_opacity=55" \
  -o filigranata.jpg

# foto iPhone HEIC -> AVIF (doppia compressione: formato di uscita moderno)
curl -X POST -H "X-Api-Key: LA_TUA_CHIAVE" --data-binary @foto.heic \
  "http://squish.cmisolutions.it:3002/optimize?format=avif&quality=55&maxw=2000" -o foto.avif

# logo PNG trasparente (caricato prima nel pannello di amministrazione come "logo_cmi")
curl -X POST -H "X-Api-Key: LA_TUA_CHIAVE" --data-binary @foto.jpg \
  "http://squish.cmisolutions.it:3002/optimize?wm_image=logo_cmi&wm_pos=br&wm_size=22&wm_opacity=80" \
  -o con_logo.jpg

FileMaker

Set Variable [ $img ; value: Immagini::ContainerOriginale ]

Insert from URL [
    Select ; With dialog: Off ;
    Target: Immagini::ContainerOttimizzato ;      // campo container: nessuna opzione extra
    "http://squish.cmisolutions.it:3002/optimize?format=jpeg&quality=80&maxw=1600" ;
    cURL options:
        "--data-binary @$img "
      & "-H \"X-Api-Key: " & $$API_KEY & "\" "
      & "-H \"Content-Type: application/octet-stream\""
      // Se il Target è una VARIABILE (es. $risultato) invece di un campo container,
      // aggiungi questa opzione, altrimenti FileMaker dà errore 507:
      // & " --FM-return-container-variable"
]

Risposta

L'immagine binaria. Header: X-Original-Bytes, X-Optimized-Bytes, X-Ratio, X-Dimensions, X-Source-Format. Il Content-Disposition dà il nome al file nel container (vedi sotto per conservarlo).

Da sapere

  • Destinazione a variabile → errore 507: se il Target dell'Insert from URL è una variabile (non un campo container), aggiungi --FM-return-container-variable alle cURL options, altrimenti FileMaker interpreta il binario come testo e dà 507. Con un campo container come Target non serve.
  • Conservare il nome del file: con --data-binary il nome NON viaggia (arrivano solo i byte) → l'uscita è optimized.<ext>. Per mantenerlo hai due strade: usa -F "file=@$img" (il container porta con sé il nome, preservato in automatico), oppure passa ?filename=nome. In entrambi i casi cambia solo l'estensione secondo il formato.
  • Accetta sia il corpo grezzo (--data-binary, consigliato) sia il multipart (-F file=@...). Quest'ultimo serve proprio a portare il nome del file.
  • Un BMP è non compresso: convertirlo in JPEG è il caso con più guadagno (misurato: 18 MB → 1,5 MB, −91%).
  • Su un JPEG a parità di risoluzione conta solo quality (misurato: q95 3,3 MB → q75 1,27 MB, −62%).
  • Filigrana e compressione si fanno in un colpo solo: sono parametri dello stesso endpoint, non due chiamate. Con le immagini il costo vero è il trasferimento.
  • La filigrana testuale usa il font incorporato in Pillow (sull'appbox non c'è alcun font di sistema, e /usr è effimero): un solo carattere, ma funziona sempre.
  • La filigrana a logo (wm_image) usa un PNG trasparente caricato una volta nel pannello di amministrazione (sezione Filigrane) e richiamato per nome: il logo non viaggia a ogni chiamata. wm_opacity modula la trasparenza già presente nel PNG, wm_color viene ignorato (il logo ha i suoi colori).
  • Font (wm_font): la filigrana di testo può usare un font diverso dal default. Ci sono ~57 font preinstallati da Google Fonts (OFL/Apache) — elenco completo con GET /fonts o nel pannello. Qualche esempio per categoria: sans roboto/poppins/inter/lato/montserrat/raleway; titoli/timbri anton/bebasneue/oswald/archivoblack/bungee/staatliches; serif merriweather/playfairdisplay/lora/ebgaramond; mono robotomono/jetbrainsmono/spacemono; script pacifico/dancingscript/caveat/lobster. Puoi aggiungerne altri (TTF/OTF) dal pannello di amministrazione o via POST /fonts.
  • Se il testo è troppo lungo o wm_size troppo alto, la filigrana viene rimpicciolita per stare dentro invece di essere tagliata dal bordo (verificato). tile fa eccezione: lì deve uscire dai bordi.
  • mozjpeg non è disponibile senza dipendenze di sistema: si usa libjpeg-turbo con optimize+progressive.

POST/watermarksX-Api-Key

Carica un logo/filigrana PNG

Salva un PNG trasparente come preset, richiamabile poi con ?wm_image=nome. Via programmatica (chiave normale, anche da FileMaker); la stessa cosa si fa a mano dal pannello di amministrazione. Il PNG va nel corpo grezzo, il nome nella query.

Input accettati. corpo grezzo = il PNG  •  oppure multipart file

parametrovaloridefaultnote
nometestoobbligatoriolettere, cifre, - e _; caricare lo stesso nome sovrascrive

cURL

curl -X POST -H "X-Api-Key: LA_TUA_CHIAVE" \
  --data-binary @logo.png \
  "http://squish.cmisolutions.it:3002/watermarks?nome=logo_cmi" 

FileMaker

Set Variable [ $png ; value: Loghi::LogoPNG ]

Insert from URL [
    Select ; With dialog: Off ; Target: $risposta ;
    "http://squish.cmisolutions.it:3002/watermarks?nome=logo_cmi" ;
    cURL options: "--data-binary @$png -H \"X-Api-Key: " & $$API_KEY & "\""
]

Risposta

JSON {"ok": true, "nome": "logo_cmi"}.

Da sapere

  • Solo PNG (serve la trasparenza), max 5 MB, fino a 50 filigrane totali.
  • Le filigrane sono condivise fra tutti i soggetti: con la chiave normale chiunque può sovrascriverle o eliminarle. Nel contesto CMI (database tutti interni) è accettabile.

GET/watermarksX-Api-Key

Elenca le filigrane

Nomi e dimensioni delle filigrane caricate. GET /watermarks/<nome> scarica il PNG.

cURL

curl -H "X-Api-Key: LA_TUA_CHIAVE" "http://squish.cmisolutions.it:3002/watermarks"
curl -H "X-Api-Key: LA_TUA_CHIAVE" "http://squish.cmisolutions.it:3002/watermarks/logo_cmi" -o logo.png

Risposta

JSON con watermarks[] (nome, bytes). Il singolo restituisce il PNG.

Da sapere

  • Per eliminare: DELETE /watermarks/<nome> con la chiave.

Comuni

Autenticazione e stato del servizio

Valgono per ogni endpoint di questo servizio.

GET/healthsenza chiave

Stato del servizio

Sonda di vita, aperta e non contabilizzata: un check ogni minuto non sporca le statistiche.

cURL

curl http://squish.cmisolutions.it:3002/health

Risposta

JSON con status, service, la versione della libreria e auth (se l'obbligo di chiave è attivo).

—Autenticazionesenza chiave

Come funzionano le chiavi

Una chiave = un soggetto (un database FileMaker, uno script, n8n). Ogni chiave porta l'elenco dei servizi su cui è abilitata, quindi la stessa chiave può valere su più servizi — ed è quello che vuoi: così le statistiche attribuiscono tutto il consumo a un'unica riga. Non condividere una chiave fra due soggetti: perderesti proprio l'informazione per cui l'hai creata. Le chiavi le gestisce l'amministratore: se te ne serve una, o la tua non funziona più, chiedila a lui.

cURL

# su ogni POST di lavoro
-H "X-Api-Key: cmi_xxxxxxxxxxxx"

# in FileMaker, tenendo la chiave in una variabile globale sola:
"-H \"X-Api-Key: " & $$API_KEY & "\"" 

Risposta

Se la chiave manca o è errata: 401 con un messaggio esplicito (mancante, non riconosciuta, revocata, non abilitata per questo servizio).

Da sapere

  • Restano aperti senza chiave: /health e la pagina di test su /.
  • Revoche e nuove chiavi hanno effetto immediato, senza riavviare i servizi.
  • Oltre ai servizi, una chiave può essere ristretta ai singoli endpoint. Se è abilitata al servizio ma non a quella rotta la risposta è 403 (non 401: la chiave è valida, manca il permesso). Le restrizioni si impostano dal pannello di amministrazione e valgono subito.
  • Ogni risposta porta X-Esito: ok|errore e X-Status. Servono da FileMaker: Insert from URL NON fallisce sugli errori HTTP — Get(LastError) resta 0 e il corpo dell'errore finisce nel contenitore, sovrascrivendo l'allegato buono. Con --dump-header $h si controlla l'esito prima di scrivere sul campo. Regola d'oro: mandare il risultato in una variabile, verificare, e solo allora fare Set Field.
  • Nome del file restituito: gli endpoint che restituiscono un file accettano ?filename=. Senza, si usa il nome originale se l'invio è multipart (che lo porta con sé); con --data-binary il nome si perde, quindi lì il parametro serve. L'estensione è sempre quella d'uscita, sostituita e non appesa. Il nome è anche nell'header X-Filename.