Cách gắn nhanh text vào ảnh để tạo hàng loạt ảnh đại diện cho video, bài post (yêu cầu biết lập trình PHP cơ bản)

Canva là ứng dụng giúp tạo ảnh đại diện rất đẹp, chúng ta chỉ cần gõ văn bản và căn sao cho ổn là được, rất tiện lợi, tuy nhiên nếu phải tạo với số lượng lớn, cách thủ công này sẽ chậm và chán!

Hôm nay, tôi xin chia sẻ với anh chị em cách tạo nhanh 1000 (hoặc hơn) ảnh đại diện có gắn text thông qua PHP (ngôn ngữ lập trình web). Nhược điểm của biện pháp này là ace cần biết một chút về PHP (nếu không biết thì cái hướng dẫn này chỉ là một mớ rắc rối), ngoài ra cách làm này cũng không phải là biện pháp tạo ra ảnh đại diện có tính nghệ thuật quá cao (nhưng được cái nó vẫn đủ dùng).

Lưu ý: đây không phải là cách tạo ảnh bằng AI gì cả, nó đơn giản chỉ là biện pháp rút ngắn thời gian khi ace có rất nhiều nội dung nào đó cần ảnh đại diện.

Sau khi tạo project PHP qua một IDE nào đó (ví dụ NetBeans / nôm na là giao diện để gõ code), ace tạo thêm 3 thư mục sau:
  • youtube_banner_original: là ảnh gốc của mình, nên là ảnh chuẩn kích cỡ ngay từ đầu, ví dụ 1080 x 1920 là kích cỡ tiện cho điện thoại khi dựng đứng.
  • youtube_banner_fonts: là nơi lưu các font chữ các bạn muốn dùng. 
  • youtube_banner_final: là nơi lưu ảnh các bạn đã gắn xong text vào ảnh, nói cách khác là thành phẩm của chúng ta.

1. Chuẩn bị sẵn ảnh gốc



Ở đây chúng ta làm ảnh đại diện trên quy mô lớn, nên việc unique từng ảnh có thể không cần thiết, do vậy, chẳng hạn để tạo 1000 ảnh, ace có thể chỉ cần 200 ảnh. Mình vào Canva, thiết lập kích cỡ chuẩn, rồi chọn các ảnh thấy ưng. Bước này ace cố gắng chọn các ảnh đẹp nhất có thể. Xong xuôi mình tải tất cả về, để ở định dạng PNG (cho nét), sau đó giải nén ảnh ra, đưa tất cả ảnh vào thư mục youtube_banner_original.

2. Chuẩn bị sẵn font chữ

Ace muốn dùng font chữ nào cho text thì mình lên Google Fonts tải về, lưu ý chọn font tiếng Việt để tránh bị lỗi font. Mặc định font tải về từ Google Fonts có định dạng ttf (TrueType Font). Ace tải font về rồi giải nén nó ra. Nó sẽ bung ra rất nhiều kiểu đậm, nhạt, in nghiêng, v.v... cho font đó, nếu ace chỉ cần dùng font thông thường của nó thì tìm đến cái có chữ Regular để copy đưa vào thư mục youtube_banner_fonts

Ví dụ bên dưới sử dụng 2 font tiếng Việt là: Be-Regular và Mali-Regular



3. Làm rõ cấu trúc chung của các ảnh đại diện

Các ảnh đại diện dĩ nhiên khác nhau về cả ảnh gốc và văn bản, nhưng chúng cần có cấu trúc chung, ví dụ text gồm 2 phần, một phần chữ nhỏ, một phần chữ lớn, tương ứng với từng font chữ, và căn ra giữa ảnh gốc chẳng hạn.

4. Đoạn mã gợi ý

Giải thích chi tiết thì khá phức tạp, cơ mà ace nào biết chút về PHP thì có thể hiểu tương đối nhanh.

Đầu tiên là chúng ta lấy ngẫu nhiên một ảnh trong thư mục ảnh gốc.

Text trong ví dụ này được căn ra giữa và để tránh text chìm vào nền ảnh gốc, chúng ta tạo nền màu có độ trong suốt nhất định (để ảnh thành phẩm không bị xấu).

Ở đây ace có các tùy chọn đầy đủ về loại font, màu chữ, kích cỡ font, vị trí của nó so với ảnh gốc (ý là không nhất thiết phải căn ra giữa).

Sử dụng các hàm sẵn có của PHP để điều chỉnh văn bản và gắn text vào ảnh.

Ace nào chưa rõ có thể hỏi ChatGPT, nó rất mạnh trong việc trả lời hoặc gợi ý code.

Đoạn mã bên dưới chắc chắn là nên được điều chỉnh tùy theo nhu cầu cụ thể của mọi người, chẳng hạn như:
  • Kích cỡ ảnh thumbnail
  • Số lượng văn bản
  • Kích cỡ font tùy theo số lượng ký tự để tránh bị tràn lề
  • Kịch bản gắn text
  • Cách lưu tên file cho thành phẩm
  • Thêm logo vào thành phẩm
  • V.v...

// Tạo banner cho video YouTube 1080 x 1920

set_time_limit(3600); // thiết lập thời gian chạy tối đa 60 phút

// lấy ngẫu nhiên một ảnh mẫu
function get_random_thumbnail_youtube_orig(){
    $image_arr = array(); // chứa url ảnh
    $image_url = NULL; // lấy một url ảnh cụ thể
    $i = 0;
    
    // lấy đường dẫn ảnh gốc
    foreach(glob(__DIR__ .'/youtube_banner_original/*.png') as $filename){
        $image_arr[$i] = $filename;
        $i++;
    }
    
    // đếm số lượng phần tử
    $cot =  count($image_arr) - 1;

    if ($cot > 0) {
        // lấy ngẫu nhiên một giá trị
        $r = rand(0,$cot);
        
        // lấy url ảnh ngẫu nhiên
        $image_url = $image_arr[$r];
    }
    
    return $image_url;
}

function create_youtube_thumbnail_size_1080_1920($name){
    // kiểm tra xem ảnh đã được tạo chưa để không cần phải tạo lại
    $full_banner_path = __DIR__ .'/youtube_banner_final/'.$name.'.png';
    
    // Các file ảnh và audio phải có tồn tại mới thực hiện lệnh
    if (file_exists($full_banner_path) == FALSE) {
        // Đường dẫn tới ảnh gốc và font chữ
        $imagePath = get_random_thumbnail_youtube_orig(); // lấy ngẫu nhiên một ảnh trong kho
        $fontPath = __DIR__ . '/youtube_banner_fonts/Be-Regular.ttf'; // lấy font chữ // __DIR__ nghĩa là lấy thư mục gốc của file đang chạy
        $fontLogo = __DIR__ . '/youtube_banner_fonts/Mali-Regular.ttf'; // font logo website

        // Tạo ảnh từ file PNG
        $image = imagecreatefrompng($imagePath);

        // Bảo toàn tính trong suốt của PNG
        imagealphablending($image, true);
        imagesavealpha($image, true);

        // Định nghĩa màu sắc cho văn bản (ở đây là màu trắng)
        $color = imagecolorallocate($image, 255, 255, 255); 

        // Định nghĩa văn bản, kích thước font
        $text1 = "Bài thơ cho em";
        $fontSize1 = 70; // Kích thước font văn bản 1

        // tính toán chiều rộng và chiều cao của văn bản 1 để căn
        // Tính toán hộp chứa văn bản 1
        $bbox1 = imagettfbbox($fontSize1, 0, $fontPath, $text1);
        $left1 = $bbox1[0];
        $bottom1 = $bbox1[1];
        $right1 = $bbox1[2];
        $top1 = $bbox1[7];

        // Chiều rộng và chiều cao của văn bản 1
        $textWidth1 = $right1 - $left1;
        $textHeight1 = $top1 - $bottom1;

        /////////////////////////////////////////
        $fontSize2 = 120; // Kích thước font văn bản 2
        $text2 = $name; // kích cỡ font lớn

        if (mb_strlen($text2, 'UTF-8') >= 8) { // nếu nhiều ký tự thì để tránh bị tràn lề thì điều chỉnh độ rộng
           $fontSize2 = 100; // Kích thước font
        }

        // tính toán chiều rộng và chiều cao của văn bản 2 để căn
        // Tính toán hộp chứa văn bản 2
        $bbox2 = imagettfbbox($fontSize2, 0, $fontPath, $text2);
        $left2 = $bbox2[0];
        $bottom2 = $bbox2[1];
        $right2 = $bbox2[2];
        $top2 = $bbox2[7];

        // Chiều rộng và chiều cao của văn bản 1
        $textWidth2 = $right2 - $left2;
        $textHeight2 = $top2 - $bottom2;

        $angle = 0;     // Góc nghiêng

        // X = (Chiều rộng hình ảnh - Chiều rộng văn bản) / 2
        // Y = (Chiều cao hình ảnh / 2) + (Chiều cao văn bản / 2)  

        $space_between_texts = 200; // khoảng cách giữa 2 văn bản

        $height_inter = $textHeight1 + $textHeight2 + $space_between_texts; // chiều cao của cả hộp văn bản
        $y_inter = (1920 + $height_inter)/2;

        // Tạo màu trong suốt (màu xám với độ trong suốt)
        $transparency = 47; // Độ trong suốt từ 0 (không trong suốt) đến 127 (hoàn toàn trong suốt)
        $boxColor = imagecolorallocatealpha($image, 30, 30, 30, $transparency);

        // Kích thước và vị trí của hộp màu
        $boxWidth = 900; // Chiều rộng của hộp / cố định
        $boxHeight = 500; // Chiều cao của hộp / cố định

        $boxX = (1080 - $boxWidth)/2; // Tọa độ X của hộp
        $boxY = (1920 - $boxHeight)/2; // Tọa độ Y của hộp
        $adjust_spacing_of_box = 110; // điều chỉnh hộp để văn bản nằm giữa nó

        if (mb_strlen($text2, 'UTF-8') >= 8) { // nếu nhiều ký tự thì để cân điều chỉnh độ cao
           $adjust_spacing_of_box = 105; // điều chỉnh hộp để văn bản nằm giữa nó
        }

        // Vẽ hộp màu để văn bản không bị chìm vào nền
        imagefilledrectangle($image, $boxX, $boxY, $boxX + $boxWidth, $boxY + $boxHeight - $adjust_spacing_of_box, $boxColor);

        $x1 = (1080 - $textWidth1)/2;   // Tọa độ X trên ảnh của văn bản 1, căn giữa
        $y1 = $y_inter - ($space_between_texts/2);        // Tọa độ Y trên ảnh của văn bản 1

        $x2 = (1080 - $textWidth2)/2; ;  // Tọa độ X trên ảnh của văn bản 2, căn giữa
        $y2 = $y_inter + ($space_between_texts/2);        // Tọa độ Y trên ảnh của văn bản 2

        // Chèn văn bản vào ảnh
        imagettftext($image, $fontSize1, $angle, $x1, $y1, $color, $fontPath, $text1);
        imagettftext($image, $fontSize2, $angle, $x2, $y2, $color, $fontPath, $text2);


        // Vẽ hộp màu để văn bản logo không bị chìm vào nền
        $loxX = 400;
        $loxY = 1780; 
        $loxWidth = 307; 
        $loxHeight = 100;
        imagefilledrectangle($image, $loxX, $loxY, $loxX + $loxWidth, $loxY + $loxHeight,$boxColor);

        // Chèn logo vào
        $text3 = "Logoooo";
        $fontSize3 = 50;
        $x3 = 420;
        $y3 = 1860;
        $color3 = imagecolorallocate($image, 247, 120, 107); // giống màu logo website
        imagettftext($image, $fontSize3, $angle, $x3, $y3, $color3, $fontLogo, $text3);

        // đường dẫn nơi lưu ảnh hoàn thành
        $newImagePath = __DIR__ . '/youtube_banner_final/'.$name.'.png';

        // Lưu ảnh mới
        imagepng($image, $newImagePath);

        // Giải phóng bộ nhớ
        imagedestroy($image);

        echo "Ảnh mới đã được lưu tại: $newImagePath </br>";
    }
    else {
        echo "Ảnh thumbnail này đã tồn tại: $full_banner_path"."</br>";
    }
}


// kịch bản
$name_array = array(
"Phương Thảo",
"Thùy Linh",
"Anh Thư",
"Thu Trang",
"Huyền Trang",
"Thu Hà",
"Thùy Trang",
"Kim Ngân",
"Hồng Nhung",
"Yến Nhi",
"Ngọc Ánh",
);

// quá trình tạo ảnh
foreach ($name_array as $narr) {
    create_youtube_thumbnail_size_1080_1920($narr);
}

Kịch bản trên tạo các ảnh đại diện là các bài thơ cho các cô có tên trong kịch bản.

Nhận xét

Bài đăng phổ biến từ blog này

[Tài liệu nghiên cứu] Lý thuyết các Chiến lược Tình dục: Một góc nhìn Tiến hóa về Hẹn hò ở Người [David M. Buss và David P. Schmitt]

[Tài liệu nghiên cứu] Vẻ đẹp và quái vật: cơ chế của sự chọn lọc giới tính ở người [David A. Puts]

[Tài liệu nghiên cứu] Tại sao họ không kết hôn? Rào cản đối với hôn nhân trong số những người có hoàn cảnh khó khăn [Kathryn Edin và Joanna M. Reed]