כלי תמונה: תמונות ממוזערות, חיתוך, טשטוש וסימן מים

איך STORAGE יוצר גדלים של תמונה לפי דרישה, מחתך לפי יחס, מטשטש, מוסיף סימן מים וממיר פורמט, איך הקבצים נרשמים בעמודה tumb, ואיך מנקים CDN של Cloudflare.

⏱ 9 דק' קריאה 1540 מילים ערוך דף זה ב-GitHub

STORAGE לא רק שומרת קבצים: היא גם מייצרת מהם גרסאות. מבקשים כתובת של תמונה ברוחב וגובה מסוימים, והגרסה נוצרת בפעם הראשונה, נשמרת לצד המקור ונרשמת בטבלה, כך שפעם הבאה מוחזרת הכתובת מיד. בעמוד הזה: get_thumb ו-get_by_name, חיתוך לפי יחס (cropper), טשטוש, סימן מים, המרת פורמט, ניקוי מטמון Cloudflare, וההגדרות הסטטיות שמשפיעות על האיכות.

system/ בעמוד הזה הוא תיקיית הליבה הפרוסה (api/core בריפו), ו-{admin} הוא CONFIG::$admin_url. הכל נמצא ב-system/collections/STORAGE.php. על שמירת הקובץ המקורי קראו קודם את אחסון קבצים.

ספריות העיבוד#

ספרייהשימוש
Verot (\Verot\Upload\Upload)שינוי גודל, חיתוך ליחס, המרת פורמט. נטענת מ-CONFIG::$core_path . '/vendor/autoload.php'
GDחיתוך לפי קואורדינטות (imagecrop) ב-save_thumb
Imagickטשטוש (get_blur_image) ושמירת JPEG באיכות (save_jpeg_with_imagick)
דרישות שרת
get_blur_image דורשת את התוסף imagick. save_thumb משתמשת ב-GD, ונופלת ל-imagejpeg כש-Imagick לא טעון. בדקו את שני התוספים בדרישות המערכת.

גדלים: get_thumb#

STORAGE::get_thumb($id, $width = "auto", $height = "auto")

מחזירה כתובת (מחרוזת) של גרסה מוקטנת של התמונה. $id יכול להיות מזהה מספרי או שורה שכבר נטענה מ-STORAGE::get(). מחרוזת ריקה מוחזרת כשהקובץ לא קיים.

רוחבגובההתוצאה
מספר"auto"מוקטנת לרוחב הנתון, היחס נשמר
"auto"מספרמוקטנת לגובה הנתון, היחס נשמר
מספרמספרחיתוך ליחס המבוקש (image_ratio_crop): התמונה ממלאת בדיוק את הגודל, והעודף נחתך

ערך שאינו מספר חיובי נחשב "auto". הקוד מעגל ל-int.

$id = STORAGE::add($_FILES["photo"]);

$small  = STORAGE::get_thumb($id, 300);        // רוחב 300, גובה לפי היחס
$tall   = STORAGE::get_thumb($id, "auto", 600);
$square = STORAGE::get_thumb($id, 200, 200);   // ריבוע, עם חיתוך

בתבנית Smarty יש פונקציה מוכנה:

<img src="{crm_storage_tumb id=$article.image width=400 height=300}" alt="">

מה קורה מאחורי הקלעים#

  1. שם הגרסה הוא tumb_<רוחב>X<גובה>, ובצד שלא ביקשתם auto (למשל tumb_300Xauto). הפונקציה STORAGE::get_key_name($name, $w, $h) מחזירה את המפתח הזה.
  2. הכתובת היא כתובת הקובץ המקורי עם שם הקובץ <uuid|id>_<מפתח>.<סיומת>.
  3. אם המפתח כבר רשום בעמודה tumb של השורה (STORAGE::is_exist($file, $key)), הכתובת מוחזרת בלי עיבוד.
  4. אחרת create_thumb (מתודה מוגנת, לא נקראת מבחוץ) יוצרת את הגרסה באותה בקשה, שומרת אותה באותו מקום אחסון של המקור (מקומי, FTP או S3) ורושמת את המפתח ב-tumb.
  5. אם היצירה נכשלה מוחזרת כתובת המקור.

הפורמטים הנתמכים לגרסאות הם jpg, jpeg, png, webp. עבור gif מוחזרת כתובת הקובץ כפי שהוא, ועבור סוג אחר לא נוצרת גרסה.

יצירה סינכרונית בתוך הבקשה

הגרסה הראשונה של כל גודל נוצרת בזמן שהדף נבנה (עם set_time_limit(0)). דף עם 50 תמונות שמעולם לא עובדו עלול להיות איטי מאוד בפעם הראשונה, ובאחסון S3 או FTP כל יצירה כוללת הורדה והעלאה. אחרי הפעם הראשונה אין עלות. מומלץ להשתמש בקבוצה קטנה וקבועה של גדלים ולא בגודל משתנה לכל בקשה, כי כל גודל חדש הוא קובץ חדש ועמודה tumb ארוכה יותר.

get_by_name: גרסה בעלת שם#

STORAGE::get_by_name($id, $name = "", $width = "auto", $height = "auto")

מחזירה כתובת של גרסה שרשומה בשם סמנטי (למשל חיתוך square או wide שנשמר מה-cropper). עם $name ריק או "tumb" מוחזרת כתובת הקובץ המקורי. אם השם עוד לא רשום בשורה, ללא מידות מוחזרת כתובת המקור, ועם מידות מוחזרת get_thumb רגילה. אם השם קיים, הגרסה נוצרת (אם צריך) ומוחזרת כתובתה.

פונקציות עזר#

מתודהמה היא עושה
get_key_name($name = false, $width = "auto", $height = "auto")בונה את מפתח הגרסה. עם שם מותאם ובלי מידות מוחזר השם עצמו
is_exist($file, $key = "")האם המפתח רשום בעמודה tumb של השורה ($file הוא מערך השורה)
get_local_file($id, $name = false)נתיב מקומי של הקובץ. ב-FTP או S3 מוריד עותק זמני לתיקיית STORAGE::get_temp_folder()
get_temp_folder()CONFIG::$base_path . '/' . STORAGE::$temp_folder (ברירת מחדל media/System/CropTmp)
resize_image($file, $w, $h, $print_to_screen = true)מוקטנת קובץ מקומי עם חיתוך ליחס (Verot), שומרת בתיקייה הזמנית ומחזירה את הנתיב. לא נרשמת בטבלה

חיתוך לפי יחס (cropper)#

עורך התמונות בפאנל מאפשר לחתוך תמונה לכמה יחסים (למשל 1x1, 16x9), וכל חיתוך נשמר כגרסה בשם היחס. הנתונים נשמרים בעמודה cropper_data כ-JSON לפי יחס.

STORAGE::save_thumb($sid, $ratio, $ratData)
  • $ratio: שם היחס (מחרוזת, נכנסת לשם הקובץ).
  • $ratData: אובייקט עם x, y, width, height בפיקסלים של המקור (כמו שהוא מוחזר מ-Cropper.js).
  • מורידה את התמונה, חותכת עם imagecrop, שומרת את הגרסה בשם <uuid|id>_<ratio>.<סיומת> ורושמת אותה. אם הנתונים זהים למה שנשמר כבר, לא נעשה כלום.
  • ל-JPEG נעשה שימוש ב-Imagick כש-STORAGE::$use_imagick_for_quality פעיל והתוסף טעון.

לאחר מכן הקריאה לגרסה: STORAGE::get_by_name($id, "16x9").

$id = 123;
$ratData = (object)["x" => 40, "y" => 0, "width" => 1600, "height" => 900];
STORAGE::save_thumb($id, "16x9", $ratData);

echo STORAGE::get_by_name($id, "16x9");
save_thumb_db ולא להעביר אליה קלט
save_thumb_db($sid, $ratio, $cropper_data = false) מעדכנת את עמודת tumb (ואת cropper_data כשהועבר) בשאילתה שמשרשרת את $cropper_data ל-SQL בלי DB::escape. בקוד הליבה היא מקבלת תמיד json_encode(...) של נתונים שחושבו, וכך צריך להישאר: אל תעבירו לה מחרוזת שהגיעה מבקשה.

טשטוש#

STORAGE::get_blur_image($id, $sigma = 13, $width = "auto", $height = "auto")

יוצרת גרסה מטושטשת (Imagick, blurImage(0, $sigma)), בדרך כלל כתמונת placeholder קטנה שנטענת לפני התמונה המלאה. עם $width או $height חיוביים התמונה מוקטנת קודם (עם אותם כללים כמו get_thumb), ורק אז מטושטשת, כך שהקובץ קטן וטשטוש זול. הסיומות הנתמכות: jpg, jpeg, png, gif, webp.

$placeholder = STORAGE::get_blur_image($id, 13, 32, "auto");
$full        = STORAGE::get_thumb($id, 1200);

שם הקובץ של הגרסה המטושטשת הוא MISC::encode(<identifier>_blur_<w>X<h>S<sigma>) עם הסיומת, כלומר מחרוזת מוצפנת ולא ניחושית (ראו הצפנה). אחרי שינוי מפתחות ההצפנה של MISC, כתובות הטשטוש שנוצרו קודם לא יתאימו לקבצים; הגרסה פשוט תיווצר מחדש.

סימן מים#

STORAGE::getWatermark($id, $wk_file, $wk_left = 20, $wk_top = -20)

מדביקה תמונת סימן מים ($wk_file, נתיב לקובץ תמונה שבו Verot יכול להשתמש) על התמונה ומחזירה את הכתובת (מחרוזת) של הגרסה עם הסימן. $wk_left ו-$wk_top הם המיקום בפיקסלים, וערך שלילי נמדד מהקצה הנגדי (ברירת המחדל 20, -20 היא פינה תחתונה). שם הגרסה: <uuid|id>_wtm_<left>X<top>.<סיומת>. נתמכים jpg, jpeg, png, gif; סיומת אחרת מחזירה false.

$url = STORAGE::getWatermark($id, CONFIG::$base_path . "/media/logo_white.png", 20, -20);
echo '<img src="' . htmlspecialchars($url) . '" alt="">';
הגרסה לא נרשמת ב-tumb

בניגוד ל-get_thumb, גרסת סימן המים לא נרשמת בעמודה tumb, והבדיקה "האם כבר קיימת" משווה את שם הקובץ המקורי לרשימה הזו. בפועל הקובץ נוצר מחדש בכל קריאה. אל תקראו לפונקציה בכל טעינת דף: צרו את הגרסה פעם אחת (בהעלאה או בפעולת מנהל) ושמרו את הכתובת.

מחיקה

בהסרת קובץ מקומי (STORAGE::remove) נמחקות גרסאות _tumb_ בלבד; גרסאות _wtm_ נמחקות רק באחסון FTP. בשימוש בסימני מים באחסון מקומי, נקו אותן בעצמכם כשמוחקים את התמונה. פרטים באחסון קבצים.

המרת פורמט#

בזמן ההעלאה: האפשרות img_convert של STORAGE::add() (jpg, png, gif או webp) מחזירה false כשהקובץ אינו תמונה (getimagesize), ובשאר המקרים יוצרת את הקובץ בפורמט המבוקש לפני שהוא נשמר. כך גם img_max_width ו-img_max_height (הקטנה יחסית בלבד, בלי הגדלה) ו-img_width עם img_height (גודל מדויק עם חיתוך).

$id = STORAGE::add($_FILES["photo"], [
    "img_convert"   => "webp",
    "img_max_width" => 2000,
]);

על קובץ קיים:

STORAGE::convert($sid, $type)

ממירה את המקור ל-$type (נתמך על ידי Verot: jpg, png, gif, webp), מחליפה את הקובץ, מוחקת את הגרסאות שנוצרו (tumb מתאפס) ומעדכנת את ext בשורה. הכתובת משתנה כי הסיומת משתנה, ולכן ערכים שהוטמעו בתוכן כקישור ישיר ישברו; שימוש במזהה תמיד נשאר תקין.

Cloudflare#

אם התמונות מוגשות מאחורי Cloudflare, אחרי החלפת תמונה או חיתוך מחדש הכתובת נשארת זהה, ולכן צריך לנקות אותה ב-CDN:

// בקובץ ההגדרות של האתר (למשל application/includes/init.php)
STORAGE::$cloudfare_cache = true;
STORAGE::$cloudfare_cache_zoneid = "<zone id>";
STORAGE::$cloudfare_cache_apikey = "<api token>";
מתודהמה היא עושה
purge_image($ref)$ref הוא מזהה, uuid או שורה. מנקה את הקובץ הראשי ואת כל הגרסאות שרשומות ב-tumb. מחזירה false כשהמפתחות לא הוגדרו
purge_cloudflare_cache($files)מקבלת כתובת או מערך כתובות, ושולחת לקלאודפלייר במנות של 30

המפתח הוא טוקן API של Cloudflare ולכן שומרים אותו בהגדרות האתר או בכספת, לא בקוד שנכנס למאגר. קראו ל-purge_image לפני שמאפסים את tumb, אחרת רשימת הגרסאות כבר לא זמינה.

הגדרות סטטיות#

הגדרהברירת מחדלהשפעה
STORAGE::$default_jpeg_quality85איכות JPEG בכל פעולות העיבוד
STORAGE::$preserve_color_profiletrueמשמרת פרופיל צבע, בהתאם ליכולות גרסת Verot המותקנת
STORAGE::$use_imagick_for_qualitytrueשמירת JPEG דרך Imagick ב-save_thumb
STORAGE::$temp_foldermedia/System/CropTmpתיקיית עבודה זמנית. קבצים שגילם יותר מ-5 שעות נמחקים ב-clear_tmp(), שרצה בתחילת כל add()
STORAGE::$gallery_max_width, $gallery_max_heightfalseהקטנה אוטומטית בהעלאות לגלריה
STORAGE::$gallery_convert_imagesfalseהמרת פורמט אוטומטית בהעלאות לגלריה
STORAGE::$gallery_require_copyrights, $gallery_require_descriptionfalseחובת מילוי שדות בגלריה

כל ההגדרות נקבעות בקוד האתר (application/includes/init.php), לא בפאנל.

ראו גם#

מצאתם טעות או חוסר? תקנו את הדף או פתחו Issue בריפו. התיעוד נכתב מתוך הקוד של ליבה 5.0.115.