使用 php GD 进行单像素操作

2023-12-10

首先我指的是之前的一个问题更改每个像素的图像并保存到数据库

我发现 html5 canvas 不适合,因为很难保守源图像的秘密。这就是为什么我尝试使用 PHP GD 库来实现我的目标。我从未使用过这个库,所以我遇到了一些困难。我想我需要以下功能

  • imagecreatetruecolor 用于在浏览器中创建图像
  • imagecolorallocate 用于从源图像返回 RGB
  • imagesetpixel 用于绘制随机像素

    $x = 200; //width of image
    $y = 200; //height of image
    
    $gd = imagecreatetruecolor ($x, $y);
     $color = imagecolorallocate($gd, $r, $g, $b) //not sure how to retrieve the rgb from the source image
    
    Then I need a function for drawing random pixels with imagesetpixel.
    imagesetpixel($gd, $posx,$posy, $color); // not sure how to retrieve the x and y position of each pixel.
    

我不是 PHP 的明星,这就是为什么我的搜索一直停留在这些 GD 函数上。希望你能给我一个创业机会


随机函数的“特征”之一是它是伪随机的,即,给定相同的种子,它将始终输出相同的序列。

所以你可以为每个“图像”存储:

sourcefile   - the name of the source image
seed         - integer, maybe the start time of this sequence
position     - number of pixels that need to be shown, or maybe % completion

所以说你要输出图像$sourcefile有种子$seed and $position可见像素的百分比。你甚至不需要使用 alpha:

// Load image
$src = imageCreateFromPNG($sourcefile); // Assume image is PNG

// Create work image
$new = imageCreateTrueColor(ImageSX($src), ImageSY($src)); // new image of same size

mt_srand($seed); // Seed the Mersenne Twister generator

// Number of pixels to set: $position = 0: NONE, $position = 100: ALL
$pixels = round($position*imageSX($src)*imageSY($src)/100);

// Now we have a problem: if we do $pixels attempts, mt_rand might sometimes
// return the same pixel again. So we end up setting less than $pixels pixels.

// So we do this the expensive way, saving an array of yet-to-be-used pixels.
$max     = ImageSX($src)*ImageSY($src);
$pixelid = array();
for ($i = 0; $i < $max; $i++)
    $pixelid[] = $i;

$W  = ImageSX($src);

while($pixels--)
{
    // Extract one pixel
    $chosen = $pixelid[$idx = mt_rand(0, $pixels)];

    array_splice ($pixelid, $idx, 1); // Remove extracted pixel from array

    $x = $chosen % $W;
    $y = ($chosen - $x)/ $W;

    $rgb = imagecolorat($src, $x, $y);
    $pix = imagecolorsforindex($src, $rgb);
    $rgb = imageColorAllocate($new, $pix['red'], $pix['green'], $pix['blue']);
    imageSetPixel($new, $x, $y, $rgb);
}

ImageDestroy($src);

// $new has now exactly $pixels set to the same pixels of $src,
// the rest are undefined (you can fill $new with white beforehand...)
Header("Content-Type: image/png");
ImagePNG($new);

变化

您可以涂掉“已用”像素,而不是拼接数组,即使这不会给出均匀分布:

$cnt = count($pixelid);

while($pixels--)
{
    // Extract one pixel
    $idx = mt_rand(0, $cnt);
    // If the extracted pixel is null, find next pixel that is unextracted
    // and if there are none, restart from the beginning of the array.
    while (-1 == ($chosen = $pixelid[$idx]))
        if ($cnt == ++$idx)
            $idx = 0;
    $chosen = $pixelid[$idx];
    $pixelid[$idx] = -1;

或者你可以只是...重试。但当图像几乎完成时,这可能会很昂贵。

$cnt = count($pixelid);
while($pixels--)
{
    // Extract one pixel
    for ($idx = mt_rand(0, $cnt); $pixelid[$idx] != -1; $idx = mt_rand(0, $cnt))
        ;
    $chosen = $pixelid[$idx];
    $pixelid[$idx] = -1;

如果您不关心图像总是以不同的方式重建,您可以使用array_shuffle()代替mt_rand(),并且在每次迭代中我从中提取第 i 个像素$pixelid.

最后一个选择是重新实现array_shuffle() using mt_rand如手册页中所述(请参阅 leethost dot com 的 tim 的示例):

function array_new_shuffle(&$items, $seed)
{
    mt_srand($seed);
    for ($i = count($items) - 1; $i > 0; $i--)
    {
        $j = @mt_rand(0, $i);
        list($items[$i], $items[$j]) = array($items[$j], $items[$i]);
    }
}

所以你会打电话array_new_shuffle()反对$pixelid using $seed,然后按顺序从打乱后的数组中提取元素:

for ($idx = 0; $idx < $pixels; $idx++)
{
    $chosen = $pixelid[$idx];
    ...

大图像

对于大图像,处理数组的成本太高,而且会耗尽内存。所以,为了避免mt_rand()重复击中相同的像素(当图像完成 99% 时,这可能会产生真正的问题,因此随机击中仍然可行的 1% 像素之一的概率当然是 1%),此 hack 使用另一张图像作为指数。

这将“数组”限制为 2^24 个条目,即边长为 2^12 或 4096 像素的图像。

节省的内存是巨大的:每个图像像素现在占用 16 个字节,而不是大约 176 个字节(在我的 Linux 64 位机器上)。这意味着 1024x1024 像素的图像只需要大约 17M 的 RAM。

在我的系统上,该脚本每秒处理大约 180k 像素(1024x1024 图像在 7.4 秒内完成 100% 处理,其中大约需要 2 秒用于图像加载和设置)。

$seed = 0;
$position = 2;
$sourcefile = '/home/lserni/Lena19721024-filtered.png';

mt_srand($seed); // Seed the Mersenne Twister generator

// Load image
    $src = ImageCreateTrueColor(512,512);
// $src = imageCreateFromPNG($sourcefile); // Assume image is PNG
$W  = ImageSX($src);
$H  = ImageSY($src);

// Total number of pixels
$size   = $W*$H;

if (($W > 4095) || ($H > 4095))
   die("Image too big");

// Create work image
$new = imageCreateTrueColor($W, $H); // new image of same size

/*
if ($position > 50)
{
    $position = 100-$position;
    $tmp = $src;
    $src = $new;
    $new = $tmp;
}
*/

// Number of pixels to set: $position = 0: NONE, $position = 100: ALL
$pixels = round($position*$size/100.0);

// Create a temporary buffer image of the same size
$fix = imageCreateTrueColor($W, $H);
for ($i = 0; $i < $size; $i++)
{
    $b = $i & 0xFF;
    $g = ($i >> 8) & 0xFF;
    $r = ($i >> 16) & 0xFF;
    imageSetPixel($fix, $i % $W, floor($i / $W), imageColorAllocate($fix, $r, $g, $b));
}

while($pixels--)
{
    // Recover one of the available pixel indexes
    $idx = mt_rand(0, $size--);

    // Recover index from image
    $y   = floor($idx / $W);
    $x   = $idx % $W;
    $idx = imageColorAt($fix, $x, $y);
    $lst = imageColorAt($fix, $size % $W, floor($size / $W));
    $b   = $lst & 0xff; $lst >>= 8;
    $g   = $lst & 0xff; $lst >>= 8;
    $r   = $lst & 0xff;
    imageSetPixel($fix, $x, $y, imageColorAllocate($fix, $r, $g, $b));

    // Whew. Now recover true x and y from new $idx
    $y   = floor($idx / $W);
    $x   = $idx % $W;

    $rgb = imagecolorat($src, $x, $y);
    $pix = imagecolorsforindex($src, $rgb);
    $rgb = imageColorAllocate($new, $pix['red'], $pix['green'], $pix['blue']);
    imageSetPixel($new, $x, $y, $rgb);
}
ImageDestroy($src);

// $new has now exactly $pixels set to the same pixels of $src,
// the rest are undefined (you can fill $new with white beforehand...)
// die("Memory: " . memory_get_peak_usage());
Header("Content-Type: image/png");
ImagePNG($new);

优化

您会注意到上面代码中的注释部分。如果发生这样的情况$position超过 50%,比如说 70%,创建一个空图像并将 70% 的像素从好图像复制到空图像是没有意义的。将空图像中 30% 的空像素复制到好图像中,将其“涂黑”,更有意义。这可以通过简单地交换来完成$new and $src和调整$position。我还没有真正彻底地测试过这段代码;这就是我留下评论的原因。但欢迎您尝试一下。

执行

使用 PRNG 的优点是你不需要保存任何图像, 但只有seed and position- 通常总共八个字节。

如果人 A 接收位置 1,并要求接收最多 5 个位置(即图像可见的 5%),并且您保存种子和这个值 5,并将其用于人 B,那么人 B 将看到相同的 5 A 得到的百分比。

除原始图像外,所有图像均未保存或加载。

如果您可以在 $_GET 参数中传递种子和位置,则可以在浏览器中显示不同阶段的图像(例如image.php?seed=12345678&position=5将显示设置了 5% 像素的图像。当然,您还可以指定像素数而不是百分比)。

这有效只要像素是随机选择的:如果 A 到达choose他或她想要的确切像素,然后这种方法无效并且您需要保存各个像素位置,这可以通过多种方式完成:使用以二进制格式保存一对 (x,y) 的平面文件,或保存整个图像。后一种方法更容易理解,并且每一步都需要存储整个图像,因此如果这是一个游戏并且您想“重玩”它,则可能需要巨大的磁盘空间。第一种方法可能合理地需要每个像素 6 个字节,即相当于具有相同高度且宽度是原始图像两倍的图像,或者每个像素少至 4 个字节。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 php GD 进行单像素操作 的相关文章

  • 由于未定义符号,PECL solr 未加载:curl_easy_getinfo

    我正在尝试加载 PECL solr 扩展 我尝试使用 pecl install solr 并下载并使用 phpize configure make 来安装它 在这两种情况下 扩展安装时都没有错误 但在 apache 重新启动后 或在命令行上
  • PHP 文件上传帮助

    div align center div 这是我的代码
  • 压缩 zend Framework 2 的 html 输出

    我目前正在 PHP 5 4 4 上使用 Zend Framework 2 beta 开发个人 web 应用程序以用于自学目的 我想知道是否可以在 html 输出发送到浏览器之前拦截它 以便通过删除所有不必要的空格来缩小它 我怎样才能在ZF2
  • Laravel 5.1 中的VerifyCsrfToken.php 第 53 行:(Firefox 浏览器)中出现 TokenMismatchException?

    我试图找出为什么会出现这个错误 即使它是全新安装的 我在我的项目中遇到了这个错误 所以我用谷歌搜索 没有一个答案对我有用 所以我创建了新项目并复制了所有控制器 视图和模型 几个小时后工作正常 再次出现令牌不匹配错误 为什么在 laravel
  • 覆盖供应商自动加载编辑器

    有没有办法让您创建的自动加载文件在调用供应商自动加载之前运行 我们似乎遇到了 SimpleSAML 的自动加载覆盖我们创建的自动加载文件之一的问题 我是 Composer 的新手 似乎无法在网上找到任何解决方案 我尝试将我们的自动加载文件包
  • 具有动态表单名称的 form_widget

    在我的 Twig 模板中 我有一个 FOR 循环 它创建多个表单 如下所示 for thing in things set form id myform thing Id set form name attribute form myfor
  • strlen()==0 和empty()之间有区别吗?

    我正在查看其他人编写的一些表单验证代码 我看到了这个 strlen 0 当测试表单变量是否为空时 我使用empty 功能 一种方法比另一种方法更好吗 它们在功能上等效吗 strlen是获取字符串中的字符数 同时empty用于测试变量是否为空
  • 使用 php 更改白天和黑夜的背景?

    我正在制作一个 tumblr 页面 我的 html 页面有两种不同的背景 我希望白天背景从早上 7 点到晚上 8 点显示 夜间背景从晚上 8 点到早上 7 点显示 我决定用 php 来做这件事 但对于 php 来说我是个新手 我的朋友给我发
  • php - 我应该加密电子邮件地址吗?

    当用户注册时 我应该将他们的电子邮件按原样存储在数据库中还是对其进行哈希处理 我希望稍后能够解密 那么我应该使用 md5 吗 谢谢你 No md5 is 单向哈希函数 http en wikipedia org wiki Cryptogra
  • 运行PHPUnit测试时如何避免内部调用函数?以及如何设置内部性能的模拟数据?

    我有一个类 Receipt php
  • PHP 中的 NOW() 函数

    是否有 PHP 函数以与 MySQL 函数相同的格式返回日期和时间NOW 我知道如何使用date 但我想问是否有专门用于此的功能 例如 返回 2009 12 01 00 00 00 您可以使用date https www php net m
  • PHP中如何识别服务器IP地址

    PHP中如何识别服务器IP地址 对于服务器 ip 来说是这样的 SERVER SERVER ADDR 这是港口的 SERVER SERVER PORT
  • 使用 DOJO 自动完成文本框

    我正在寻找一种使用 DOJO 进行文本框自动建议的简单方法 我将查询的数据库表 使用 PHP 脚本 以 JSON 形式返回 有超过 100 000 条记录 因此这确实不应该采用 FilteringSelect 或 ComboBox 的形式
  • 如何在没有引用的情况下复制对象?

    PHP5 OOP 有据可查对象通过引用传递 http php net manual en language oop5 references php默认情况下 如果这是默认的 在我看来 有一种非默认的方式可以在没有参考的情况下进行复制 如何
  • 将数组拆分为特定数量的块

    我知道array chunk 允许将数组拆分为多个块 但块的数量根据元素的数量而变化 我需要的是始终将数组拆分为特定数量的数组 例如 4 个数组 以下代码将数组分为 3 个块 两个块各有 2 个元素 1 个块有 1 个元素 我想要的是将数组
  • 如何在php中使用preg添加html属性

    我正在寻找在 php 中编写一个脚本来扫描 html 文档并根据它找到的内容向元素添加新标记 更具体地说 我是扫描文档并为每个元素搜索CSS标记 float right left 如果找到它 它会添加align right left 基于它
  • 将 MySQL 结果作为 PHP 数组

    mysql 表 config name config value allow autologin 1 allow md5 0 当前的 php 代码 sth mysql query SELECT rows array while r mysq
  • Zend Framework Zend_Form 装饰器: 位于按钮元素内部?

    我有一个像这样创建的按钮元素 submit new Zend Form Element Button submit submit gt setLabel My Button submit gt setDecorators array Vie
  • mysqli bind_param 中的 NULL 是什么类型?

    我正在尝试将参数绑定到 INSERT INTO MySQLi 准备好的语句 如果该变量存在 否则插入 null 然后我知道 type variable i corresponding variable has type integer d
  • 文件修改时间检查的成本

    对于Linux下包含少量字节的文件 我只需要处理自上次处理以来发生更改的时间 我通过调用 PHP 检查文件是否被更改clearstatcache filemtime 定期 由于整个文件总是很小 因此删除对 filemtime 的调用并通过将

随机推荐

  • 如何从资产预填充房间数据库?

    我正在使用 SQLiteOpenHelper 类编写一个应用程序 并决定使用 Room 重新构建它并实现 MVVM 模式 以获得一些额外的可用性 我的第一个问题是 Room 需要使用 createFromAsset database dat
  • iOS UIWebView 中的 Javascript console.log()

    使用 UIWebView 编写 iPhone iPad 应用程序时 控制台不可见 这个优秀的答案展示了如何捕获错误 但我也想使用 console log 今天咨询了一位尊敬的同事后 他提醒我注意 Safari 开发人员工具包 以及如何将其连
  • 在 Django 中创建模板时迭代模型属性

    我在 Google App Engine 中使用 Django 如果我有课的话 class Person first name StringProperty last name StringProperty 我有一个实例 其中 Person
  • 更新 Bigquery 表架构

    我在 BQ 中已有一个表 其中填充了数据 我想重命名表的标题 更新架构 我正在使用命令行工具 假设这是类似的事情 bq update schema Col1 STRING Col2 STRING data set Table Name 但我
  • Meteor.js - 暂时阻止模板重新渲染(禁用反应性)

    我的应用程序中有一个页面 其中包含用户正在处理的项目列表 当他们想要添加新项目时 我会显示一个模式表单来获取项目名称 如果他们单击 确定 我将创建项目并使用 Meteor Router 重定向到 project 新项目 id 但是 就在重定
  • 使用 Autobahn WebSocket 进行试用单元测试

    我正在尝试为使用 Autobahn 的应用程序编写单元测试 我想测试我的控制器 它从协议获取接收的数据 解析它并对其做出反应 但是当我的测试达到应该断开协议的程度时 self sendClose 然后它会引发错误 exceptions At
  • WebBrowser 控件:检测导航失败

    我托管一个 web 浏览器控件 通常加载外部文档 然后使用 HTML DOM 进行一些修改 我们还使用虚假协议嵌入自定义应用程序链接 例如在中捕获和处理的 关闭此 BeforeNavigate2 当链接目标拼写错误时 例如 spp Clos
  • 为什么经常建议不要使用rails default_scope?

    到处 on the网上有人提到使用railsdefault scope是一个坏主意 并且热门default scopestackoverflow 上有关于如何覆盖它的信息 这感觉很混乱 值得一个明确的问题 我认为 那么 为什么要使用轨道de
  • ExtractYear 和 ExtractMonth 在 Django 中返回 None

    我正在尝试根据年 月和列值对数据进行分组 查询是 FeedbackData objects annotate year ExtractYear created month ExtractMonth created values year m
  • 模块初始化错误:无法在 AWS lambda 上加载本机模块“Crypto.Cipher._raw_ecb”

    我正在使用 AWS lambda 提供服务 我正在使用 PyCryptodome 进行加密和解密 我可以在本地测试我的应用程序 但是当我上传到 AWS lambda 进行解密时 我得到的错误是 模块初始化错误 无法加载本机模块 Crypto
  • 禁用内存地址的随机化

    我正在尝试调试使用大量指针的二进制文件 有时 为了快速查看输出以找出错误 我会打印出对象的地址及其相应的值 但是 对象地址是随机的 这违背了快速检查的目的 有没有办法暂时 永久禁用此功能 以便每次运行程序时都获得相同的值 哎呀 操作系统是L
  • C# List 添加继承的项目 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 假设我们有 2 个班级 第一个是人 using System using System Collections Generic using System Linq using S
  • 如何将符号链接移至垃圾箱?

    我没有看到任何选项FSPathMoveObjectToTrashSync 不跟踪链接的功能 这是我尝试过的 创建链接和文件 21 32 41 tmp touch my file 21 32 45 tmp ln s my file my li
  • 从 Java 使用 SharePoint Web 服务时 NTLM 失败?

    我有一个 Java 客户端 它使用使用 JDK 6 的 JAX WS 实现编写的 SharePoint 2010 标准 Web 服务 sitedata asmx permissions asmx 等 到目前为止 身份验证是使用自定义的 NT
  • OpenGL 3.0 帧缓冲区输出到附件而无需我指定?

    好的 我有一个带有一堆附件的帧缓冲区 附件是颜色 绽放 速度和深度 我首先使用以下代码将帧缓冲区清除为我选择的值 Clear Color Buffer float colorDefaultValue 4 0 5 0 5 0 5 1 0 gl
  • 连接公式中的粗体文本

    我希望在使用连接公式时能够将句子中的一两个特定单词加粗 一个例子如下所示 第一句话使用连接公式 第二句话是手动输入并格式化的 有没有办法在连接公式中进行这种格式设置 而不必每次都手动执行 请注意 这只是一个示例 我可能需要使用它在不同的句子
  • 使用 Keras/Tensorflow 模拟 PyTorch 切片分配的最佳方法

    我试图模仿下面 PyTorch 中完成的操作 vol Variable torch FloatTensor A B 2 C D E zero cuda for i in range C if i gt 0 vol B i i input0
  • 如何在 JFreeChart 中添加水平滚动条?

    我可以添加一个水平滚动条来查看以前的数据吗 JFreechart 我正在使用折线图绘制动态图并一次在 x 轴上显示 10 个值 我想使用水平滚动条查看该图 如何设置滚动条的值来查看以前的数据 有多种选择 添加您的ChartPanel to
  • 为什么 Option::map 的参数存在生命周期问题?

    我将一个字符串放入Option并尝试对其进行映射 例如修剪字符串 fn main let s i want to be trimmed to string let s opt Some s let x s opt map z z trim
  • 使用 php GD 进行单像素操作

    首先我指的是之前的一个问题更改每个像素的图像并保存到数据库 我发现 html5 canvas 不适合 因为很难保守源图像的秘密 这就是为什么我尝试使用 PHP GD 库来实现我的目标 我从未使用过这个库 所以我遇到了一些困难 我想我需要以下