fix: permite corpo do artigo começar na página 1 quando há espaço - #1296
fix: permite corpo do artigo começar na página 1 quando há espaço#1296Rossi-Luciano wants to merge 1 commit into
Conversation
get_or_create_second_section criava a seção do corpo (2 colunas) com
docx.add_section() sem argumento - que no python-docx tem como padrão
WD_SECTION.NEW_PAGE, uma quebra de página forçada e incondicional. Isso
significa que o corpo do artigo (Introdução em diante) nunca podia começar
na página 1, mesmo quando o rosto (título/autores/resumo/palavras-chave)
era curto o bastante para sobrar espaço - a página 1 ficava com um vazio
entre o fim do resumo e o rodapé "CITE AS".
Reproduzido nos 4 fixtures reais de tests/fixtures/pdf/ (a1-a4). Comparando
com os PDFs canônicos (ground_truth), pelo menos parte deles preenche a
página 1 com o início do corpo quando cabe.
Trocar a quebra para WD_SECTION.CONTINUOUS resolve o vazio, mas quebra o
cabeçalho corrente ("ECONOMIA E SOCIEDADE" + título do artigo) em todas as
páginas a partir da 2ª - confirmado com um teste mínimo isolado (só
python-docx + LibreOffice, sem código do packtools): um cabeçalho definido
numa seção contínua e desvinculada da anterior (is_linked_to_previous =
False) simplesmente não é renderizado pelo LibreOffice na conversão pra
PDF. É uma limitação real do LibreOffice, não bug do packtools.
Corrigido escrevendo o cabeçalho corrente no header padrão da própria
seção 0 (get_default_header, distinto do first_page_header que guarda o
rosto) em vez de numa seção 2 separada e desvinculada - a seção do corpo
fica vinculada (herda o cabeçalho) em vez de redefini-lo, o que renderiza
corretamente no LibreOffice mesmo através de uma quebra contínua. Também
removido o unlink forçado da seção de índice 1 em
_apply_header_footer_linking, que reintroduzia o mesmo problema no fim do
pipeline.
get_or_create_second_section agora aceita page_attributes e lê start_type
de lá (default continua CONTINUOUS) - o comportamento novo já nasce
configurável, em vez de ficar hardcoded e precisar ser retrabalhado depois
quando a configuração de layout por JSON (issue scieloorg#1278) for implementada.
Atualizado também o valor default de PAGE_ATTRIBUTES['start_type'] em
enum.py, que já existia como campo mas nunca era lido em lugar nenhum e
ainda apontava pro comportamento antigo (NEW_PAGE).
Validado ponta a ponta nos 4 fixtures: página 1 aproveitada, cabeçalho e
rodapé corretos em todas as páginas (checado explicitamente na 2ª e na
última página de cada um). Saída idêntica à versão anterior deste commit
(antes de parametrizar) confirmada por diff de texto.
Refs scieloorg#1278.
| current_page_number = 1 | ||
|
|
||
| second_section = docx_renderer.section.get_or_create_second_section(docx) | ||
| docx_renderer.section.set_start_page_number(second_section, current_page_number) |
There was a problem hiding this comment.
Esse reinício aplicado somente à segunda seção não é respeitado como esperado pelo LibreOffice quando a seção é contínua. Nos fixtures, a página 2 passa a exibir o número físico (2), inclusive no A1, onde deveria exibir 272.
Testei aplicar a numeração à primeira seção, mas, se as demais seções tiverem configuração diferente, o LibreOffice promove a quebra contínua para uma nova página. Uma solução que preservou simultaneamente o corpo na página 1 e a numeração correta foi, depois de docx_setup_sections, aplicar o mesmo w:pgNumType a todas as seções: usar fpage como início ou 0 quando ele estiver ausente. Assim, obtive A1 271 --> 272 e A2–A4 com página 2 igual a 1, sem reintroduzir a página em branco.
Sugiro também retirar essa responsabilidade de docx_second_footer_pipe, deixando essa função apenas montar o rodapé, e configurar a numeração globalmente após todas as seções terem sido criadas.
pitangainnovare
left a comment
There was a problem hiding this comment.
A mudança para uma seção contínua resolve o espaço em branco e permite que o corpo comece na primeira página, mas introduz uma regressão bloqueante na numeração. Na conversão com LibreOffice, o reinício configurado apenas na segunda seção não é respeitado como esperado: no A1, por exemplo, a página 2 passa a exibir 2, quando deveria exibir 272. A2–A4 também exibem 2, quando o esperado é 1.
Testei algumas alternativas localmente. Configurar somente a primeira seção corrige os números, mas faz o LibreOffice promover a quebra contínua para uma nova página, eliminando o benefício principal deste PR. A solução que preservou os dois comportamentos foi aplicar o mesmo início de numeração a todas as seções, depois que elas já estiverem criadas:
docx_renderer.section.docx_setup_sections(docx)
try:
start_page_number = int(footer_data["fpage"])
except ValueError:
start_page_number = 0
for section in docx.sections:
docx_renderer.section.set_start_page_number(
section,
start_page_number,
)O início deve ser fpage, e não fpage + 1, porque o campo PAGE avança naturalmente nas páginas seguintes. Quando fpage estiver ausente, iniciar em 0 faz a segunda página ser numerada como 1.
Com essa configuração uniforme, obtive:
- A1: página 1 =
271, página 2 =272, mantendo 13 páginas; - A2: página 2 =
1, última página =8; - A3 e A4: página 2 =
1, última página =7; - corpo permanecendo na primeira página e cabeçalho corrido preservado.
Sugiro também retirar a configuração da numeração de docx_second_footer_pipe. Essa função pode ficar responsável apenas pela composição do rodapé, enquanto a numeração global é aplicada no final de pipeline_docx, depois de docx_setup_sections.
Por fim, seria importante acrescentar uma validação que proteja conjuntamente os dois resultados após a conversão pelo LibreOffice: o corpo deve começar na página 1 e a página 2 deve apresentar o número editorial correto. Os testes estruturais atuais passam mesmo quando o PDF renderizado contém a numeração incorreta.
O que esse PR faz?
Problema existente: a transição do rosto do artigo (título/autores/resumo/palavras-chave, 1 coluna) para o corpo (Introdução em diante, 2 colunas) usa
docx.add_section()sem argumento — que no python-docx tem como padrãoWD_SECTION.NEW_PAGE, uma quebra de página forçada e incondicional. O corpo do artigo nunca pode começar na página 1, mesmo quando o rosto é curto o bastante para sobrar espaço — a página 1 fica com um vazio entre o fim do resumo e o rodapé "CITE AS" (issue #1295).Solução proposta: trocar a quebra de
WD_SECTION.NEW_PAGEporWD_SECTION.CONTINUOUS, deixando o corpo fluir para a página 1 quando houver espaço. Essa troca isolada quebrou o cabeçalho corrente ("nome do periódico" + título do artigo) em todas as páginas a partir da 2ª — confirmado com um teste mínimo isolado (sópython-docx+ LibreOffice, sem código do packtools) que uma seção contínua e desvinculada da anterior (is_linked_to_previous = False) não tem seu cabeçalho renderizado pelo LibreOffice na conversão pra PDF. Corrigido escrevendo o cabeçalho corrente no header padrão da própria primeira seção (distinto dofirst_page_header, que guarda só o rosto da capa) em vez de numa seção separada e desvinculada — a seção do corpo passa a herdar esse cabeçalho em vez de redefini-lo.get_or_create_second_sectionjá nasce parametrizável (page_attributes['start_type'], defaultCONTINUOUS) em vez de deixar o novo comportamento hardcoded — evita ter que mexer na mesma função de novo quando a configuração de layout por JSON (issue #1278) for implementada.Resultado: a página 1 passa a aproveitar o espaço disponível, com o corpo do artigo começando ali quando o rosto permite — sem quebrar cabeçalho nem rodapé em nenhuma página. Quem precisar da convenção antiga (rosto sempre isolado na página 1) pode obter isso hoje passando
page_attributescomstart_type: WD_SECTION.NEW_PAGEdiretamente na API Python — a exposição via CLI/JSON fica pra uma etapa seguinte.Onde a revisão poderia começar?
packtools/sps/formats/pdf/renderer/docx/section.py, funçõesget_or_create_second_sectioneget_default_header(nova). Depoispacktools/sps/formats/pdf/pipeline/docx.py::docx_second_header_pipe.Como este poderia ser testado manualmente?
Comparar a página 1 antes/depois (imagens anexadas) — e confirmar que o cabeçalho ("ECONOMIA E SOCIEDADE" + título) continua aparecendo normalmente da página 2 em diante.
Testes automatizados:
python -m unittest discover -s tests/sps/formats/pdf -v.Algum cenário de contexto que queira dar?
Encontrado durante um levantamento mais amplo de qualidade do gerador de PDF contra um corpus de artigos reais (
tests/fixtures/pdf/), comparando a saída atual contra os PDFs editoriais canônicos (*.gt.pdf). Faz parte do escopo da issue #1278 (layout de página/coluna configurável).Screenshots
Quais são os tickets relevantes?
Refs #1278. Closes #1295.
Referências
N/A
Segurança da informação (NSI.04)
Este PR manipula dados sensíveis ou pessoais (LGPD)?
Este PR altera autenticação, autorização, controle de acesso ou gerenciamento de sessão?
Este PR introduz, atualiza ou remove dependências de terceiros?
Este PR foi validado pelo pipeline de segurança (SonarQube / Trivy)?
SECURITY_ADHERENCE.md. Os gates automáticos reais deste repositório (Snyk e GitGuardian) rodam via CI neste PR.Este PR concatena, monta ou executa comandos SQL, HTML ou JavaScript a partir de entrada externa?
Este PR expõe novos endpoints, telas ou serviços?
Algum segredo, senha, chave ou token está sendo adicionado ao código-fonte?