From 3507d17dc59d16a8e15b382b769a1e3e414c4930 Mon Sep 17 00:00:00 2001 From: thug0bin Date: Sun, 8 Mar 2026 13:57:32 +0900 Subject: [PATCH] =?UTF-8?q?fix(upload):=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20QR?= =?UTF-8?q?=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PIL 이미지 처리 추가 (product-images API와 동일) - 800x800 리사이즈 - 200x200 썸네일 생성 - RGBA->RGB 변환 - 1:1 중앙 크롭 --- backend/app.py | 67 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/backend/app.py b/backend/app.py index 4f60f12..4f0cb41 100644 --- a/backend/app.py +++ b/backend/app.py @@ -7682,21 +7682,62 @@ def api_upload_session_image(session_id): return jsonify({'success': False, 'error': '세션이 만료되었습니다'}), 404 # 이미지 데이터 받기 + import base64 + from PIL import Image + from io import BytesIO + if 'image' not in request.files: # base64로 받은 경우 data = request.get_json() or {} - image_base64 = data.get('image_base64') - if not image_base64: + image_data_raw = data.get('image_base64') + if not image_data_raw: return jsonify({'success': False, 'error': '이미지가 필요합니다'}), 400 else: # 파일로 받은 경우 - import base64 file = request.files['image'] - image_data = file.read() - image_base64 = base64.b64encode(image_data).decode('utf-8') + image_data_raw = base64.b64encode(file.read()).decode('utf-8') - # product_images.db에 저장 barcode = session['barcode'] + product_name = session.get('product_name', barcode) + + try: + # base64 디코딩 & PIL 이미지 처리 + image_bytes = base64.b64decode(image_data_raw) + img = Image.open(BytesIO(image_bytes)) + + # RGBA -> RGB 변환 + if img.mode == 'RGBA': + bg = Image.new('RGB', img.size, (255, 255, 255)) + bg.paste(img, mask=img.split()[3]) + img = bg + elif img.mode != 'RGB': + img = img.convert('RGB') + + # 1:1 중앙 크롭 + width, height = img.size + min_dim = min(width, height) + left = (width - min_dim) // 2 + top = (height - min_dim) // 2 + img = img.crop((left, top, left + min_dim, top + min_dim)) + + # 800x800 리사이즈 + img = img.resize((800, 800), Image.LANCZOS) + + # base64 변환 (원본) + buffer = BytesIO() + img.save(buffer, format='JPEG', quality=90) + image_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8') + + # 썸네일 생성 (200x200) + thumb_img = img.resize((200, 200), Image.LANCZOS) + thumb_buffer = BytesIO() + thumb_img.save(thumb_buffer, format='JPEG', quality=85) + thumbnail_base64 = base64.b64encode(thumb_buffer.getvalue()).decode('utf-8') + + except Exception as e: + return jsonify({'success': False, 'error': f'이미지 처리 실패: {str(e)}'}), 400 + + # SQLite 저장 try: img_db_path = Path(__file__).parent / 'db' / 'product_images.db' conn = sqlite3.connect(str(img_db_path)) @@ -7706,26 +7747,24 @@ def api_upload_session_image(session_id): cursor.execute('SELECT id FROM product_images WHERE barcode = ?', (barcode,)) existing = cursor.fetchone() - product_name = session.get('product_name', barcode) # 세션에서 가져오거나 바코드 사용 - if existing: cursor.execute(''' UPDATE product_images - SET image_base64 = ?, updated_at = CURRENT_TIMESTAMP + SET image_base64 = ?, thumbnail_base64 = ?, status = 'manual', updated_at = datetime('now') WHERE barcode = ? - ''', (image_base64, barcode)) + ''', (image_base64, thumbnail_base64, barcode)) else: cursor.execute(''' - INSERT INTO product_images (barcode, product_name, image_base64, status, created_at) - VALUES (?, ?, ?, 'manual', CURRENT_TIMESTAMP) - ''', (barcode, product_name, image_base64)) + INSERT INTO product_images (barcode, product_name, image_base64, thumbnail_base64, status) + VALUES (?, ?, ?, ?, 'manual') + ''', (barcode, product_name, image_base64, thumbnail_base64)) conn.commit() conn.close() # 세션 상태 업데이트 session['status'] = 'uploaded' - session['image_base64'] = image_base64 + session['image_base64'] = thumbnail_base64 # 폴링용으로 썸네일 사용 return jsonify({'success': True, 'message': '이미지가 저장되었습니다'})