본문 바로가기

PY(Python Image Processing)

python web app puzzle game ( crop image, flask, pillow )

728x90

[directory]

 

puzzle_game/

├── app.py                          # 메인 파이썬 애플리케이션 파일
├── static/                         # 정적 파일을 저장하는 디렉토리
│   ├── uploads/                    # 업로드된 이미지를 저장하는 디렉토리
│   └── puzzle/                     # 퍼즐 조각 이미지를 저장하는 디렉토리

└── templates/                      # HTML 템플릿 파일을 저장하는 디렉토리
    ├── upload.html                 # 이미지 업로드 폼 페이지
    └── puzzle.html                 # 퍼즐 게임 페이지

 

 

[requirements.txt]

Flask==2.3.3
Pillow==9.2.0

 

[app.py]

from flask import Flask, render_template, request, redirect, url_for, send_file
from PIL import Image
import os
import random

app = Flask(__name__)

UPLOAD_FOLDER = 'static/uploads/'
PUZZLE_FOLDER = 'static/puzzle/'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['PUZZLE_FOLDER'] = PUZZLE_FOLDER

if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)

if not os.path.exists(PUZZLE_FOLDER):
    os.makedirs(PUZZLE_FOLDER)

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # 파일 업로드 처리
        if 'file' not in request.files or 'grid_size' not in request.form:
            return redirect(request.url)
       
        file = request.files['file']
        grid_size = int(request.form['grid_size'])  # 사용자가 입력한 그리드 크기
        if file.filename == '' or grid_size <= 0:
            return redirect(request.url)
       
        if file:
            filename = file.filename
            filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            file.save(filepath)
           
            # 이미지 자르기
            image = Image.open(filepath)
            image = image.resize((400, 400))  # 400x400으로 리사이즈
            pieces = []
            piece_size = 400 // grid_size  # 조각 크기 계산
            for i in range(0, 400, piece_size):
                for j in range(0, 400, piece_size):
                    piece = image.crop((j, i, j + piece_size, i + piece_size))
                    piece_path = os.path.join(app.config['PUZZLE_FOLDER'], f'piece_{i}_{j}.png')
                    piece.save(piece_path)
                    pieces.append(f'piece_{i}_{j}.png')
           
            random.shuffle(pieces)  # 퍼즐 조각 섞기
           
            return render_template('puzzle.html', pieces=pieces, grid_size=grid_size)
    return render_template('upload.html')

if __name__ == '__main__':
    app.run(debug=True)

 

 

[upload.html]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Upload Image</title>
</head>
<body>
    <h1>Upload an Image to Create a Puzzle</h1>
    <form method="post" enctype="multipart/form-data">
        <label for="file">Choose an image:</label>
        <input type="file" name="file" accept="image/*" required><br><br>

        <label for="grid_size">Grid size (e.g., 4 for 4x4):</label>
        <input type="number" name="grid_size" min="2" max="20" value="4" required><br><br>
       
        <button type="submit">Upload</button>
    </form>
</body>
</html>

 

 

[puzzle.html]

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Puzzle Game</title>
    <style>
        .puzzle-container {
            display: grid;
            grid-template-columns: repeat({{ grid_size }}, 1fr);
            grid-template-rows: repeat({{ grid_size }}, 1fr);
            gap: 2px;
            margin-top: 20px;
            width: 400px;
            height: 400px;
        }
        .puzzle-piece {
            width: 100%;
            height: 100%;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h1>Puzzle Game</h1>
    <div class="puzzle-container">
        {% for piece in pieces %}
            <img src="{{ url_for('static', filename='puzzle/' ~ piece) }}" class="puzzle-piece">
        {% endfor %}
    </div>
    <script>
        // 퍼즐 조각을 클릭하여 퍼즐을 완성할 수 있도록 하는 간단한 스크립트 (확장 가능)
        const pieces = document.querySelectorAll('.puzzle-piece');
        let selectedPiece = null;

        pieces.forEach(piece => {
            piece.addEventListener('click', () => {
                if (selectedPiece) {
                    const tempSrc = selectedPiece.src;
                    selectedPiece.src = piece.src;
                    piece.src = tempSrc;
                    selectedPiece = null;
                } else {
                    selectedPiece = piece;
                }
            });
        });
    </script>
</body>
</html>

 

[operation]

pip install -r requirements.txt

python app.py

728x90