PHP Conference Japan 2024

imageaffine

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

imageaffine返回包含使用可选剪裁区域的仿射变换源图像的图像

描述

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 现在可以为空。
8.0.0 成功时,此函数现在返回一个 GDImage 实例;之前,返回的是一个 resource
添加注释

用户贡献的注释 5 条注释

abc at ed48 dot com
10 年前
仿射是涉及矩阵的几何变换操作,涵盖 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) 缩放,

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

重新映射方程:

x' = Mx + 0y + 0 = Mx

y' = 0x + Ny = 0 = Ny

每个点将根据 M 和 N(负值或正值)拉伸或压缩其路径,水平或垂直。

d) 沿 x 轴错切,

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

重新映射方程:

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

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

沿 y 轴错切,

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

重新映射方程:

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

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

e) 顺时针旋转,

$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 Ø

逆时针旋转,

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

重新映射方程:

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

y' = x sin Ø + y cos Ø = 0 = y sin Ø - x cos Ø
abc at ed48 dot com
10 年前
这是一个示例,每次执行时都会执行特定的处理

<?php

if (!function_exists('imageaffine'))
{
echo
'此版本的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) 缩放,

$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,它会受到
* 伪影下采样结果的影响
*/
imagesetinterpolation($img, $interpolation);
/*
* imageaffine将以变形的方式缩放尺寸 -
* 即使使用基于正方形的图像
* 1200x1200将得到类似1199x1200的结果
* - 非常欢迎改进
* 变通方法:调整原始宽度和裁剪参数
* 为我解决了这个问题
*/
$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);

IMG_MITCHELL在GDlib环境中(...实际上是由于gds alpha 7bit通道导致的png31?)缩放具有透明度的png24时尤其先进。最常见的是,由于调整大小后出现的难以察觉的伪影,您将遇到使用png的压缩效果不佳的问题。

希望我们能在基本的GD调整大小函数(如imagecopyresized或imagescale)中看到更高级的插值方法的实现。
To Top