เกี่ยวกับ Thumbnail ใน CI วันนี้ผมเอา Idea มาแชร์
วันนี้ บทความที่ผมจะมาเขียน เป็นเรื่องเกี่ยวกับ Thumbnail ล้วนๆ ซึ่ง เป็นการสร้างภาพ Thumbnail on the fly นั่นแหละ แต่มันก็มีทั้ง ข้อดีและ ข้อเสียเหมือนกัน ลองดูเอานะ
Concept:
โดยปกติแล้ว เวลาเราสร้าง Thumbnail หลักการก็คือ
1. Upload Original Binary File.
2. Resize to smaller and upload.
ซึ่งอาจจะเห็นมันมีแค่ 2 อย่างก็จบแล้ว แต่พอเอาเข้าจริงมันเป็นงานที่น่าเบื่อมากเลย ทำไมต้องมาเสียเวลา ทำงานซ้ำไปซ้ำมา ผมก็เลยเกิด idea ทำไมไม่ให้มัน Generate on the fly เลยล่ะ?
แต่....
ถ้าทำอย่างงั้นมันก็ไปเปลือง ทรัพยากร Server แย่สิ หนักเอาการเลยนะนั่น ก็เลยคิดต่ออีกหน่อย...
แล้วถ้าทำเป็น Cache File หลังจาก Generate แล้ว เวลาสั่ง gen ก็มาเช็คก่อนล่ะว่ามีไฟล์รึเปล่า ทำแบบนี้น่าจะใช้ ทรัพยากรจากตอนแรกแค่ไม่ถึง 10%
คิดได้แบบนี้ผมก็เลยเริ่มทำจาก
1. สร้าง Folder ชั้นนอก CI ไว้เก็บ รูป thumbnails ทั้งหมด
- ที่สร้างข้างนอกเพราะผมเผื่อเอาไว้วันหลังถ้ารูปมันเยอะจัด จะได้แก้ไขเรื่อง File System อาจจะใช้ NAS มาจัดเก็บแทน หรือ เอา Reverse Proxy มาคลุมเฉพาะ Dir จะได้ไม่สับสน
2. เขียน lib ขึ้นมา 1 ตัว โดยมีโครงสร้างราวๆ นี้
3. ผมเขียน lib อีกตัวไว้ใช้เรียก path จัดเก็บต่างๆ ดังที่จะได้เห็นจาก $this->CI->path นี่ล่ะครับ (อันนี้คือผมขี้เกียจมาจำ path แล้วก็อยากแก้ที่จุดเดียว ไม่ให้วุ่นวาย) โดยผมจะไม่เอาโคดมาเปิดเผยนะครับ ไม่ใช่ว่าหวงหรืออะไร เพียงแต่ lib ตัวนี้มันเรียกไป หา ไฟล์ config เรื่อง path ของผมอีกซึ่ง มันลำบากที่จะอธิบาย กลัวจะงงกัน เอาเป็นว่า
โดยการทำงานของมันก็คือ
1. มันจะไป get data ของ image ต้นฉบับออกมาทุกอย่างโดยใช้ คำสั่ง get_file_info ที่อยู่ใน helper:file ของ CI มาบอกกับ width และ 300 ที่เราส่งไป [Array]
* ที่ต้อง เอา file info ทั้งหมดมาตั้งเป็นชื่อเพราะว่า ถ้าเกิด original source เปลี่ยนไป ระบบเราจะได้ gen ภาพใหม่ขึ้นมา ไม่ใช่ใช้แต่ของเดิม
ข้อดี
แต่ข้อเสียล่ะ….
1. แน่นอน พื้นที่จัดเก็บจะต้องเสียไปมากกว่าปกติ เพราะว่า ไม่มีการลบไฟล์เลย แม้กระทั่ง Content ต้นฉบับ ถูกลบไปแล้ว
Concept:
โดยปกติแล้ว เวลาเราสร้าง Thumbnail หลักการก็คือ
1. Upload Original Binary File.
2. Resize to smaller and upload.
ซึ่งอาจจะเห็นมันมีแค่ 2 อย่างก็จบแล้ว แต่พอเอาเข้าจริงมันเป็นงานที่น่าเบื่อมากเลย ทำไมต้องมาเสียเวลา ทำงานซ้ำไปซ้ำมา ผมก็เลยเกิด idea ทำไมไม่ให้มัน Generate on the fly เลยล่ะ?
แต่....
ถ้าทำอย่างงั้นมันก็ไปเปลือง ทรัพยากร Server แย่สิ หนักเอาการเลยนะนั่น ก็เลยคิดต่ออีกหน่อย...
แล้วถ้าทำเป็น Cache File หลังจาก Generate แล้ว เวลาสั่ง gen ก็มาเช็คก่อนล่ะว่ามีไฟล์รึเปล่า ทำแบบนี้น่าจะใช้ ทรัพยากรจากตอนแรกแค่ไม่ถึง 10%
คิดได้แบบนี้ผมก็เลยเริ่มทำจาก
1. สร้าง Folder ชั้นนอก CI ไว้เก็บ รูป thumbnails ทั้งหมด
- ที่สร้างข้างนอกเพราะผมเผื่อเอาไว้วันหลังถ้ารูปมันเยอะจัด จะได้แก้ไขเรื่อง File System อาจจะใช้ NAS มาจัดเก็บแทน หรือ เอา Reverse Proxy มาคลุมเฉพาะ Dir จะได้ไม่สับสน
2. เขียน lib ขึ้นมา 1 ตัว โดยมีโครงสร้างราวๆ นี้
<?php if ( ! defined(‘BASEPATH’)) exit(‘No direct script access allowed’);
class Thumb {
//var $_dir = ’static/thumb’;
var $_dim = ‘width’;
var $_size = 75;
function __construct()
{
// Nothing;
}
function GetThumb($resource, $dim, $size)
{
if (!file_exists($resource))
return;
$this->CI =& get_instance();
$this->_dim = $dim;
$this->_size = $size;
$fileinfo = get_file_info($resource);
array_push($fileinfo, $this->_dim, $this->_size);
$filehash = md5(serialize($fileinfo)).‘.’.end(explode(‘.’, $fileinfo[‘name’]));
$filepath = crc32_hash($filehash).‘/’.$filehash;
$thumbpath = $this->CI->path->GetThumbPath($filepath, ‘rel’);
if (!file_exists($thumbpath))
{
$this->GenThumb($resource, $thumbpath);
}
return $this->CI->path->GetThumbPath($filepath, ‘abs’);
}
function GenThumb($resource, $destination)
{
$create_dir = dirname($destination);
if (!is_dir($create_dir))
mkdir($create_dir, 0777, true);
$this->CI->load->library(‘image_lib’);
$config[‘create_thumb’] = true;
$config[‘thumb_marker’] = ”;
$config[‘width’] = $this->_size;
$config[‘height’] = $this->_size;
$config[‘master_dim’] = $this->_dim;
$config[’source_image’] = $resource;
$config[‘new_image’] = $destination;
$this->CI->image_lib->initialize($config);
$this->CI->image_lib->resize();
}
}
?>
แต่ขอบอกไว้ก่อนว่ามัน Copy ไปใช้เลยไม่ได้นะ
เพราะใน lib ตัวนี้ผมยังเรียก function ที่ผมเขียนขึ้นเอง และ lib อีกตัวที่ผมเขียนขึ้นเองมา ใช้ร่วมด้วย โดยผมจะบอกสิ่งที่ผมทำไปทั้งหมดดังนี้
ครับดังนี้ครับ
ครับดังนี้ครับ
1. ผมเรียก autoload ให้กับ helper:file
2. ผมเขียน extends helper:file ลงไปอีกตัวนึง เอาไว้จัดการเรื่อง hashing folder เพื่อไม่ให้ node เต็ม โดยใช้การ hash แบบ crc32
File:application/helpers/MY_file_helper.php
<?php if ( ! defined(‘BASEPATH’)) exit(‘No direct script access allowed’);
if (!function_exists(‘crc32_hash’))
{
function crc32_hash($key, $max=5000)
{
return (crc32($key) & 0×7fffffff) % $max;
}
}
?>
3. ผมเขียน lib อีกตัวไว้ใช้เรียก path จัดเก็บต่างๆ ดังที่จะได้เห็นจาก $this->CI->path นี่ล่ะครับ (อันนี้คือผมขี้เกียจมาจำ path แล้วก็อยากแก้ที่จุดเดียว ไม่ให้วุ่นวาย) โดยผมจะไม่เอาโคดมาเปิดเผยนะครับ ไม่ใช่ว่าหวงหรืออะไร เพียงแต่ lib ตัวนี้มันเรียกไป หา ไฟล์ config เรื่อง path ของผมอีกซึ่ง มันลำบากที่จะอธิบาย กลัวจะงงกัน เอาเป็นว่า
#$this->CI->path->GetThumbPath($filepath, ‘rel’);
#มันก็คือ
#’static/thumbnails/’.$filepath;
#ส่วน
#$this->CI->path->GetThumbPath($filepath, ‘abs’);
#มันก็คือ
#http://……/static/thumnails/’.$filepath;
เท่านี้เองแหละ ไม่มีไรหรอก
ซึ่งพอเราเรียกใช้งาน เราก็จะเรียกประมาณนี้…
$this->load->library(‘thumb’); echo "<img src=’".$this->thumb->GetThumb(’some/original/file.jpg’, ‘width’, 300)."’ />";
โดยการทำงานของมันก็คือ
1. มันจะไป get data ของ image ต้นฉบับออกมาทุกอย่างโดยใช้ คำสั่ง get_file_info ที่อยู่ใน helper:file ของ CI มาบอกกับ width และ 300 ที่เราส่งไป [Array]
2. จากนั้นจะเอาค่าทั้งหมดมา md5 มาตั้งเป็นชื่อไฟล์ แล้วไปเช็คกับ static thumbnail เราว่ามีไฟล์นี้อยู่มั้ย ถ้ามีอยู่ ก็ส่ง path เต็มๆ ไปเลย ไม่ต้องมา generate ใหม่ แต่ถ้าไม่มีก็ สร้างแล้วค่อย ส่ง path เต็มๆ ไป
* ที่ต้อง เอา file info ทั้งหมดมาตั้งเป็นชื่อเพราะว่า ถ้าเกิด original source เปลี่ยนไป ระบบเราจะได้ gen ภาพใหม่ขึ้นมา ไม่ใช่ใช้แต่ของเดิม
เท่านี้ล่ะครับ หลักการไม่มีอะไรมากเลย
ข้อดี
1. สะดวก ไม่ต้องมาเขียนสร้าง thumbnail หลังจาก อัพโหลดรูปใหญ่
2. จะเปลี่ยน Size เมื่อไหร่ก็ได้
3. จะมาเติมลายน้ำ ขอบโค้งอะไรตอนไหนก็ได้
4. เอาไปใช้ใน smarty ได้เลย โดย register class ลงไป
5. จะได้แสดงภาพได้หลายๆ size ตรงไหนก็ได้
6. ไม่ได้เป็นการ Generate on the fly แต่เป็นการทำ static cache แล้วส่งไป จึงไม่เปลือง resource เท่าไหร่
แต่ข้อเสียล่ะ….
1. แน่นอน พื้นที่จัดเก็บจะต้องเสียไปมากกว่าปกติ เพราะว่า ไม่มีการลบไฟล์เลย แม้กระทั่ง Content ต้นฉบับ ถูกลบไปแล้ว
2. ต้องมาเปลือง resource สร้างไฟล์ ในครั้งแรกก่อนเก็บลง cache
ข้อเสียมันขี้ติ๋วมากอ่ะ HD ก็ถูก Resource ก็ไม่ได้มากมายอะไร ผมจึงไม่ลังเลเลย ที่จะเปลี่ยนวิธีใช้งานมาเป็นแบบนี้
ปล. ไฟล์ที่ให้ในเวบมันอาจจะไม่สมบูรณ์เอาไปใช้ไม่ได้ทันที แต่ก็อย่างที่บอก ผมแค่มาแชร์ idea ซึ่งวิธีทำมันง่าย จนคิดว่า คนที่ใช้ CI อยู่แล้วน่าจะทำได้ สบาย

2 comments