final stage -- still some bugs

This commit is contained in:
hayano
2024-11-08 04:30:58 +00:00
parent 2aaecb6b22
commit 9eb45d7e97
7 changed files with 743 additions and 82 deletions

View File

@ -31,9 +31,26 @@ import requests
from io import BytesIO
from PIL import Image
import re
from django.http import HttpResponse
import uuid
import unicodedata
import tempfile
import os
import logging
from openpyxl.utils import get_column_letter
from openpyxl.drawing.image import Image as XLImage
from openpyxl.drawing.spreadsheet_drawing import OneCellAnchor, AnchorMarker
from openpyxl.utils.units import pixels_to_EMU
from PIL import Image
import logging
logging.getLogger('PIL').setLevel(logging.WARNING)
logging.getLogger('openpyxl').setLevel(logging.WARNING)
logging.getLogger('PIL.PngImagePlugin').setLevel(logging.WARNING)
logging.getLogger('PIL.TiffImagePlugin').setLevel(logging.WARNING)
logging.basicConfig(
level=logging.INFO, # INFOレベル以上のログを表示
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
@ -76,6 +93,8 @@ class SumasenExcel:
self._page_manager = None
try:
logging.info("step-1")
# document base を設定
self.docpath = docbase
if not os.path.exists(docbase):
@ -94,6 +113,8 @@ class SumasenExcel:
self.basic = basic
logging.info("step-2")
# basicセクションから必要なパラメータを取得
template_file = basic.get("template_file")
if not template_file:
@ -114,6 +135,7 @@ class SumasenExcel:
if not sections:
logging.error("sections not found in basic section")
logging.info("step-3")
# セクションをリストに変換
self.section_list = [s.strip() for s in sections.split(",")]
@ -127,11 +149,15 @@ class SumasenExcel:
# デフォルトで作成されるシートを削除
self.workbook.remove(self.workbook.active)
logging.info("step-4")
# テンプレートワークブックをロード
self.template_filepath = f"{self.docpath}/{template_file}"
if not os.path.exists(self.template_filepath):
logging.error(f"Template file not found: {self.template_filepath}")
logging.info("step-5")
self.template_workbook = openpyxl.load_workbook(self.template_filepath)
self.template_sheet = self.template_workbook.active
@ -275,7 +301,8 @@ class SumasenExcel:
logging.error(f"Error in proceed_group: {str(e)}")
return {"status": False, "message": f"Exception in proceed_group : Error generating report: {str(e)}"}
def format_cell_value(self,field_value, cell):
def format_cell_value(self, field_value, cell):
"""セルの値を適切な形式に変換する
Args:
@ -288,62 +315,133 @@ class SumasenExcel:
# Noneの場合は空文字を返す
if field_value is None:
return ""
# 真偽値の場合
if isinstance(field_value, bool):
return "OK" if field_value else "-"
# 日時型の場合
if isinstance(field_value, datetime):
jst = pytz.timezone('Asia/Tokyo')
# UTC -> JST変換
jst_time = field_value.astimezone(jst)
return jst_time.strftime('%H:%M:%S')
# 文字列の場合、URLかどうかをチェック
# 文字列の場合の処理
if isinstance(field_value, str):
# URL形式かどうかチェック
try:
result = urlparse(field_value)
# URLで、かつ画像ファイルの拡張子を持つ場合
if all([result.scheme, result.netloc]) and \
re.search(r'\.(jpg|jpeg|png|gif|bmp)$', result.path, re.I):
# 画像ファイルパスを取得する関数
def get_image_path(value):
# URLの場合
if value.startswith('https://'):
# URLからファイル名を抽出
filename = os.path.basename(urlparse(value).path)
return os.path.join("/app/media/compressed", filename)
# checkinパスの場合
elif value.startswith('checkin/'):
return os.path.join("/app/media", value)
# ファイル名のみの場合
elif re.search(r'\.(jpg|jpeg|png|gif|bmp|mpo)$', value, re.I):
return os.path.join("/app/media/compressed", value)
return None
# 画像パスを取得
image_path = get_image_path(field_value)
if image_path and os.path.exists(image_path):
try:
# 画像をダウンロード
response = requests.get(field_value)
img = Image.open(BytesIO(response.content))
from PIL import Image
import io
# セルの大きさを取得(ピクセル単位)
cell_width = cell.column_dimensions.width * 6 # 概算のピクセル変換
cell_height = cell.row_dimensions.height
# アスペクト比を保持しながらリサイズ
img_aspect = img.width / img.height
cell_aspect = cell_width / cell_height
if img_aspect > cell_aspect:
width = int(cell_width)
height = int(width / img_aspect)
else:
height = int(cell_height)
width = int(height * img_aspect)
# 画像をリサイズしてセルに追加
img = img.resize((width, height))
# 画像をセルに追加実装方法はExcelライブラリに依存
if hasattr(cell, 'add_image'): # 使用するライブラリによって適切なメソッドを使用
cell.add_image(img)
return "" # 画像を追加したので、テキスト値は空にする
# 画像を開く
with Image.open(image_path) as img:
# RGBAの場合はRGBに変換
if img.mode in ('RGBA', 'LA'):
background = Image.new('RGB', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[-1])
img = background
elif img.mode not in ('RGB', 'L'):
img = img.convert('RGB')
# ワークシートを取得
worksheet = cell.parent
try:
# 列の幅を取得(文字単位からピクセルに変換)
column_letter = get_column_letter(cell.column)
column_width = worksheet.column_dimensions[column_letter].width
cell_width = int((column_width or 8.43) * 7.5) # 8.43は標準の文字幅
except Exception:
cell_width = 100 # デフォルト値
try:
# 行の高さを取得(ポイント単位からピクセルに変換)
row_height = worksheet.row_dimensions[cell.row].height
cell_height = int((row_height or 15) * 1.33) # 15は標準の行の高さ
except Exception:
cell_height = 20 # デフォルト値
# 最小サイズを設定
cell_width = max(cell_width, 100)
cell_height = max(cell_height, 20)
# 最大サイズを設定
max_width = 800
max_height = 600
cell_width = min(cell_width, max_width)
cell_height = min(cell_height, max_height)
# アスペクト比を保持しながらリサイズ
img_width, img_height = img.size
img_aspect = img_width / img_height
cell_aspect = cell_width / cell_height
if img_aspect > cell_aspect:
width = cell_width
height = int(width / img_aspect)
else:
height = cell_height
width = int(height * img_aspect)
# 画像をリサイズ
img_resized = img.resize((width, height), Image.BICUBIC)
# BytesIOオブジェクトを作成して画像を保存
img_byte_arr = io.BytesIO()
img_resized.save(img_byte_arr, format='JPEG', quality=85, optimize=True)
img_byte_arr.seek(0)
# OpenPyXLのImageオブジェクトを作成
from openpyxl.drawing.image import Image as XLImage
excel_image = XLImage(img_byte_arr)
# 画像の配置
excel_image.anchor = f"{column_letter}{cell.row}"
# 画像をワークシートに追加
worksheet.add_image(excel_image)
return ""
except Exception as e:
logging.warning(f"画像の処理に失敗: {str(e)}")
return field_value # エラーの場合はURLをそのまま返す
logging.error(f"画像の処理に失敗: {str(e)}, image_path={image_path}")
import traceback
logging.error(traceback.format_exc())
return field_value
else:
if image_path:
logging.warning(f"画像ファイルが存在しません: {image_path}")
return field_value
except Exception as e:
logging.warning(f"形式変換の処理に失敗: {str(e)}")
return field_value # エラーの場合はURLをそのまま返す
logging.error(f"形式変換の処理に失敗: {str(e)}")
import traceback
logging.error(traceback.format_exc())
return field_value
# その他の場合は文字列に変換
return str(field_value)