2024 年 PHP Conference Japan

imageaffine

(PHP 5 >= 5.5.0, PHP 7, PHP 8)

imageaffine使用選用的裁剪區域,返回包含仿射變換後的 src 影像的影像

說明

imageaffine(GdImage $image, array $affine, ?array $clip = null): GdImage|false

警告

此函式目前沒有說明文件;僅提供其參數列表。

參數

image

一個 GdImage 物件,由圖像創建函式之一返回,例如 imagecreatetruecolor()

affine

索引鍵從 0 到 5 的陣列。

clip

具有索引鍵 "x"、"y"、"width" 和 "height" 的陣列;或 null

回傳值

成功時返回仿射圖像物件,失敗時返回 false

更新日誌

版本 說明
8.0.0 clip 現在可以為 null。
8.0.0 成功時,此函式現在返回一個 GDImage 實例;以前返回的是 resource
新增註記

使用者貢獻的註記 5 則註記

abc at ed48 dot com
10 年前
仿射變換 (AFFINE) 是一種涉及矩陣的幾何變換操作,涵蓋 2D 和 3D 環境。
變換經常用於線性代數和電腦圖學。

在圖像的幾何變換中,會映射像素坐標。

這意味著每個像素都由兩個坐標定位,位於圖像的矩形域中。
在不深入探討像素映射的細節的情況下,讓我們來看看真正重要的部分:仿射變換。
像素映射有幾種類別,其中一種稱為「仿射」。
仿射變換包括:縮放、旋轉、剪切和平移。

PHP 5.5.0+ 像「libart」一樣,使用六個浮點數元素的陣列來完成這項工作。

仿射陣列的定義如下:

$affine = [ a0, a1, b0, b1, a2, b2 ];

其中,
a0、a1、b0、b1、a2、b2 是浮點數值。

由方程式表示:

x' = a0x + a1y + a2

y' = b0x + b1y + b2

a) 單位矩陣,點的路徑沒有變化:

$affine = [ 1, 0, 0, 1, 0, 0 ];

方程式重新映射:

x' = 1x + 0y + 0 = x

y' = 0x + 1y + 0 = y

b) 平移:

$affine = [ 1, 0, 0, 1, H, V ];

方程式重新映射:

x' = 1x + 0y + H = x + H

y' = 0x + 1y + V = y + V

每個點水平移動 H 個單位,垂直移動 V 個單位。

c ) 縮放 (SCALE),

$affine = [ i, 0, j, 1, 0, 0 ];

方程式重新映射:

x' = Mx + 0y + 0 = Mx

y' = 0x + Ny + 0 = Ny

每個點將根據 M 和 N 的值(正數或負數)在其路徑上水平或垂直拉伸或壓縮。

d ) 平行於 x 軸的剪切 (SHEARING),

$affine = [ 1, K, 0, 1, 0, 0 ];

方程式重新映射:

x' = 1x + Ky + 0 = x + Ky

y' = 0x + 1y + 0 = y

平行於 y 軸的剪切 (SHEARING),

$affine = [ K, 0, 0, 1, 0, 0 ];

方程式重新映射:

x' = 1x + 0y + 0 = x

y' = Kx + 1y + 0= y + Kx

e ) 順時針旋轉 (ROTATION),

$affine = [ cos Ø, sin Ø, -sin Ø, cos Ø, 0, 0 ];

方程式重新映射:

x' = x cos Ø + y sin Ø + 0 = x cos Ø + y sin Ø

y' = -x sin Ø + y cos Ø + 0 = y cos Ø - x sin Ø

逆時針旋轉 (ROTATION),

$affine = [ cos Ø, -sin Ø, sin Ø, cos Ø, 0, 0 ];

方程式重新映射:

x' = x cos Ø - y sin Ø + 0 = x cos Ø - y sin Ø

y' = x sin Ø + y cos Ø + 0 = y cos Ø + x sin Ø
abc at ed48 dot com
10 年前
以下是一個範例,每次執行時都會執行特定的處理

<?php

if (!function_exists('imageaffine'))
{
echo
'FUNCTION NOT DEFINED IN THIS VERSION OF PHP';
exit;
}

$base_img = 'affine.png';

$tgt_img1 = 'triangle1.png';

$tgt_img2 = 'triangle2.png';

$arr_affine = [
[
1, 0, 0, 1, 0, 0 ],
[
1, 0, 0, 1, 150, 0 ],
[
1.2, 0, 0, 0.6, 0, 0 ],
[ -
1.2, 0, 0, -0.6, 0, 0 ],
[
1, 2, 0, 1, 0, 0 ],
[
2, 1, 0, 1, 0, 0 ],
[
cos(15), sin(15), -sin(15), cos(15), 0, 0 ],
[
cos(15), -sin(15), sin(15), cos(15), 0, 0 ]
];

$RSR_base = imagecreatetruecolor(400, 300);
$w = imagesx($RSR_base);
$h = imagesy($RSR_base);

$arr_clip = [ 'x' => 0, 'y' => 0, 'width' => $w, 'height' => $h ];

$fillcolor = imagecolorallocate($RSR_base, 0, 0, 0);

imagefill($RSR_base, 10,10, $fillcolor);

imagepng($RSR_base, $base_img);

$drawcolor = imagecolorallocate($RSR_base, 255, 0, 0);

$triangle = [ 50, 50, 50, 150, 200, 150 ];
$points = 3;

imageantialias($RSR_base, 1);

$drawtriangle = imagefilledpolygon($RSR_base, $triangle, $points, $drawcolor);

imagepng($RSR_base, $tgt_img1);

$select = mt_rand(0, 7);

$RSRaff2 = imageaffine($RSR_base, $arr_affine[$select], $arr_clip);

imagepng($RSRaff2, $tgt_img2, 9);

?>

支援影像<br><br>
<img src="<?php echo $base_img; ?>" alt="*" /><br><br>

基礎影像<br><br>
<img src="<?php echo $tgt_img1; ?>" alt="*" /><br><br>

結果影像<br><br>
<img src="<?php echo $tgt_img2; ?>" alt="*" />
adri at sternschanze dot net
6 年前
修正

仿射陣列的定義如下:

$affine = [ a0, b0, a1, b1, a2, b2 ];
abc at ed48 dot com
10 年前
修正中

c ) 縮放 (SCALE),

$affine = [ M, 0, N, 1, 0, 0 ];

方程式重新映射:

x' = Mx + 0y + 0 = Mx

y' = 0x + Ny + 0 = Ny

每個點將根據 M 和 N 的值(正數或負數)在其路徑上水平或垂直拉伸或壓縮。
der at herrstrietzel dot de
3 年前
可能是 imagecopyresampled 的替代方案或解決方法,因為 imageaffine 支援更複雜的插值方法,例如 IMG_MITCHELL。

// 建立影像資源
$img_path = 'test.jpg';
$img = imagecreatefromstring(file_get_contents($img_path));
// 使用 Mitchell 插值法將影像縮放至 50%
$scale = 0.5;
imagesetinterpolation($img, IMG_MITCHELL);
$img_scaled = imageaffine($img, [0.5, 0, 0, 0.5, 0, 0]);
// 儲存影像
$output = 'test_scaledAffine.png';
imagepng($img_scaled, $output, 9);
echo '<img src="'.$output.'" width="300">';

輔助函式範例

function scaleImgAffine($img, $newWidth, $resized_file='', $interpolation=IMG_MITCHELL)
{
// 如果 $img 是檔案路徑,則建立影像資源
if(!is_resource($img)){
$img = imagecreatefromstring(file_get_contents($img));
}
// 取得原始影像尺寸
$w = imagesx($img);
$h = imagesy($img);

/**
* 建議的插值方法是 'IMG_MITCHELL'
* 為大多數影像類型提供最佳的精度和
* 壓縮效果
* 特別是對於透明度會受影響的 png 檔
* 來自縮小取樣結果的偽影 (artifact)
*/
imagesetinterpolation($img, $interpolation);
/*
* imageaffine 會以非等比例的方式縮放尺寸 –
* 即使是基於正方形的圖像
* 1200x1200 會變成類似 1199x1200 的結果
* – 非常歡迎改進
* 解決方法:將原始寬度和 clip 參數都調整
* 增加 1px 就解決了我的問題
*/
$scale = ($newWidth+1) / $w;
$newHeight = floor($h*$scale);

// 使用仿射矩陣縮放
$resized_affine =
imageaffine(
$img,
[$scale, 0, 0, $scale, 0, 0],
['x' => 0, 'y' => 0, 'width' => $w, 'height' => $h-1]
);
/*
* 'clip' 參數可能會造成誤導,因為它預期的是
* 原始寬度,而不是最終/轉換後的寬度
*/

// 儲存到檔案或返回資源
if($resized_file){
$file_type = pathinfo($resized_file, PATHINFO_EXTENSION );
switch($file_type){
case 'jpg'
case 'jpeg'
// 將 JPG 的透明度扁平化
$tmp_img = imagecreatetruecolor($newWidth, $newHeight );
$bg = imagecolorallocate($tmp_img, 255,255,255);
imagefill($tmp_img, 0, 0, $bg);
imagesavealpha($tmp_img, false);
imagealphablending($tmp_img, true);
imagecopy($tmp_img, $resized_affine, 0, 0, 0, 0, $newWidth, $newHeight );
imagejpeg($tmp_img, $resized_file, 85);
break;
case 'png'
imagepng($resized_affine, $resized_file, 9);
break;
}
}else{
return $resized_affine;
}
}

$img_scaled_affine = scaleImgAffine($img_path, 400, 'test_scaledAffine.jpg', true);

在 GDlib 環境中縮放具有透明度的 png24(實際上是 png31,因為 gd 的 alpha 通道是 7 位元?)時,IMG_MITCHELL 格外先進。最常見的情況是,由於調整大小後出現難以察覺的偽影,使用 png 會導致壓縮效果不佳。

希望我們能看到在基本的 GD 調整大小函數(例如 imagecopyresized 或 imagescale)中,加入更先進的插值方法。
To Top