PHP Conference Japan 2024

imagecreatefromgif

(PHP 4, PHP 5, PHP 7, PHP 8)

imagecreatefromgif从文件或 URL 创建新图像

描述

imagecreatefromgif(字符串 $filename): GdImage|false

imagecreatefromgif() 返回一个图像标识符,表示从给定文件名获得的图像。

警告

将 GIF 文件读取到内存时,图像对象中只返回第一帧。图像大小不一定与 getimagesize() 报告的大小相同。

提示

如果启用了 fopen 封装器,则可以使用 URL 作为此函数的文件名。有关如何指定文件名的更多详细信息,请参阅 fopen()。请参阅 支持的协议和封装器,了解各种封装器的功能、使用方法以及它们可能提供的任何预定义变量的信息。

参数

filename

GIF 图像的路径。

返回值

成功时返回图像对象,错误时返回 false

变更日志

版本 描述
8.0.0 成功时,此函数现在返回一个 GDImage 实例;以前,返回的是 资源

示例

示例 #1 处理加载 GIF 期间发生的错误的示例

<?php
function LoadGif($imgname)
{
/* 尝试打开 */
$im = @imagecreatefromgif($imgname);

/* 查看是否失败 */
if(!$im)
{
/* 创建一个空白图像 */
$im = imagecreatetruecolor (150, 30);
$bgc = imagecolorallocate ($im, 255, 255, 255);
$tc = imagecolorallocate ($im, 0, 0, 0);

imagefilledrectangle ($im, 0, 0, 150, 30, $bgc);

/* 输出错误消息 */
imagestring ($im, 1, 5, 5, 'Error loading ' . $imgname, $tc);
}

return
$im;
}

header('Content-Type: image/gif');

$img = LoadGif('bogus.image');

imagegif($img);
imagedestroy($img);
?>

上面的例子将输出类似于以下内容

Output of example : Example to handle an error during loading of a GIF
添加注释

用户贡献的注释 20 条注释

15
frank at huddler dot com
13 年前
基于此处和其他地方报告的问题更新的 is_ani

<?php
function is_ani($filename) {
if(!(
$fh = @fopen($filename, 'rb')))
return
false;
$count = 0;
//动画 GIF 包含多个“帧”,每个帧都有一个由以下内容组成的标题:
// * 一个静态的 4 字节序列 (\x00\x21\xF9\x04)
// * 4 个可变字节
// * 一个静态的 2 字节序列 (\x00\x2C)(某些变体可能使用 \x00\x21?)

// 我们读取文件直到到达文件结尾,或者我们已经找到
// 至少 2 个帧标题
while(!feof($fh) && $count < 2) {
$chunk = fread($fh, 1024 * 100); //一次读取 100kb
$count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches);
}

fclose($fh);
return
$count > 1;
}
?>
2
moxley at moxleydata dot com
18 年前
我想找出 GIF 是黑白的还是彩色的,但我不想等待 imagecreatefromgif() 解析 200k 文件(大约 1 秒)来获取颜色映射,所以我编写了这个函数来获取 GIF 中所有颜色的列表。希望它对您有用。

<?php
function getGIFColorMap($file)
{
$fp = fopen($file, 'r');
$buf = fread($fp, 1024);
fclose($fp);

// 计算颜色数量
// buf[10] 是颜色信息字节
$color_byte = ord($buf[10]);
$has_color_map = ($color_byte >> 7) & 1;
$color_res = (($color_byte >> 4) & 7) + 1;
$bits_per_pixel = ($color_byte & 7) + 1;
$color_count = 1 << $bits_per_pixel;

if (!
$has_color_map) return null;

// buf[13] 是颜色映射的起始位置
$color_map_index = 13;
$map = array();
for (
$i=0; $i < $color_count; $i++) {
$index = $color_map_index + $i*3;
$r = ord($buf[$index]);
$g = ord($buf[$index + 1]);
$b = ord($buf[$index + 2]);
$map[$i] = array($r, $g, $b);
}
return
$map;
}
?>
2
hdogan at gmail dot com
7年前
刚刚意识到一些动画GIF不包含GCE(图形控制扩展)。这是重构后的is_ani()函数

<?php
/**
* 检测给定文件指针资源或文件名是否是动画GIF。
*
* @param resource|string $file 文件指针资源或文件名
* @return bool
*/
function is_animated_gif($file)
{
$fp = null;

if (
is_string($file)) {
$fp = fopen($file, "rb");
} else {
$fp = $file;

/* 确保我们位于文件的开头 */
fseek($fp, 0);
}

if (
fread($fp, 3) !== "GIF") {
fclose($fp);

return
false;
}

$frames = 0;

while (!
feof($fp) && $frames < 2) {
if (
fread($fp, 1) === "\x00") {
/* 一些动画GIF不包含图形控制扩展(以21 f9开头) */
if (fread($fp, 1) === "\x21" || fread($fp, 2) === "\x21\xf9") {
$frames++;
}
}
}

fclose($fp);

return
$frames > 1;
}
2
ZeBadger
11年前
以100KB块读取文件的is_ani版本是有缺陷的,因为帧结束标记可能被分割在两个块之间——所以要小心。
1
josh [ a t ] OnlineComics [ d o t ] net
21年前
我刚在我的服务器上安装了gif2png,我花了一点时间研究才发现……

passthru("$path/gif2png -O $image_path/image.gif")

如果安全模式开启则无法工作。如果您使用的是共享服务器,它很可能已开启。但是,您不需要关闭安全模式,只需在您的php.ini文件中将safe_mode_exec_dir变量设置为安装gif2png的目录。然后您就可以从您的PHP脚本执行该程序了。
1
unknown at hotmail dot com
22年前
如果GD不支持GIF,并且gif2png不可用,并且您不是管理员,您可以像这样在您的帐户中安装它

创建do.php
<?
global $do;
passthru($do);
?>

然后上传gif2png-2.4.6.tar.gz,解压并安装它
do.php?do=tar+-xvzf+gif2png-2.4.6.tar.gz
do.php?do=gif2png-2.4.5/configure
do.php?do=make

然后删除除gif2png之外的所有文件。不要忘记删除do.php,因为它会造成系统严重的安全漏洞。

尽情享受!

Anze
4
ZeBadger
18 年前
我编写了这段代码来检测gif文件是否为动画。我想我会分享一下 :-)

<?php

function is_ani($filename)
{
$filecontents=file_get_contents($filename);

$str_loc=0;
$count=0;
while (
$count < 2) # 找到第二个帧后就没有继续下去的必要了
{

$where1=strpos($filecontents,"\x00\x21\xF9\x04",$str_loc);
if (
$where1 === FALSE)
{
break;
}
else
{
$str_loc=$where1+1;
$where2=strpos($filecontents,"\x00\x2C",$str_loc);
if (
$where2 === FALSE)
{
break;
}
else
{
if (
$where1+8 == $where2)
{
$count++;
}
$str_loc=$where2+1;
}
}
}

if (
$count > 1)
{
return(
true);

}
else
{
return(
false);
}
}

exec("ls *gif" ,$allfiles);
foreach (
$allfiles as $thisfile)
{
if (
is_ani($thisfile))
{
echo
"$thisfile 是动画<BR>\n";
}
else
{
echo
"$thisfile 不是动画<BR>\n";
}
}
?>

如果您需要,可以很容易地修改它来计算帧数。
1
marianbucur17 at yahoo dot com
8年前
我创建了一个改进版本的frank at huddler dot com的is_ani函数,即使在块之间也能保持得分。希望这有帮助!

/**
* 检查提供的文件是否为动画gif。
*
* @param string $fileName
* @return bool
*/
function isAnimatedGif($fileName)
{
$fh = fopen($fileName, 'rb');

if (!$fh) {
return false;
}

$totalCount = 0;
$chunk = '';

// 动画gif包含多个“帧”,每个帧都有一个由以下组成的头部:
// * 一个静态的4字节序列(\x00\x21\xF9\x04)
// * 4个可变字节
// * 一个静态的2字节序列(\x00\x2C)(某些变体可能使用\x00\x21?)

// 我们读取文件直到到达文件末尾,或者我们已经找到至少2个帧头。
while (!feof($fh) && $totalCount < 2) {
// 每次读取100kb并将其追加到剩余的块中。
$chunk .= fread($fh, 1024 * 100);
$count = preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches);
$totalCount += $count;

// 仅当我们找到至少一个匹配项时才执行此代码块,
// 并且如果我们没有达到所需的匹配项最大数量。
if ($count > 0 && $totalCount < 2) {
// 获取最后一个完整的表达式匹配。
$lastMatch = end($matches[0]);
// 获取最后一个匹配项后的字符串。
$end = strrpos($chunk, $lastMatch) + strlen($lastMatch);
$chunk = substr($chunk, $end);
}
}

fclose($fh);

return $totalCount > 1;
}
1
steve at stevedix dot de
19年前
如果有人在找Yamasoft的GIF转换工具

虽然Yamasoft的网站早已不存在,但代码可以在以下网站找到:
http://www.fpdf.org/phorum/read.php?f=1&i=9418&t=7568#9418

http://www.fpdf.org/download/php-gif.zip

http://phpthumb.sourceforge.net/index.php?source=phpthumb.gif.php
0
simon at shortpixel dot com
6年前
针对当前is_ani函数问题的修复方法是将前一帧的最后20字节添加到下一帧。

<?php
function is_ani($filename) {
if(!(
$fh = @fopen($filename, 'rb')))
return
false;
$count = 0;
//动画GIF包含多个“帧”,每个帧都有一个
//由以下组成的头部:
// * 一个静态的4字节序列 (\x00\x21\xF9\x04)
// * 4个可变字节
// * 一个静态的2字节序列 (\x00\x2C) (某些变体可能使用 \x00\x21 ?)

// 我们读取文件,直到到达文件末尾,或者我们已经找到
// 至少2个帧头
$chunk = false;
while(!
feof($fh) && $count < 2) {
//添加前一个字符串的最后20个字符,以确保搜索模式不会被分割。
$chunk = ($chunk ? substr($chunk, -20) : "") . fread($fh, 1024 * 100); //一次读取100kb
$count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches);
}

fclose($fh);
return
$count > 1;
}
?>
0
Malcolm Murphy
13 年前
希望这可以帮助大家在使用检查动画GIF的函数时避免一些麻烦。

我遇到了一些GIF使用不同的帧分隔符序列\x00\x21,而不是官方标准\x00\x2C。这似乎发生在Photoshop CS5中保存的动画GIF中,但我并不确定问题究竟源于何处。

无论如何,我一直在使用模式
"#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s"
这似乎涵盖了所有GIF,希望能避免误判。

谢谢。
0
匿名
21年前
关于:2002年5月9日 11:31

看起来gif2png不再位于http://www.tuxedo.org/~esr/gif2png/
我在http://www.r1ch.net/stuff/gif2png/找到一个Win32版本。
(对于Unix和源代码,请参阅 http://catb.org/~esr/gif2png/ )

在Win32中,
passthru("gif2png $filename");
如果gif2png.exe在路径中,则可以正常工作。
它会用.png扩展名覆盖文件,所以要小心,或者像上面提到的帖子中一样使用临时文件(无需-O;在命令行中键入“gif2png”以查看选项)。

我在PHP中遇到了超过默认30秒执行时间限制的问题,所以我添加了这行代码
set_time_limit(0); // 一些奇怪的GIF需要很长时间(例如,一个25K的GIF,700x700,大部分是空白的)
0
fezber at yamasoft dot com
21年前
对于只需要GIF读取(而不是写入)支持的用户,但是
1) 不想修改GD库
2) 不想重新编译任何东西
3) 没有安装转换包的权限
4) 任何其他原因……

我创建了一个小的php脚本(大约25KB),允许您从文件中加载GIF(您甚至可以指定动画GIF上的图像索引),然后将其转换为PNG或BMP文件。

举个例子

<?
include("gif.php");

$gif = gif_loadFile("./test.gif");

if($gif) {
// GIF文件成功打开
if(gif_outputAsPNG($gif, "./test.png")) {
// 现在,只需使用ImageCreateFromPng…
$img = ImageCreateFromPng("./test.png");

if($img) {
header("Content-Type: image/jpeg");
ImageJPEG($img);
ImageDestroy($img);
}
else {
// 无法打开PNG
}
}
else {
// 无法将GIF转换为PNG…
}
}
else {
// GIF未加载…
}
?>

当然,它比使用合适的软件和/或库要慢,但对于偶尔读取一些GIF文件非常有用。

您可以在以下位置找到gif.php源代码:http://www.yamasoft.com/php-gif.zip

Fabien
0
Ady at freebsd dot ady dot ro
21年前
FreeBSD用户很幸运,可以通过ports系统在GD2.x中编译GIF支持。
您只需在编译graphics/gd2端口时导出“WITH_LZW=yes”全局变量,例如:

# cd /usr/ports/graphics/gd2
# export WITH_LZW=yes
# make && make install

然后重新编译和(重新)安装www/mod_php4端口,您就可以开始了… :)

祝你好运!
0
senbei at terra dot es
22年前
由于GIF支持已从较新的GD库中删除,您仍然可以通过外部程序使用它。
我在某处读到过使用ImageMagick,我自己也尝试过,但它是一个相当大的包,需要一些服务器上不可用的X11库。
我找到的另一个选项是使用一个小程序“gif2png” http://www.tuxedo.org/~esr/gif2png/
将gif文件转换为png文件。它可在Unix和dos/win32/winnt下运行,并且非常简单。
如果您需要修改用户上传的gif文件以将其保存到您的网站,只需使用此代码:

$path=$_FILES["photo"]["tmp_name"];
passthru("/usr/bin/gif2png -d -O ".$path);
$src_img=imagecreatefrompng( dirname($path)."/".basename($path, ".gif").".png");

这将把gif转换为png并删除gif文件,然后它将使用GDlib打开png,以便您可以对其执行任何操作。
-1
jason at null dot zzz
20年前
感谢Yamasoft提供的gif到png库。它有效!但是,有一个bug。我把第1003行改成这样:

if(isset($this->m_img->m_bTrans) && $this->m_img->m_bTrans && ($nColors > 0)) {

因为我收到了一个m_bTrans未定义的错误。我认为这是因为我的gif没有透明度。在我更新了这一行后,没有问题了。

谢谢!

-j
-1
匿名
21年前
function LoadGif ($imgname) {
$im = @ImageCreateFromGIF ($imgname); /* 尝试打开 */
if (!$im) { /* 查看是否失败 */
$im = ImageCreate (150, 30); /* 创建一个空白图像 */
$bgc = ImageColorAllocate ($im, 255, 255, 255);
$tc = ImageColorAllocate ($im, 0, 0, 0);
ImageFilledRectangle ($im, 0, 0, 150, 30, $bgc);
/* 输出错误消息 */
ImageString($im, 1, 5, 5, "Error loading $imgname", $tc);
}
return $im;
}
-1
geoffrey at poulet dot org
21年前
经过数小时的搜索,我终于找到一个可以将JPG转换为GIF的程序。
IJG - The Independent JPEG Group的JPEG软件
版本6支持GIF(使用LZW进行读取和写入)
版本6b支持GIF(仅写入,不使用LZW)

文件名是:jpegsrc.v6.tar.gz
-1
匿名
11年前
使用以下脚本来生成(保留)动画GIF,它修复了GD库动画问题。
http://www.gdenhancer.com/
-2
anthony dot atkins at vt dot edu
24年前
<?php

function myImageCreateFromGif($file_or_url) {

$dummy_file = "/tmp/dummy.gif";

# 如果这是一个URL,使用fopen获取文件数据,然后
# 保存到一个临时文件
if (preg_match("/(http|ftp):\/\//i", $file_or_url)) {
# 使用fopen打开文件,它支持远程URL
$input = fopen($file_or_url, "rb");

# 读取文件内容
# 将接受最多10MB的文件,但可能会在此之前获得
# EOF,我们必须这样做,因为
# filesize不能用于URL。唉。
$image_data = fread($input, 10000000);

fclose($input);

# 将内容写入临时文件
$output = fopen("$dummy_file", "wb");
fwrite($output, $image_data);
fclose($output);

# 从临时文件创建GIF
$image = ImageCreateFromGif($dummy_file);

# 删除临时文件
unlink($dummy_file);

}

# 如果它不是URL,我们可以直接打开图像
else {
$image = ImageCreateFromGif($file_or_url);
}

if (
$image) { return $image; }
else { return
0; }
}


if (!
$url) { $url = "http://scholar.lib.vt.edu/images/cornholio.gif";}
$image = myImageCreateFromGif($url);

if (
$image == "" || $image == 0) {
print
"<p>没有返回图像数据...</p>\n";
}
else {
header("Content-Type: image/gif\n\n");
ImageGif($image);
}

?>
To Top