feat(535-2): B09 도면 PDF PyMuPDF(AGPL) 제거 — 장마다 SVG 쪽 → 공용 PDF 엔진(Chromium) · pypdf 합치기
- 점선 = 미리 자른 실선 조각(Chromium 이 점선을 채운 윤곽으로 풀어 PDF 3 배 커지는 것 막음) - 글 안 빈칸 그대로(white-space: pre) · 세운 글 방향 = 화면(openwebcad canvas)과 같게 - 못 넣은 그림 = data: 아님 · base64 깨짐 - test_302_2: PDF 읽기 pymupdf → pypdf · add_drawing_page(pymupdf 문서) 시험 → drawing_page(SVG) 로 고침 · 점선 조각 · 빈칸 시험 더함 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,18 +1,20 @@
|
||||
"""PLAN 302-2 인쇄 미리보기 도면 PDF — 목록 차례 · 쪽 수 · 쪽 크기 · 한글 · 숨긴 층 · 권한.
|
||||
"""PLAN 302-2 · 535-2 인쇄 미리보기 도면 PDF — 목록 차례 · 쪽 수 · 쪽 크기 · 한글 · 숨긴 층 · 권한 ·
|
||||
점선 조각 · 그림 · 빈칸 그대로(PDF 읽기 = pypdf).
|
||||
|
||||
임시 폴더 견본만 씀(공용 storage 안 씀) — B07 목록 · 단건 · 표제란 값은 바꿔 끼움.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import json
|
||||
from pathlib import Path
|
||||
from uuid import uuid4
|
||||
|
||||
import pymupdf
|
||||
import pytest
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from pypdf import PdfReader
|
||||
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Template import (
|
||||
frame_entities,
|
||||
@@ -24,7 +26,8 @@ from B09_Estimation.draft import B09_Draft_Print_Drawings_Router as router_modul
|
||||
from B09_Estimation.draft import B09_Draft_Print_Drawings_Source as source
|
||||
from B09_Estimation.draft.B09_Draft_Print_Drawings_Pdf import (
|
||||
PT_PER_MM,
|
||||
add_drawing_page,
|
||||
dash_pieces,
|
||||
drawing_page,
|
||||
paint_color,
|
||||
)
|
||||
from common_util import common_util_auth as auth
|
||||
@@ -170,18 +173,21 @@ def test_PDF_쪽수_크기_한글_숨긴층(sample):
|
||||
assert response.headers["content-type"] == "application/pdf"
|
||||
assert response.headers["x-aislo-pages"] == "5"
|
||||
assert json.loads(response.headers["x-aislo-skipped-images"]) == {}
|
||||
doc = pymupdf.open(stream=response.content, filetype="pdf")
|
||||
assert doc.page_count == 5
|
||||
for page in doc:
|
||||
assert abs(page.rect.width / PT_PER_MM - 840) < 0.5
|
||||
assert abs(page.rect.height / PT_PER_MM - 594) < 0.5
|
||||
first = doc[0].get_text()
|
||||
if response.status_code == 503:
|
||||
pytest.skip(response.json()["message"]) # 서버에 Edge · Chrome 없음
|
||||
pages = PdfReader(io.BytesIO(response.content)).pages
|
||||
assert len(pages) == 5
|
||||
for page in pages:
|
||||
assert abs(float(page.mediabox.width) / PT_PER_MM - 840) < 0.5
|
||||
assert abs(float(page.mediabox.height) / PT_PER_MM - 594) < 0.5
|
||||
texts = [page.extract_text() for page in pages]
|
||||
first = texts[0]
|
||||
assert "가나다임도개설공사" in first and "라마바설계" in first # 표제란 한글 그대로
|
||||
assert "보이는글" in first
|
||||
assert "숨은글" not in first and "얼린글" not in first
|
||||
# 구조물 장 = 얹은 도각 + 장 도번 · 표제란 = 프로젝트 값
|
||||
assert "구조물그림" in doc[2].get_text() and "SD-000001" in doc[2].get_text()
|
||||
assert "SD-000002-2" in doc[4].get_text() and "가나다임도개설공사" in doc[4].get_text()
|
||||
assert "구조물그림" in texts[2] and "SD-000001" in texts[2]
|
||||
assert "SD-000002-2" in texts[4] and "가나다임도개설공사" in texts[4]
|
||||
|
||||
|
||||
def test_PDF_고른_차례_모르는_id(sample):
|
||||
@@ -189,8 +195,10 @@ def test_PDF_고른_차례_모르는_id(sample):
|
||||
client = _client(SESSION)
|
||||
picked = ["structure:SD-000001", "b07:cover"]
|
||||
response = client.post(f"/api/projects/{pid}/print/drawings-pdf", json={"ids": picked})
|
||||
doc = pymupdf.open(stream=response.content, filetype="pdf")
|
||||
assert doc.page_count == 2 and "구조물그림" in doc[0].get_text()
|
||||
if response.status_code == 503:
|
||||
pytest.skip(response.json()["message"])
|
||||
pages = PdfReader(io.BytesIO(response.content)).pages
|
||||
assert len(pages) == 2 and "구조물그림" in pages[0].extract_text()
|
||||
bad = client.post(f"/api/projects/{pid}/print/drawings-pdf", json={"ids": ["b07:없음"]})
|
||||
assert bad.status_code == 400
|
||||
|
||||
@@ -244,9 +252,14 @@ def test_로그인_회사_권한(sample, monkeypatch):
|
||||
assert _client(SESSION, project_company=1).get(path).status_code == 200
|
||||
|
||||
|
||||
#: 1×1 PNG
|
||||
PNG = (
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAE"
|
||||
"hQGAhKmMIQAAAABJRU5ErkJggg=="
|
||||
)
|
||||
|
||||
|
||||
def test_그림_넣기_못_넣은_수():
|
||||
png = pymupdf.Pixmap(pymupdf.csRGB, pymupdf.IRect(0, 0, 4, 4), 0).tobytes("png")
|
||||
import base64
|
||||
|
||||
def image(data: str) -> dict:
|
||||
points = [{"x": 10, "y": 10}, {"x": 50, "y": 10}, {"x": 50, "y": 50}, {"x": 10, "y": 50}]
|
||||
@@ -254,14 +267,31 @@ def test_그림_넣기_못_넣은_수():
|
||||
|
||||
drawing = {
|
||||
"entities": [
|
||||
image("data:image/png;base64," + base64.b64encode(png).decode()),
|
||||
image("data:image/png;base64," + PNG),
|
||||
image("/api/assets/없는그림.png"),
|
||||
image("data:image/png;base64,@@깨진@@"),
|
||||
],
|
||||
"layers": [],
|
||||
}
|
||||
doc = pymupdf.open()
|
||||
paper, skipped = add_drawing_page(doc, drawing)
|
||||
assert skipped == 1 and len(doc[0].get_images()) == 1
|
||||
page, size, paper, skipped = drawing_page(drawing)
|
||||
assert skipped == 2 and page.count("<image ") == 1
|
||||
|
||||
|
||||
def test_점선_조각_빈칸_그대로():
|
||||
"""점선 = 미리 자른 실선 조각(Chromium 이 윤곽으로 안 풂) · 무늬 = 꺾은선 처음부터 이어 셈."""
|
||||
pieces = dash_pieces([(0, 0), (10, 0), (10, 10)], (6, 3))
|
||||
assert pieces == [
|
||||
[(0, 0), (6.0, 0.0)],
|
||||
[(9.0, 0.0), (10, 0), (10.0, 5.0)],
|
||||
[(10.0, 8.0), (10, 10)],
|
||||
]
|
||||
assert dash_pieces([(0, 0), (1, 0)], (0, 0)) == [[(0, 0), (1, 0)]] # 무늬 없음 = 실선
|
||||
line = {"type": "Line", "layerId": "a", "lineDash": [6, 3]}
|
||||
line["shapeData"] = {"startPoint": {"x": 0, "y": 0}, "endPoint": {"x": 100, "y": 0}}
|
||||
text = _text("축 척", 50, 50, "a")
|
||||
page, size, paper, _ = drawing_page({"entities": [line, text], "layers": []})
|
||||
assert "stroke-dasharray" not in page and page.count("M") > 5
|
||||
assert "축 척" in page and "white-space: pre" in page
|
||||
|
||||
|
||||
def test_미확정_횡단_구조물_Node_번들이_돎():
|
||||
|
||||
Reference in New Issue
Block a user