You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hoje o gerador de PDF decide layout (1 ou 2 colunas, largura de tabela/figura) através de duas heurísticas isoladas e desconectadas:
renderer/docx/figure.py::decide_figure_layout decide por DPI da imagem.
pipeline/xml.py::determine_table_layout decide por contagem de coluna (> 4).
Nenhuma das duas retorna largura real nem justificativa — só um rótulo de string. A geometria de página (enum.py::PAGE_ATTRIBUTES) é uma constante fixa em A4/2-colunas, sem possibilidade de configuração por periódico. Isso já causou pelo menos um caso real de infidelidade visual confirmado contra PDF publicado (ver "Considerações").
Esta tarefa introduz um "modelo intermediário" de layout — LayoutConfig — como abstração central e reutilizável que:
Centraliza geometria de página/coluna/margem por periódico (PageProfile), com fallback para o default atual (A4, 2 colunas) quando o periódico não estiver calibrado.
Faz tabela e figura consultarem o mesmo contexto de layout, em vez de cada uma ter sua própria noção de largura disponível.
Retorna toda decisão como objeto estruturado (LayoutDecision): largura resolvida + justificativa legível + origem do julgamento (medido/heurística/override) — não só um rótulo.
Expõe uma abstração explícita (full_width()) para "quebrar pra largura total e restaurar depois", substituindo a lógica de quebra/restauração de seção hoje duplicada entre tabela e figura.
Permite calibrar um periódico por ISSN eletrônico (profiles/{issn_epub}.json), detectado automaticamente a partir do XML de entrada — sem precisar de flag manual.
determine_table_layout consulta LayoutConfig quando fornecido, mantendo o comportamento atual quando não
decide_figure_layout/add_figure/_compute_single_column_width (figure.py) idem
_compute_table_width (table.py) idem
pipeline_docx detecta o ISSN eletrônico do XML e carrega o perfil calibrado automaticamente (load_profile), com fallback ao default quando não calibrado
Registro de perfis por periódico em packtools/sps/formats/pdf/profiles/{issn_epub}.json (3 periódicos calibrados por medição contra PDF publicado: Acta Amazonica, Acta Botanica Brasilica, Anuário Antropológico)
Testes automatizados cobrindo 1 coluna, 2 colunas e alternância temporária com retorno correto (tests/sps/formats/pdf/test_layout_config.py, mais testes de integração em pipeline/test_xml.py e novo renderer/docx/test_figure.py/test_table.py)
Validação ponta a ponta contra PDF publicado real, para os 3 periódicos calibrados (comparação visual + medição de bounding box)
Expor seleção manual de 1/2 colunas via API Python e CLI (pdf_generator) — hoje a escolha é sempre automática via perfil, sem override explícito do usuário final
Ligar largura real de coluna medida (column_min_widths_pt) na decisão de tabela — hoje determine_table_layout sempre cai no fallback heurístico (contagem de coluna), porque não há largura por coluna medida disponível nesse ponto do pipeline
Calibrar mais periódicos além dos 3 iniciais
Considerações e notas
Achado motivador: teste ponta a ponta com tests/fixtures/pdf/a1.xml (Acta Amazonica) contra o PDF publicado real mostrou página em altura errada (A4 hardcoded vs. altura real do periódico) e um bug real e independente em _compute_single_column_width/_compute_table_width: ambos assumiam sempre 2 colunas (/2 fixo), o que só quebra visivelmente num periódico calibrado para 1 coluna (Anuário Antropológico) — corrigido nesta tarefa.
Dimensionamento de largura de figura dentro do teto disponível (quando não precisa de largura total) não tem regra geral confirmada — uma hipótese de DPI de metadado não confiável (96/72 como artefato) bateu para um periódico e foi contrariada por outro (Acta Botanica Brasilica, onde o alvo real usa ~2.2x o tamanho nativo confiável). Documentado como limitação conhecida em profiles/1677-941X.json, não resolvido nesta tarefa — indicação de que precisa calibração por figura, não por periódico.
Descrição da tarefa
Hoje o gerador de PDF decide layout (1 ou 2 colunas, largura de tabela/figura) através de duas heurísticas isoladas e desconectadas:
renderer/docx/figure.py::decide_figure_layoutdecide por DPI da imagem.pipeline/xml.py::determine_table_layoutdecide por contagem de coluna (> 4).Nenhuma das duas retorna largura real nem justificativa — só um rótulo de string. A geometria de página (
enum.py::PAGE_ATTRIBUTES) é uma constante fixa em A4/2-colunas, sem possibilidade de configuração por periódico. Isso já causou pelo menos um caso real de infidelidade visual confirmado contra PDF publicado (ver "Considerações").Esta tarefa introduz um "modelo intermediário" de layout —
LayoutConfig— como abstração central e reutilizável que:PageProfile), com fallback para o default atual (A4, 2 colunas) quando o periódico não estiver calibrado.LayoutDecision): largura resolvida + justificativa legível + origem do julgamento (medido/heurística/override) — não só um rótulo.full_width()) para "quebrar pra largura total e restaurar depois", substituindo a lógica de quebra/restauração de seção hoje duplicada entre tabela e figura.profiles/{issn_epub}.json), detectado automaticamente a partir do XML de entrada — sem precisar de flag manual.Subtarefas
PageProfile/LayoutDecision/WidthClass/LayoutConfig(packtools/sps/formats/pdf/layout_config.py)determine_table_layoutconsultaLayoutConfigquando fornecido, mantendo o comportamento atual quando nãodecide_figure_layout/add_figure/_compute_single_column_width(figure.py) idem_compute_table_width(table.py) idempipeline_docxdetecta o ISSN eletrônico do XML e carrega o perfil calibrado automaticamente (load_profile), com fallback ao default quando não calibradopacktools/sps/formats/pdf/profiles/{issn_epub}.json(3 periódicos calibrados por medição contra PDF publicado: Acta Amazonica, Acta Botanica Brasilica, Anuário Antropológico)tests/sps/formats/pdf/test_layout_config.py, mais testes de integração empipeline/test_xml.pye novorenderer/docx/test_figure.py/test_table.py)pdf_generator) — hoje a escolha é sempre automática via perfil, sem override explícito do usuário finalcolumn_min_widths_pt) na decisão de tabela — hojedetermine_table_layoutsempre cai no fallback heurístico (contagem de coluna), porque não há largura por coluna medida disponível nesse ponto do pipelineConsiderações e notas
tests/fixtures/pdf/a1.xml(Acta Amazonica) contra o PDF publicado real mostrou página em altura errada (A4 hardcoded vs. altura real do periódico) e um bug real e independente em_compute_single_column_width/_compute_table_width: ambos assumiam sempre 2 colunas (/2fixo), o que só quebra visivelmente num periódico calibrado para 1 coluna (Anuário Antropológico) — corrigido nesta tarefa.profiles/1677-941X.json, não resolvido nesta tarefa — indicação de que precisa calibração por figura, não por periódico.LayoutConfigalém do escopo desta tarefa, para não duplicar modelagem defig/tablewrap.pdf_generatorCLI, reproduzido durante os testes desta tarefa, não corrigido aqui — fora de escopo).