تغییر اندازه و دستکاری تصاویر در PHP — راهنمای کاربردی با مثال

آخرین به‌روزرسانی: ۲۸ آبان ۱۳۹۷
زمان مطالعه: ۷ دقیقه

در این راهنما مقدمه‌ای کوتاه در مورد کتابخانه GD ارائه می‌کنیم و شیوه بارگذاری تصاویر از یک فایل یا ایجاد آن‌ها از صفر را در PHP آموزش می‌دهیم. پس از آن شیوه برش، چرخش، مقیاس‌بندی و معکوس کردن تصاویر را در PHP می‌آموزیم. همچنین تابع ()imagefilter برای اعمال فیلترهای مختلف روی منابع تصویری بارگذاری شده در اسکریپت را مشاهده می‌کنیم. افزون بر آن برخی تابع‌های مفید در GD مانند ()imagesx و ()imagesy برای دریافت عرض و ارتفاع تصاویر بارگذاری شده را نیز بررسی خواهیم کرد.

در انتهای این راهنمای GD شما با چگونگی استفاده از این کتابخانه برای خودکارسازی برخی کارهای اولیه مانند تغییر اندازه همه تصاویر در یک دایرکتوری یا اعمال فیلترهایی مانند خاکستری کردن تصاویر پیش از ذخیره‌سازی نتایج نهایی آشنا خواهید بود. در این مقاله در مورد بسیاری از تابع‌های مفید در GD و شیوه استفاده از آن‌ها برای خودکارسازی اغلب وظایف دستکاری تصاویر را می‌آموزیم.

دستکاری تصاویر با استفاده از ماتریس پیچش (Convolution)

به جز پیکسل‌هایی که در لبه یک تصویر هستند، همه پیکسل‌ها از سوی هشت پیکسل دیگر احاطه شده‌اند. جلوه‌هایی مانند تار کردن یا تشخیص لبه برای هر پیکسل بر اساس مقدار آن پیکسل و مقادیر پیکسل‌های پیرامونی آن محاسبه می‌شوند. برای نمونه در زمینه تشخیص لبه، یک تغییر سریع در رنگ به معنی این است که به لبه یک شیء در تصویر رسیده‌ایم. برای مثال یک تغییر ناگهانی از سفید به قهوه‌ای در تصویر زیر نشان‌دهنده مرز بین فنجان و میز است.

یک روش ساده برای تعیین نوع فیلتر از طریق ماتریس پیچش است. GD از تابعی که در زیر آمده پشتیبانی می‌کند که یک ماتریس پیچش 3×3 را روی منبع تصویر image$ اعمال می‌کند.

imageconvolution($image, $matrix, $div, $offset)

پارامتر matrix$ آرایه‌ای از سه آرایه دیگر است که هر کدام از آن‌ها شامل سه مقدار اعشاری هستند، یعنی یک ماتریس 3×3 است. عنصر نخست آرایه در مقدار رنگ پیکسل گوشه چپ-بالا ضرب می‌شود. به طور مشابه، عنصر دوم آرایه‌ی نخست در مقدار رنگ پیکسلی که مستقیماً در بالای پیکسل مرکزی قرار دارد ضرب می‌شود. رنگ نهایی پیکسل با افزودن نتیجه همه این دستکاری‌ها و سپس تقسیم کردن آن بر div$ به دست می‌آید تا نتیجه نرمال‌شده‌ای به دست آید. نرمال‌سازی به طور کلی باعث می‌شود که رنگ نهایی زیر 255 باشد.

همان طور که دیدیم پارامتر div$ به عنوان مخرج نتیجه پیچش برای نرمال‌سازی مقدار، استفاده می‌شود. در سوی دیگر، پارامتر offset$ برای تعیین مقدار افست برای همه رنگ‌ها مورد استفاده قرار می‌گیرد. شیوه اثرگذاری آن بر نتیجه نهایی را در مثال زیر مشاهده می‌کنید.

نمونه‌های پیچش

در ادامه فهرستی از ماتریس‌های پیچش مختلف را می‌بینید که روی تصویر یک فنجان روی میز اعمال شده‌اند.

تار شدن کادری

$box_blur = array([1, 1, 1], [1, 1, 1], [1, 1, 1]);
imageconvolution($im_php, $box_blur, 9, 0);

جلوه Box Blur صرفاً از طریق میانگین‌گیری از هر پیکسل به وسیله همسایه‌های آن به دست می‌آید. مقدار مخرج 9 به خاطر مجموع همه عناصر در سه آرایه یعنی 9 به این صورت تعیین شده است.

شارپ کردن

$sharpen = array([0, -1, 0], [-1, 5, -1], [0, -1, 0]);
imageconvolution($im_php, $sharpen, 1, 0);

جلوه Sharpen از طریق تشدید اختلاف‌های بین هر پیکسل و همسایه‌هایش ایجاد می‌شود. این کار موجب می‌شود که لبه‌ها واضح‌تر شوند. در مورد این جلوه، مخرج کسر 1 است، زیرا مجموعه همه عناصر در سه آرایه برابر با 1 خواهند بود.

جلوه Emboss

$emboss = array([-2, -1, 0], [-1, 1, 1], [0, 1, 2]);
imageconvolution($im_php, $emboss, 1, 0);

این جلوه به وسیله یک ماتریس مشابه ماتریس sharpen اعمال می‌شود؛ جز این که مقادیر به سمت بالا-چپ منفی می‌شوند و به سمت پایین-راست مثبت هستند. همین نکته موجب ایجاد این جلوه می‌شود. مجموع همه عناصر در مورد این ماتریس پیچشی برابر با 1 است و از این رو لازم نیست نگران افست رنگ باشیم.

تشخیص لبه (Edge Detect)

$edge_detect = array([-1, -1, -1], [-1, 8, -1], [-1, -1, -1]);
imageconvolution($im_php, $edge_detect, 1, 0);
imageconvolution($im_php, $edge_detect, 1, 255);

تشخیص لبه مشابه جلوه sharpen است؛ اما جلوه آن قوی‌تر است. ضمناً مقدار اصلی تصویر، وزنی بیشتر از همسایه‌هایش ندارد. یعنی باید تنها به لبه‌ها توجه کنیم و نه نواحی دارای رنگ‌های ثابت.

در مورد تشخیص لبه، مجموع همه عناصر برابر با 0 است. این بدان معنی است که تصویر به طور عمده تیره خواهد بود؛ مگر این که تغییر عمده‌ای در رنگ وجود داشته باشد که به طور کلی در لبه‌های اشیا رخ می‌دهد. این تصویرِ عمدتاً سیاه را می‌توان با تعیین پارامتر افست به میزان 255 به صورت سفید درآورد.

در تصویر زیر نتیجه اعمال همه این ماتریس‌های پیچش را مشاهده می‌کنید:

تابع‌های کپی تصویر

کتابخانه GD در PHP تابع‌های زیادی برای کپی بخشی از تصویر و سپس تغییر اندازه و ادغام آن دارد. زمانی که از این تابع‌ها استفاده می‌کنید، باید به خاطر داشته باشید که PHP گوشه چپ-بالای تصویر را به عنوان مبدأ تلقی می‌کند. یک مقدار x مثبت شما را به سمت راست تصویر می‌برد و مقدار y مثبت به منزله حرکت به سمت پایین در تصویر است

ساده‌ترین تابع، (imagecopy($dst_im، $src_im، $dst_x، $dst_y، $src_x، $src_y، $src_w، $src_h است. این تابع تصویر مبدأ را به تصویر مقصد کپی می‌کند. پارامترهای $dst_x و $dst_y گوشه بالا-چپ را تعیین می‌کنند که تصویر کپی شده در آنجا قرار خواهد گرفت. پارامترهای $src_x، $src_y، $src_w، و src_h$ بخش مستطیلی از تصویر مبدأ را تعیین می‌کنند که به مقصد کپی خواهد شد.

شما می‌توانید از این تابع برای برش تصاویر و ایجاد یک تصویر از صفر با استفاده از ()imagecreatetruecolor و کپی کردن و برش مستطیلی تصور اولیه در آن استفاده کنید. همچنین می‌توانید از امکان افزودن واترمارک روی تصاویر استفاده کنید؛ اما باید به خاطر داشته باشید که در این روش، اندازه واترمارک را نمی‌توان بر اساس اندازه تصاویر تغییر داد.

یک راه‌حل برای این مشکل استفاده از تابع زیر است:

imagecopyresized($dst_im، $src_im، $dst_x، $dst_y، $src_x، $src_y، $dst_w، $dst_h، $src_w، $src_h)

این تابع همه پارامترهای ()imagecopy را می‌پذیرد و دو پارامتر اضافی برای تعیین اندازه ناحیه مقصد که تصویر مبدأ در آن چسبانده خواهد شد دارد.

تابع ()imagecopyresized کامل نیست چون اندازه تصویر را به درستی بزرگ یا کوچک نمی‌کند. با این وجود با استفاده از تابع ()imagecopyresampled که همه پارامترهای مشابه را می‌پذیرد می‌توانید نتیجه بهتری از تغییر اندازه تصویر بگیرید.

کپی با شفافیت

دو تابع دیگر در مورد کپی کردن تصاویر به نام‌های ()imagecopymerge و ()imagecopymergegray وجود دارند که مفید هستند.

تابع زیر:

imagecopymerge($dst_im، $src_im، $dst_x، $dst_y، $src_x، $src_y، $src_w، $src_h، $pct)

نیز عملکرد مشابه ()imagecopy دارد که پارامتر pct$ اضافی میزان شفافیت تصویر برش یافته را تعیین می‌کند. مقدار 0 به معنی عدم شفافیت و مقدار 100 به معنی شفافیت کامل است. زمانی که نمی‌خواهید محتوای تصویر اصلی را به طور کامل در پشت واترمارک پنهان کنید، استفاده از این تابع کاملاً مفید خواهد بود.

در سوی دیگر، تابع ()imagecopymergegray از آخرین پارامتر برای تبدیل تصویر مبدأ به صورت خاکستری پشتیبانی می‌کند. اگر مقدار آن را برابر با 0 در نظر بگرید، تصویر مبدأ همه رنگ خود را از دست می‌دهد و اگر مقدارش برابر با 100 باشد، تصویر بدون هیچ تغییر حفظ می‌شود.

نمونه‌ای از کپی تصویر

در مثال زیر از تابع ()imagecopy برای تبدیل نیمه راست تصویر به حالت منفی‌اش استفاده می‌کنیم:

$im_php = imagecreatefromjpeg('fish-mosaic.jpg');
$im_php = imagescale($im_php, 800);
$im_php_inv = imagescale($im_php, 800);
 
$im_width = imagesx($im_php);
$im_height = imagesy($im_php);
 
imagefilter($im_php_inv, IMG_FILTER_NEGATE);
imagecopy($im_php, $im_php_inv, $im_width/2, 0, $im_width/2, 0, $im_width/2, $im_height);
 
$new_name = 'fish-mosaic-half-negate.jpg'; 
imagejpeg($im_php, $new_name);

در این کد ما دو کپی از تصویر اولیه ایجاد کرده‌ایم که هر یک از آن‌ها تا عرض 800 پیکسل کوچک شده‌اند. پس از آن از تابع ()imagefilter برای ایجاد یک حالت منفی از تصویر اولیه img_php_inv$ استفاده شده است. سپس نیمه راست این تصویر منفی با استفاده از تابع ()imagecopy به تصویر اصلی کپی می‌شود.

این روش یک کاربرد مقدماتی تابع ()imagecopy را نشان می‌دهد. شما می‌توانید نتایج را در ادامه مشاهده کنید. همچنین می‌توانید تصویر را به بخش‌های کوچک‌تر تقسیم کنید یا آن را به حالت نوارهایی برش دهید تا جلوه‌های جذاب‌تری روی آن ایجاد شوند. ما از تابع ()imagecopymergegray در قطعه کد زیر برای ایجاد نوارهای بیشتری از تصویر اصلی ماهی استفاده کرده‌ایم:

$im_php = imagecreatefromjpeg('fish-mosaic.jpg');
$im_php = imagescale($im_php, 800);
$im_php_bw = imagescale($im_php, 800);
 
$im_width = imagesx($im_php);
$im_height = imagesy($im_php);
 
$stripes = 200;
for($i = 0; $i < $stripes; $i++) {
    if($i%2 == 0) {
        imagecopymergegray($im_php, $im_php_bw, $i*$im_width/$stripes, 0, $i*$im_width/$stripes, 0, $im_width/$stripes, $im_height, 0);
    } else {
        imagecopymergegray($im_php, $im_php_bw, $i*$im_width/$stripes, 0, $i*$im_width/$stripes, 0, $im_width/$stripes, $im_height, 100);
    }
}
 
imagefilter($im_php, IMG_FILTER_CONTRAST, -255);
imagefilter($im_php, IMG_FILTER_COLORIZE, 250, 0, 0, 100);
 
$new_name = 'fish-mosaic-stripes.jpg'; 
imagejpeg($im_php, $new_name);

نمونه کد فوق از راهبرد مشابه مثال قبلی استفاده می‌کند؛ اما این بار تصویر به نوارهای کوچک‌تری برش یافته است که بر اساس مقدار متغیر i$ به تناوب به صورت خاکستری درآمده‌اند یا بدون تغییر مانده‌اند. پس از کامل شدن همه عملیات کپی و ادغام، دو فیلتر روی تصویر اعمال می‌کنیم تا نوارهای برش یافته برجسته‌تر شوند. تصویر زیر نتیجه نهایی این دو تابع را همراه با فیلترهای اعمال شده روی تصویر نشان می‌دهد.

قرار دادن واترمارک یا اطلاعات دیگر تصویر

برخی سازمان‌ها واترمارک‌های خود را روی تصاویر اضافه می‌کنند تا مشخص شود که مالک تصویر چه کسی است. این کار باعث می‌شود که شناسایی برند افزایش یابد و افراد دیگر را از کپی غیر مجاز تصاویر بازمی‌دارد. به لطف کتابخانه GD در PHP درج واترمارک روی تصاویر کار بسیار سرراستی محسوب می‌شود.

$im_php = imagecreatefromjpeg('waterfall.jpg');
$watermark = imagecreatefrompng('watermark.png');
$im_width = imagesx($im_php);
$im_height = imagesy($im_php);
 
$watermark = imagescale($watermark, $im_width/5);
$wt_width = imagesx($watermark);
$wt_height = imagesy($watermark);
 
imagecopy($im_php, $watermark, 0.95*$im_width - $wt_width, 0.95*$im_height - $wt_height, 0, 0, $wt_width, $wt_height);
 
$new_name = 'waterfall-watermark.jpg'; 
imagejpeg($im_php, $new_name);

در قطعه کد فوق ما دو منبع تصویر مختلف به ترتیب با استفاده از ()imagecreatefromjpeg برای تصویر اصلی و ()imagecreatefrompng برای تصویر دارای واترمارک ایجاد کرده‌ایم. عرض و ارتفاع تصویر اصلی با استفاده از تابع‌های ()imagesx و ()imagesy تعیین می‌شود.

اکنون همه تصاویری که می‌خواهیم واترمارک کنیم، ابعاد یکسانی دارند. اگر واترمارک را بر اساس ابعاد تصویر اصلی تغییر اندازه ندهید، شکل عجیبی می‌یابد. برای نمونه یک واترمارک 200 پیکسلی روی تصویر 1000 پیکسلی شاید مناسب به نظر برسد؛ اما برای تصویر با عرض 600 پیکسل بسیار بزرگ خواهد بود و روی تصویر 2400 پیکسلی نیز ممکن است کاملاً کوچک دیده شود.

بنابراین از تابع ()imagescale استفاده می‌کنیم تا اندازه واترمارک همیشه یک‌پنجم عرض تصویر اصلی بماند. سپس از تابع ()imagecopy برای قرار دادن واترمارک در موقعیت صحیح استفاده می‌کنیم. نتیجه نهایی قطعه کد فوق به صورت زیر است:

افزون بر واترمارک می‌توان از اطلاعات دیگری مانند مکانی که عکس گرفته شده یا زمان عکس‌برداری نیز به این منظور استفاده کرد.

سخن پایانی

در این نوشته به معرفی برخی از تابع‌های مهم و مفید کتابخانه GD در PHP پرداختیم. در بخش نخست این راهنما نشان دادیم که چگونه می‌توان تصاویر را با استفاده از ماتریس پیچشی در PHP دستکاری کرد. همچنین نمونه‌هایی از عملیات ماتریس پیچشی برای کمک به درک کار با مقادیر رنگ‌های پیکسل‌های مختلف در PHP معرفی شدند.

در بخش دوم این راهنما نیز شیوه کپی و/یا تغییر اندازه بخشی از تصویر برای چسباندن روی تصویری دیگر را آموختیم. این وضعیت در مواردی که می‌خواهیم چیزی مانند واترمارک یا زمان عکسبرداری را به عکس اضافه کنیم مفید خواهد بود. با استفاده از این تابع‌ها می‌توانید جلوه‌های بسیار جذابی روی عکس‌ها ایجاد کنید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۳ نفر
آیا این مطلب برای شما مفید بود؟
شما قبلا رای داده‌اید!
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
tutsplus

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *