Fix PDF issue

This commit is contained in:
hayano
2024-11-09 09:50:58 +00:00
parent 27aed10a4a
commit 2ca77b604b
6 changed files with 300 additions and 101 deletions

View File

@ -1,5 +1,5 @@
import os
from aiohttp import ClientError
from botocore.exceptions import ClientError
from django.template.loader import render_to_string
from django.conf import settings
import logging
@ -193,12 +193,12 @@ class S3Bucket:
s3_key = os.path.basename(file_path)
# S3クライアントが指定されていない場合は新規作成
if s3_client is None:
s3_client = self.connect()
if self.s3_client is None:
self.s3_client = self.connect()
# ファイルのアップロード
logger.info(f"アップロード開始: {file_path} → s3://{self.bucket_name}/{s3_key}")
s3_client.upload_file(file_path, self.bucket_name, s3_key)
self.s3_client.upload_file(file_path, self.bucket_name, s3_key)
logger.info("アップロード完了")
return True
@ -313,11 +313,11 @@ class S3Bucket:
try:
# S3クライアントが指定されていない場合は新規作成
if s3_client is None:
s3_client = self.connect()
if self.s3_client is None:
self.s3_client = self.connect()
# プレフィックスに一致するオブジェクトをリスト
paginator = s3_client.get_paginator('list_objects_v2')
paginator = self.s3_client.get_paginator('list_objects_v2')
pages = paginator.paginate(Bucket=self.bucket_name, Prefix=prefix)
for page in pages:
@ -361,12 +361,12 @@ class S3Bucket:
try:
# S3クライアントが指定されていない場合は新規作成
if s3_client is None:
s3_client = self.connect()
if self.s3_client is None:
self.s3_client = self.connect()
# オブジェクトの削除
logger.info(f"削除開始: s3://{self.bucket_name}/{s3_key}")
s3_client.delete_object(Bucket=self.bucket_name, Key=s3_key)
self.s3_client.delete_object(Bucket=self.bucket_name, Key=s3_key)
logger.info("削除完了")
return True

View File

@ -2764,14 +2764,111 @@ def export_excel(request, zekken_number, event_code):
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
# 一時ディレクトリを作成ASCII文字のみのパスを使用
temp_dir = tempfile.mkdtemp(prefix='lo-')
logger.debug(f"Created temp directory: {temp_dir}")
# ASCII文字のみの作業ディレクトリを作成
work_dir = os.path.join(temp_dir, 'work')
output_dir = os.path.join(temp_dir, 'output')
os.makedirs(work_dir, exist_ok=True)
os.makedirs(output_dir, exist_ok=True)
# すべてのディレクトリに適切な権限を設定
for directory in [temp_dir, work_dir, output_dir]:
os.chmod(directory, 0o777)
logger.debug(f"Set permissions for directory: {directory}")
# ASCII文字のみの一時ファイル名を使用
temp_excel_name = f"certificate_{zekken_number}.xlsx"
temp_excel_path = os.path.join(work_dir, temp_excel_name)
# 元のExcelファイルを作業ディレクトリにコピー
shutil.copy2(excel_path, temp_excel_path)
os.chmod(temp_excel_path, 0o666)
logger.debug(f"Copied Excel file to: {temp_excel_path}")
# LibreOffice設定ディレクトリを作成
libreoffice_config_dir = os.path.join(temp_dir, 'libreoffice')
os.makedirs(libreoffice_config_dir, exist_ok=True)
# フォント設定ディレクトリを作成
font_conf_dir = os.path.join(temp_dir, 'fonts')
os.makedirs(font_conf_dir, exist_ok=True)
# フォント設定ファイルを作成
fonts_conf_content = '''<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<dir>/usr/share/fonts</dir>
<match target="pattern">
<test qual="any" name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="assign" binding="same">
<string>IPAexGothic</string>
</edit>
</match>
<match target="pattern">
<test qual="any" name="family">
<string>serif</string>
</test>
<edit name="family" mode="assign" binding="same">
<string>IPAexMincho</string>
</edit>
</match>
</fontconfig>'''
font_conf_path = os.path.join(libreoffice_config_dir, 'fonts.conf')
with open(font_conf_path, 'w') as f:
f.write(fonts_conf_content)
# LibreOfficeのフォント設定を作成
registry_dir = os.path.join(libreoffice_config_dir, 'registry')
os.makedirs(registry_dir, exist_ok=True)
# フォント埋め込み設定を作成
pdf_export_config = '''<?xml version="1.0" encoding="UTF-8"?>
<oor:data xmlns:oor="http://openoffice.org/2001/registry">
<oor:component-data oor:package="org.openoffice.Office.Common" oor:name="Filter">
<node oor:name="PDF">
<prop oor:name="EmbedFonts" oor:op="fuse">
<value>true</value>
</prop>
<prop oor:name="ExportFormFields" oor:op="fuse">
<value>true</value>
</prop>
<prop oor:name="UseTaggedPDF" oor:op="fuse">
<value>true</value>
</prop>
</node>
</oor:component-data>
</oor:data>'''
pdf_config_path = os.path.join(registry_dir, 'pdf_export.xcu')
with open(pdf_config_path, 'w') as f:
f.write(pdf_export_config)
# すべてのディレクトリに適切な権限を設定
for directory in [temp_dir, work_dir, output_dir,registry_dir]:
os.chmod(directory, 0o777)
logger.debug(f"Set permissions for directory: {directory}")
os.chmod(temp_excel_path, 0o666)
os.chmod(font_conf_path, 0o666)
os.chmod(pdf_config_path, 0o666)
# フォーマット指定excel or pdf
format_type = request.query_params.get('format', 'pdf')
if format_type.lower() == 'pdf':
try:
# パスとファイル名に分離
file_dir = os.path.dirname(excel_path) # パス部分の取得
file_name = os.path.basename(excel_path) # ファイル名部分の取得
file_dir = os.path.dirname(temp_excel_path) # パス部分の取得
file_name = os.path.basename(temp_excel_path) # ファイル名部分の取得
# ファイル名の拡張子をpdfに変更
base_name = os.path.splitext(file_name)[0] # 拡張子を除いたファイル名
@ -2786,11 +2883,10 @@ def export_excel(request, zekken_number, event_code):
conversion_command = [
'soffice', # LibreOfficeの代替コマンド
'--headless',
'--convert-to',
'pdf',
'--outdir',
file_dir,
excel_path
'--convert-to', 'pdf:writer_pdf_Export',
'--outdir',file_dir,
'-env:UserInstallation=file://' + libreoffice_config_dir,
temp_excel_path
]
logger.debug(f"Running conversion command: {' '.join(conversion_command)}")
@ -2798,6 +2894,11 @@ def export_excel(request, zekken_number, event_code):
# 環境変数を設定
env = os.environ.copy()
#env['HOME'] = temp_dir # LibreOfficeの設定ディレクトリを一時ディレクトリに設定
env['HOME'] = temp_dir
env['LANG'] = 'ja_JP.UTF-8' # 日本語環境を設定
env['LC_ALL'] = 'ja_JP.UTF-8'
env['FONTCONFIG_FILE'] = font_conf_path
env['FONTCONFIG_PATH'] = font_conf_dir
# 変換プロセスを実行
process = subprocess.run(
@ -2805,7 +2906,9 @@ def export_excel(request, zekken_number, event_code):
env=env,
capture_output=True,
text=True,
check=True
cwd=work_dir,
check=True,
timeout=30
)
logger.debug(f"Conversion output: {process.stdout}")
@ -2819,9 +2922,10 @@ def export_excel(request, zekken_number, event_code):
)
s3 = S3Bucket('sumasenrogaining')
s3.upload_file(pdf_path, f'{event_code}/scoreboard', f'certificate_{zekken_number}.pdf')
s3.upload_file(excel_path, f'{event_code}/scoreboard_excel', f'certificate_{zekken_number}.xlsx')
s3.upload_file(pdf_path, f'{event_code}/scoreboard/certificate_{zekken_number}.pdf')
s3.upload_file(excel_path, f'{event_code}/scoreboard_excel/certificate_{zekken_number}.xlsx')
os.remove(temp_excel_path)
os.remove(excel_path)
os.remove(pdf_path)
@ -2833,7 +2937,7 @@ def export_excel(request, zekken_number, event_code):
return Response(
{"error": f"PDF conversion failed: {str(e)}"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
)
finally:
# 一時ディレクトリの削除
if temp_dir and os.path.exists(temp_dir):