final stage -- still some bugs
This commit is contained in:
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user