Notice
Recent Posts
Recent Comments
Link
250x250
«   2025/09   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Tags more
Archives
Today
Total
관리 메뉴

혼자서 앱 만드는 개발자 함께하는 AI 세상

php로 배경 이미지 위에 글짜를 등록해서 자동으로 jpg 이미지 파일 생성 본문

시트메타 백엔드 노코드 플랫폼 시스템

php로 배경 이미지 위에 글짜를 등록해서 자동으로 jpg 이미지 파일 생성

혼앱사 2025. 2. 15. 22:59
반응형

 

시트메타를 erp 에서 내용에 해당하는 글들을 배경이미지에 넣고 주면 매번 상품등록할떄 편하게 처리 가능할것 같아서 만들어보았습니다.

상품 정보를 등록하는 그리드에 이미 만들어놓은 이미지를 가지고 처리합니다.

이런 이미지를 테스트를 따로 만들어서 넣으면 되요

 

위에서 버튼을 만들어서 

제품사향 페이지를 처리했어요

상세화면 을 뽑았는데 안에 들어가는 이미지는 상세이미지는 다양하기때문에 수작업으로 처리하는 것이 좋다는 의견입니다.

 

magettftext() 함수는 PHP에서 TrueType 폰트를 사용하여 이미지를 생성할 때 텍스트를 출력하는 함수입니다. 그러나 기본적으로 자동 줄바꿈 기능이 없어서 20줄 이상이 되면 수동으로 줄바꿈 처리를 해야 합니다.

 

✅ 해결 방법: wordwrap() 및 explode() 활용

 

텍스트를 특정 너비에서 줄바꿈하고, imagettftext()를 여러 번 호출하여 여러 줄을 출력할 수 있습니다.

<?php
// 기본 설정
header("Content-Type: image/png");
$width = 800;
$height = 600;
$create_img = imagecreatetruecolor($width, $height);
$bg_color = imagecolorallocate($create_img, 255, 255, 255);
$color = imagecolorallocate($create_img, 0, 0, 0);
imagefilledrectangle($create_img, 0, 0, $width, $height, $bg_color);

$font = 'path/to/your/font.ttf'; // 폰트 경로
$font_size = 20;
$x = 200;
$y = 130;
$line_height = 30; // 줄 간격
$max_width = 50; // 한 줄당 최대 글자 수

// 출력할 텍스트
$watermark_text = "이것은 매우 긴 텍스트입니다. 20줄 이상일 경우 다음 줄에 표시되도록 설정해야 합니다. 자동 줄바꿈을 적용합니다.";

// 줄바꿈 적용
$wrapped_text = wordwrap($watermark_text, $max_width, "\n", true);
$lines = explode("\n", $wrapped_text);

// 여러 줄 출력
foreach ($lines as $line) {
    imagettftext($create_img, $font_size, 0, $x, $y, $color, $font, $line);
    $y += $line_height;
}

// 이미지 출력
imagepng($create_img);
imagedestroy($create_img);
?>

1. wordwrap($watermark_text, $max_width, "\n", true);

→ 한 줄당 $max_width 글자를 초과하면 \n을 삽입하여 자동 줄바꿈 처리

2. explode("\n", $wrapped_text);

→ 줄바꿈된 텍스트를 배열로 변환하여 한 줄씩 출력

3. foreach 문을 사용하여 여러 줄을 imagettftext()로 출력

4. $y += $line_height;

→ 줄바꿈될 때마다 y 좌표를 증가시켜 줄 간격 조정

 

이제 긴 텍스트가 자동으로 여러 줄에 표시될 것입니다. 🚀

추가적인 기능이 필요하시면 말씀해 주세요! 😊

 

현재 코드에서 해결해야 할 문제는 다음과 같습니다.

 

🔴 문제점

1. 개행(\n)을 기준으로 문자열을 분리해야 함

2. <red>텍스트</red> 같은 HTML 태그를 감지하고 색상을 변경해야 함

3. 문법 오류 (while 조건, imagettftext() 위치 계산 문제 등)

 

<?php
// 기본 설정
header("Content-Type: image/png");
$width = 800;
$height = 600;
$create_img = imagecreatetruecolor($width, $height);
$bg_color = imagecolorallocate($create_img, 255, 255, 255); // 배경색 흰색
$black = imagecolorallocate($create_img, 0, 0, 0); // 기본 검은색
$cyan = imagecolorallocate($create_img, 0, 255, 255); // 강조색 (청록색)

imagefilledrectangle($create_img, 0, 0, $width, $height, $bg_color);

$font = 'path/to/your/font.ttf'; // 폰트 경로
$font_size = 20;
$x = 50; // 시작 X 좌표
$y = 50; // 시작 Y 좌표
$line_height = 40; // 줄 간격

$desc = "보이지 않는 곳까지 관리하는 케어 SYSTEM, <red>안심위생케어</red>\n"
      . "신경 쓸 필요 없는 자동제빙 SYSTEM, <red>취향대로 즐기는 얼음</red>\n"
      . "신선함을 지켜주는 냉기 SYSTEM, <red>인공지능 냉기케어 시스템</red>\n"
      . "신선함을 지켜주는 냉기 SYSTEM, <red>인공지능 냉기케어 시스템</red>";

// 개행 기준으로 줄 나누기
$lines = explode("\n", $desc);

// 줄별로 텍스트 출력
foreach ($lines as $line) {
    // 태그를 감지하고 분리
    $parts = preg_split('/(<red>.*?<\/red>)/', $line, -1, PREG_SPLIT_DELIM_CAPTURE);
    
    $current_x = $x; // X 좌표 초기화

    foreach ($parts as $part) {
        if (preg_match('/<red>(.*?)<\/red>/', $part, $matches)) {
            $text = $matches[1]; // 태그 안의 텍스트 추출
            $color = $cyan; // 강조 색상 적용
        } else {
            $text = $part;
            $color = $black;
        }

        // 텍스트 출력 후 X 좌표 이동 (텍스트 너비 측정)
        $bbox = imagettfbbox($font_size, 0, $font, $text);
        $text_width = $bbox[2] - $bbox[0];

        imagettftext($create_img, $font_size, 0, $current_x, $y, $color, $font, $text);
        $current_x += $text_width;
    }

    $y += $line_height; // 다음 줄로 이동
}

// 이미지 출력
imagepng($create_img);
imagedestroy($create_img);
?>

 

전체 실제 소스 입니다.

<?php

require './db_info.php'; //위에 생성했던 데이터베이스 연결 파일 호출
require './lib.php';
header('Content-Type: application/json; charset=UTF-8');
header("HTTP/1.1 200 OK");
header("Access-Control-Allow-Methods: OPTIONS,GET,POST,PUT,DELETE");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: x-requested-with");
session_start();
$requestParts = explode('/', $_GET['request']);
//echo $headers["X-Auth-Token"];
$responce = new \stdClass();


$img_path = "/ok1shop/uploads/mijung/main.jpg";
///echo $img_path;



$watermark_font = "./font/NotoSansCJKkr-Medium.ttf";//폰트파일도절대경로로지정해야함(url이아닌path)
///Users/skpark/Downloads/Noto_Sans_KR/static/NotoSansKR-Black.ttf /Users/skpark/Downloads/Noto_Sans_KR/static/NotoSansKR-Bold.ttf /Users/skpark/Downloads/Noto_Sans_KR/static/NotoSansKR-ExtraBold.ttf /Users/skpark/Downloads/Noto_Sans_KR/static/NotoSansKR-ExtraLight.ttf /Users/skpark/Downloads/Noto_Sans_KR/static/NotoSansKR-Light.ttf /Users/skpark/Downloads/Noto_Sans_KR/static/NotoSansKR-Medium.ttf /Users/skpark/Downloads/Noto_Sans_KR/static/NotoSansKR-Regular.ttf /Users/skpark/Downloads/Noto_Sans_KR/static/NotoSansKR-SemiBold.ttf /Users/skpark/Downloads/Noto_Sans_KR/static/NotoSansKR-Thin.ttf
$watermark_font = "./font/NotoSansKR-Medium.ttf"; // 절대경로 사용



$mb0 = $_GET["mb0"];


$select_query = " SELECT * FROM   okShop_MENU_MGT_product_desc2  where mb0=$mb0  ";
$result = mysqli_query($conn, $select_query);
$watermark_text = [];

while ($row = mysqli_fetch_assoc($result)) {
    $watermark_text = $row;//워터마크텍스트

}



//echo print_r($row);


//워터마크텍스트삽입
if ($file = trim($requestParts[0]) == "profile") {
    profile_view($img_path);
} else if (is_image($img_path)) {
    // Add watermark to the image
    add_watermark_text($img_path, $watermark_font);

} else {
    // Serve the file for download
    serve_file_for_download($img_path);
}


function is_image($file_path)
{
    $image_types = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp'];
    $mime_type = mime_content_type($file_path);
    return in_array($mime_type, $image_types);
}





function add_watermark_text($image_path, $font)
{

    global $watermark_text;

    $ALIGN_CENTER = true;




    $thin = "./font/NotoSansKR-Thin.ttf";
    $SemiBold = "./font/NotoSansKR-SemiBold.ttf";
    $Regular = "./font/NotoSansKR-Regular.ttf";
    $Medium = "./font/NotoSansKR-Medium.ttf";
    $Light = "./font/NotoSansKR-Light.ttf";
    $ExtraLight = "./font/NotoSansKR-ExtraLight.ttf";
    $ExtraBold = "./font/NotoSansKR-ExtraBold.ttf";
    $Bold = "./font/NotoSansKR-Bold.ttf";
    $Black = "./font/NotoSansKR-Black.ttf";




    $array_img_chk = array("jpg", "jpeg", "png", "gif", "bmp");

    //이미지확장자
    $img_ext = explode(".", strrev($image_path));
    $img_ext = strrev($img_ext[0]);
    $img_ext = strtolower($img_ext);
    $opacity = 20;
    //이미지파일인경우에만진행
    if (in_array($img_ext, $array_img_chk)) {

        if ($img_ext == 'jpg' || $img_ext == 'jpeg') {
            $create_img = imagecreatefromjpeg($image_path);
            $image_org = imagecreatefromjpeg($image_path);
        }
        if ($img_ext == 'png') {
            $create_img = imagecreatefrompng($image_path);
            $image_org = imagecreatefrompng($image_path);

        }

        if ($img_ext == 'gif') {
            $create_img = imagecreatefromgif($image_path);
            $image_org = imagecreatefromgif($image_path);
        }
        if ($img_ext == 'bmp') {
            $create_img = imagecreatefromwbmp($image_path);
            $image_org = imagecreatefromwbmp($image_path);
        }

        if ($create_img) {
            list($IMAGE_W, $IMAGE_H) = getimagesize($image_path);
            list($WATERMARK_W, $WATERMARK_H) = [300, -200];
            if ($ALIGN_CENTER) { // Center			

                $POS_X = (($IMAGE_W - $WATERMARK_W) / 2);
                $POS_Y = (($IMAGE_H - $WATERMARK_H) / 2);
            } else {
                $POS_X = ($IMAGE_W - $WATERMARK_W);
                $POS_Y = ($IMAGE_H - $WATERMARK_H);
            }


            imagealphablending($create_img, true);
            $color = imagecolorallocate($create_img, 0, 0, 0);





            $font_size = 40;
            $wrapped_text = $watermark_text["mb10"];
            $img_width = imagesx($create_img);  // 이미지 너비
            $img_height = imagesy($create_img); // 이미지 높이


            // 텍스트 크기 계산
            $text_box = imagettfbbox($font_size, 0, $font, $wrapped_text);
            $text_width = $text_box[2] - $text_box[0]; // 텍스트 너비
            $text_height = $text_box[1] - $text_box[7]; // 텍스트 높이

            // 중앙 좌표 계산
            $x = ($img_width - $text_width) / 2;
            $y = 120;

            // 텍스트 출력
            imagettftext($create_img, $font_size, 0, $x, $y, $text_color, $font, $wrapped_text);

            $wrapped_text = $watermark_text["mb11"];

            $y = 180;
            $font_size = 23;
            $text_box = imagettfbbox($font_size, 0, $Light, $wrapped_text);
            $text_width = $text_box[2] - $text_box[0]; // 텍스트 너비

            $x = ($img_width - $text_width) / 2;
            $font = "./font/NotoSansKR-Bold.ttf";
            imagettftext($create_img, $font_size, 0, $x, $y, $text_color, $Light, $wrapped_text);
            $wrapped_text = $watermark_text["mb12"];

            /*
            NotoSansKR-Thin.ttf
            NotoSansKR-SemiBold.ttf
            NotoSansKR-Regular.ttf
            NotoSansKR-Medium.ttf
            NotoSansKR-Light.ttf
            NotoSansKR-ExtraLight.ttf
            NotoSansKR-ExtraBold.ttf
            NotoSansKR-Bold.ttf
            NotoSansKR-Black.ttf
            */


            $y = 950;
            $font_size = 25;
            $text_box = imagettfbbox($font_size, 0, $font, $wrapped_text);
            $text_width = $text_box[2] - $text_box[0]; // 텍스트 너비

            $x = ($img_width - $text_width) / 2;
            $white = imagecolorallocate($create_img, 255, 255, 255); // 강조색 (청록색)

            imagettftext($create_img, $font_size, 0, $x, $y, $white, $font, $wrapped_text);



            $font_size = 20;
            $x = 100; // 시작 X 좌표
            $y = 1300; // 시작 Y 좌표
            $line_height = 50; // 줄 간격

            $black = imagecolorallocate($create_img, 0, 0, 0); // 기본 검은색
            $red = imagecolorallocate($create_img, 255, 0, 0); // 강조색 (청록색)

            $desc = $watermark_text["mb9"];

            // 개행 기준으로 줄 나누기
            $lines = explode("\n", $desc);

            // 줄별로 텍스트 출력
            foreach ($lines as $line) {
                // 태그를 감지하고 분리
                $parts = preg_split('/(<red>.*?<\/red>)/', $line, -1, PREG_SPLIT_DELIM_CAPTURE);

                $current_x = $x; // X 좌표 초기화

                foreach ($parts as $part) {
                    if (preg_match('/<red>(.*?)<\/red>/', $part, $matches)) {
                        $text = $matches[1]; // 태그 안의 텍스트 추출
                        $color = $red; // 강조 색상 적용
                    } else {
                        $text = $part;
                        $color = $black;
                    }

                    // 텍스트 출력 후 X 좌표 이동 (텍스트 너비 측정)
                    $bbox = imagettfbbox($font_size, 0, $font, $text);
                    $text_width = $bbox[2] - $bbox[0];

                    imagettftext($create_img, $font_size, 0, $current_x, $y, $color, $Regular, $text);
                    $current_x += $text_width;
                }

                $y += $line_height; // 다음 줄로 이동
            }



            imagecopymerge($create_img, $image_org, 0, 0, 0, 0, $IMAGE_W, $IMAGE_H, $opacity); // 원본과 워터마크를 찍은 이미지를 적당한 투명도로 겹치기

            imagesavealpha($create_img, true);

            header("Content-type:image/png");
            imagepng($create_img);

            // imagedestroy($create_img);
        }
    }
}

/**
 * Serve a file for download.
 *
 * @param string $file_path The path to the file.
 */
function serve_file_for_download($file_path)
{
    if (file_exists($file_path)) {
        $file_name = basename($file_path);
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename=' . $file_name);
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file_path));
        readfile($file_path);
        exit;
    } else {
        http_response_code(404);
        echo json_encode(["error" => "File not found."]);
    }
}

function profile_view($file_path)
{
    if (file_exists($file_path)) {
        // Get image information
        list($width, $height, $type) = getimagesize($file_path);

        // Calculate new dimensions
        $new_width = 100;
        $new_height = intval(($height / $width) * $new_width);

        // Create a new image from file
        switch ($type) {
            case IMAGETYPE_JPEG:
                $src_image = imagecreatefromjpeg($file_path);
                break;
            case IMAGETYPE_PNG:
                $src_image = imagecreatefrompng($file_path);
                break;
            case IMAGETYPE_GIF:
                $src_image = imagecreatefromgif($file_path);
                break;
            default:
                http_response_code(415);
                echo json_encode(["error" => "Unsupported image type."]);
                exit;
        }

        // Create a new true color image with the desired dimensions
        $dst_image = imagecreatetruecolor($new_width, $new_height);

        // Preserve transparency for PNG and GIF images
        if ($type == IMAGETYPE_PNG || $type == IMAGETYPE_GIF) {
            imagecolortransparent($dst_image, imagecolorallocatealpha($dst_image, 0, 0, 0, 127));
            imagealphablending($dst_image, false);
            imagesavealpha($dst_image, true);
        }

        // Copy and resize the old image into the new image
        imagecopyresampled($dst_image, $src_image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);

        // Set headers
        header('Content-Type: ' . image_type_to_mime_type($type));
        header('Content-Disposition: inline; filename="' . basename($file_path) . '"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');

        // Output the image
        switch ($type) {
            case IMAGETYPE_JPEG:
                imagejpeg($dst_image);
                break;
            case IMAGETYPE_PNG:
                imagepng($dst_image);
                break;
            case IMAGETYPE_GIF:
                imagegif($dst_image);
                break;
        }

        // Free up memory
        imagedestroy($src_image);
        imagedestroy($dst_image);
        exit;
    } else {
        http_response_code(404);
        echo json_encode(["error" => "File not found."]);
    }
}
728x90
반응형
Comments