feat: adicionar suporte a impressoras pequenas com parâmetro dpi e layout adaptativo para etiquetas

This commit is contained in:
2026-03-14 21:21:15 -03:00
parent b6e4aa7622
commit 5c8d6a368e
6 changed files with 261 additions and 64 deletions
+68 -5
View File
@@ -374,16 +374,17 @@ O backend implementa **last-write-wins com timestamp**:
### Etiqueta SVG (`GET /filaments/:id/label.svg`)
- Query params: `width_mm` (padrão: 50), `height_mm` (padrão: 30), `fields` (opcional)
- Retorna SVG com os campos selecionados embutidos
- Query params: `width_mm` (padrão: 50), `height_mm` (padrão: 30), `fields` (opcional), `dpi` (opcional, padrão 96)
- Layout adaptativo: modo **mini** para `width_mm < 30` ou `height_mm < 20`
- `dpi` afeta `px_per_mm` e portanto as dimensões em pixels do SVG gerado
- `Content-Type: image/svg+xml`
- `Content-Disposition: attachment; filename="meowspool-label-{id}.svg"`
### Etiqueta PDF (`GET /filaments/:id/label.pdf`)
- Query params: `width_mm` (padrão: 50), `height_mm` (padrão: 30), `fields` (opcional)
- Retorna PDF de página única com dimensões exatas em mm — ideal para impressoras de etiqueta (Brother, Dymo)
- Gerado com `printpdf`: fundo escuro `#1E1B18`, barra de cor do filamento, texto com Helvetica builtin, QR Code embutido como PNG luma
- Query params: `width_mm` (padrão: 50), `height_mm` (padrão: 30), `fields` (opcional), `dpi` (opcional, reservado)
- Layout adaptativo: modo **mini** para `width_mm < 30` ou `height_mm < 20` — fontes e posições proporcionais, garante que nenhum elemento saia da página
- Gerado com `printpdf`: fundo escuro `#1E1B18`, barra de cor do filamento, texto com Helvetica builtin, QR Code PNG luma embutido com `interpolate: false` (bordas nítidas em impressoras térmicas)
- `Content-Type: application/pdf`
- `Content-Disposition: attachment; filename="meowspool-label-{id}.pdf"`
@@ -404,6 +405,33 @@ Se `fields` for omitido, todos os elementos são incluídos.
Implementado em `LabelFields` (`filament_service.rs`) — `LabelFields::from_str(Option<&str>)`.
### Parâmetro `dpi` (SVG e PDF)
Controla o DPI alvo da impressora. Afeta o cálculo de pixels do SVG e garante QR nítido em impressoras térmicas.
| Impressora | `dpi` recomendado |
| --------------------- | ----------------- |
| Tela / padrão | 96 (omitir param) |
| Niimbot D11/D110 | 203 |
| Brother QL / Dymo | 300 |
### Layout adaptativo ("mini" vs padrão)
Etiquetas com `width_mm < 30` **ou** `height_mm < 20` ativam o modo **mini**, que:
- Usa fontes menores (proporcionais à altura física)
- Posiciona QR Code com margem de 1mm (vs 2mm no padrão)
- Estreita a barra de cor (~11% da largura vs ~5% + 6px no padrão)
- Encurta o rótulo de peso: `"320g"` em vez de `"320g disponível"`
- Separador de marca/material: espaço simples em vez de ` · ` (economiza espaço)
- No SVG, o separador de meta usa espaço em vez de ` · `
- Garante que nenhum texto extrapole a borda inferior da etiqueta
Exemplo para Niimbot 22×14mm:
```
GET /api/v1/filaments/:id/label.pdf?width_mm=22&height_mm=14&fields=color,name,qrcode&dpi=203
GET /api/v1/filaments/:id/label.svg?width_mm=22&height_mm=14&fields=color,name,qrcode&dpi=203
```
---
## Segurança
@@ -419,6 +447,41 @@ Implementado em `LabelFields` (`filament_service.rs`) — `LabelFields::from_str
## Mudanças Recentes (14/03/2026)
### ✅ Suporte a Impressoras Pequenas — Niimbot e layout adaptativo
**Arquivos alterados**: `filament_handler.rs`, `filament_service.rs`
#### Novo query param `dpi`
Adicionado campo `dpi: Option<u32>` ao `LabelQuery` (handler). Aceito em `/label.svg` e `/label.pdf`. Valores recomendados:
| Impressora | `dpi` |
| ---------------- | ----- |
| Tela / padrão | omitir (96) |
| Niimbot D11/D110 | 203 |
| Brother / Dymo | 300 |
No SVG, `dpi` define `px_per_mm = dpi / 25.4` — o tamanho em pixels do arquivo corresponde à resolução física da impressora. No PDF, o `dpi` é ignorado (PDF já trabalha em mm), mas reservado para uso futuro.
#### Layout adaptativo — modo "mini"
Ativado quando `width_mm < 30` **ou** `height_mm < 20` (ex: Niimbot 22×14mm). Diferenças em relação ao modo padrão:
| Aspecto | Padrão | Mini |
| --- | --- | --- |
| Barra de cor | 3.5mm fixo | 11% da largura |
| QR size | 75% da altura | 80% da altura |
| Margem QR | 2mm | 1mm |
| Y do texto | `h - 8/14/20` (fixo, quebrava para h<20) | `h * 0.72/0.50/0.28` (proporcional) |
| Fontes | 79pt fixo | proporcionais à altura física |
| Rótulo peso | `"320g disponível"` | `"320g"` |
| Separador meta | ` · ` | ` ` (espaço) |
| `interpolate` no QR (PDF) | `true` | `false` (bordas nítidas em térmica) |
**Correção crítica**: no modo anterior, `Mm(h - 20.0)` gerava coordenada negativa para `h < 20mm` (Niimbot), colocando o texto fora da página.
---
### ✅ Exportação de Etiqueta PDF (`GET /filaments/:id/label.pdf`)
- **Dependência**: `printpdf = "0.7"` adicionada ao `Cargo.toml`