import gradio as gr import tempfile from pdf2image import convert_from_path import fitz # PyMuPDF import cv2 import numpy as np # ========== 解析ロジック関数 ========== def estimate_blurriness(pil_image): """ ぼけ度を推定(Laplacian分散) 値が小さいほどぼけている """ gray = np.array(pil_image.convert('L')) return cv2.Laplacian(gray, cv2.CV_64F).var() def estimate_contrast(pil_image): """ コントラストを推定(標準偏差) 値が小さいほどグレーでのっぺり """ gray = np.array(pil_image.convert('L')) return gray.std() def analyze_pdf(pdf_file): """ アップロードされたPDFの各ページを画像に変換し - 画像サイズ - 総ピクセル数 - ぼけ度 - コントラスト - 推定DPI などをもとにAudiverisでの利用適性を判定 """ MAX_PIXELS_AUDIVERIS = 20_000_000 results = [] overall_rating = "OK" try: with tempfile.TemporaryDirectory() as tmpdir: # PDF → 画像変換 images = convert_from_path(pdf_file.name, dpi=300, output_folder=tmpdir) doc = fitz.open(pdf_file.name) dpi_infos = [] for i, (img, page) in enumerate(zip(images, doc)): width, height = img.size total_pixels = width * height reasons = [] page_rating = "OK" # Audiverisのピクセル上限チェック if total_pixels > MAX_PIXELS_AUDIVERIS: page_rating = "非推奨(画像が大きすぎる)" reasons.append(f"総ピクセル数 {total_pixels:,} > 20,000,000") # 解像度チェック if width < 1000 or height < 1000 and "非推奨" not in page_rating: page_rating = "非推奨(解像度が小さい)" reasons.append("幅または高さが1000px未満") elif width < 1500 or height < 1500 and page_rating == "OK": page_rating = "注意(やや低め)" # ぼけ度チェック blur_score = estimate_blurriness(img) if blur_score < 30 and "非推奨" not in page_rating: page_rating = "非推奨(ぼけている)" reasons.append(f"ぼけ度={blur_score:.1f}") # コントラストチェック contrast_score = estimate_contrast(img) if contrast_score < 30 and "非推奨" not in page_rating: page_rating = "非推奨(コントラストが低い)" reasons.append(f"コントラスト={contrast_score:.1f}") # DPI情報 rect = page.rect width_pt = rect.width height_pt = rect.height dpi_x = width / (width_pt / 72) dpi_y = height / (height_pt / 72) dpi_infos.append(f"ページ{i+1}推定DPI: {dpi_x:.1f}x{dpi_y:.1f}") # 理由をまとめる reasons_str = "; ".join(reasons) if reasons else "条件クリア" # ページ結果 results.append( f"ページ{i+1}: {width}x{height}px / ピクセル数={total_pixels:,} / " f"ぼけ度={blur_score:.1f} / コントラスト={contrast_score:.1f} → {page_rating} ({reasons_str})" ) # 総合評価を更新 if "非推奨" in page_rating: overall_rating = "非推奨" elif "注意" in page_rating and overall_rating == "OK": overall_rating = "注意" # まとめテキスト result_text = "\n".join(results + [""] + dpi_infos) result_text += f"\n\n総合評価: {overall_rating}" # 改善提案 if overall_rating == "非推奨": result_text += "\n\n推奨対策: スキャン解像度を下げる・画像を縮小するなどして、ファイルサイズや画質を調整してください。" return result_text, overall_rating except Exception as e: return f"処理中にエラーが発生しました: {str(e)}", "エラー" # ========== Gradio UI部分 ========== with gr.Blocks() as demo: gr.Markdown("# 🎼 Audiveris適性チェック(非公式・推定)") gr.Markdown( """ PDFをアップロードすると、ページごとの画像サイズ、ピクセル数、ぼけ度、コントラストを分析し、 Audiverisで使用可能かを「OK / 注意 / 非推奨」で推定します。 """ ) with gr.Row(): pdf_input = gr.File(label="PDFファイル") analyze_button = gr.Button("判定") result_output = gr.Textbox(label="詳細結果", lines=20) rating_output = gr.Textbox(label="総合評価") analyze_button.click(analyze_pdf, inputs=pdf_input, outputs=[result_output, rating_output]) if __name__ == "__main__": demo.launch()