摘要
本文记录了服务器端(php,java)直接输出图像的一种方法。可用于论坛签名实时显示IP及时间。
php版图像效果:
Key Words: 动态输出图像, IP输出到图像,
引言
今天整理虚拟主机空间里的文件时,发现根目录有一个ip.php文件,一时忘了是啥,一看内容才发现是早些时候写的php输出图像的小程序片段。
最早是在Dospy.com塞班论坛的用户[变号]的论坛签名上看到过。(2012年)可以在[这里]查看论坛签名效果。好吧其实就是一个图像:

PHP版
于是可能在去年某个时候,我上塞班论坛时看到了变号君的签名,就想着用php试试能不能实现。
下面是当时通过搜索互联网,写出来的代码:
<?php
header("Content-type: image/png");
//创建图像http://www.php.net/imagecreate
$im = imagecreate(130,30);
//http://www.php.net/ImageColorAllocate
$background_color = ImageColorAllocate ($im, 255, 255, 255);
unset($ip);
if($_SERVER['HTTP_CLIENT_IP']){
$ip=$_SERVER['HTTP_CLIENT_IP'];
} else if($_SERVER['HTTP_X_FORWARDED_FOR']){
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
} else{
$ip=$_SERVER['REMOTE_ADDR'];
}
//设置颜色http://www.php.net/imagecolorallocate
$col = imagecolorallocate($im, 0, 51, 102);
//画字符串http://www.php.net/imagestring
imagestring($im, 3, 5, 1, $ip , $col);
$ip="By Youth.Lin";
imagestring($im, 3, 15, 15, $ip , $col);
//输出图像http://www.php.net/imagegif
imagegif($im);
imagedestroy($im);
?>
出处已不可考,或许是我从网上东拼西凑出来的。直接看代码也挺直观的。
缺点:文件名是.php后缀,而不是图像的后缀。
2016-01-28更新:
使用.htaccess的URL重写规则,使得访问ip.png实际上是访问ip.php第一步:开启Apache服务器的重写模块
打开 Apache 的配置文件
httpd.conf文件,找到下面一行:
#LoadModule rewrite_module modules/mod_rewrite.so
去掉#号注释。第二步:新建.htaccess文件
Linux可以直接新建,Windows需要使用记事本的另存为,类型选择所有文件,一般编码选择UTF8(不能直接重命名)。
第三步:编写伪静态规则
<IfModule mod_rewrite.c> RewriteEngine on RewriteRule ^ip\.png$ /ip.php [L] </IfModule>
^ip\.png$^脱帽符号表示匹配开头, \.点号使用反斜杠转义 $美元符号表示匹配结尾。 [L]表示停止处理接下来的规则参见
Java版
正好目前在学Java Web, 于是今天我打算用java来也试试实现一下。
用JSP的Servlet 匹配(mapping) URL 这样就可以是任意文件名了。
首先我们需要设置输出类型是图像,然后创建一幅图像,把IP及日期画在图像上,最后输出图像即可。(下方右上角可以选择新窗口看代码)
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ImageConsumer;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by lin on 2016-01-27-027.
*/
@WebServlet(name = "IPServlet", value = "/ip.png")
public class IPServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置文件类型
response.setContentType("image/png");
//获取参数
String w = request.getParameter("w");
String h = request.getParameter("h");
String s = request.getParameter("s");
String c = request.getParameter("c");
int width = 300, height = 60, size = 18;
if (s != null) {
try {//使用try-catch块防止出错
size = Integer.parseInt(s);
} catch (Exception e) {
}
}
Font font = new Font("微软雅黑", Font.PLAIN, size);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D gd = img.createGraphics();
gd.setFont(font);
String ip = getIp(request);
//ip = "1234::1234::1234::1234::1234::1234::1234::1234";
Date date = new Date();
//Java String和Date的转换
//http://www.cnblogs.com/bmbm/archive/2011/12/06/2342264.html
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss (z) E");
String d = sdf.format(date);
String me = "Powered By Youth.霖";
double ipW = getWidth(font, ip, gd.getFontRenderContext()),
ipH = getHeight(font, ip, gd.getFontRenderContext()),
dateW = getWidth(font, d, gd.getFontRenderContext()),
dateH = getHeight(font, d, gd.getFontRenderContext()),
meW = getWidth(font, me, gd.getFontRenderContext()),
meH = getHeight(font, me, gd.getFontRenderContext());
width = (int) ipW;
if (dateW > width) width = (int) dateW;
if (meW > width) width = (int) meW;
width += 2;//留一点点边距
height = (int) (ipH + dateH + meH + 2);
if (w != null) {
width = Integer.parseInt(w);
}
if (h != null) {
height = Integer.parseInt(h);
}
//Java生成透明背景图片
//http://snkcxy.iteye.com/blog/1872229
img = gd.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
gd = img.createGraphics();
gd.setFont(font);
//随机颜色
Color color = new Color(
(new Double(Math.random() * 128)).intValue() + 128,
(new Double(Math.random() * 128)).intValue() + 128,
(new Double(Math.random() * 128)).intValue() + 128);
if (c != null) {
try {
//Java中颜色的String和Color对象之间的互相转换
//http://winhack.iteye.com/blog/1843781
color = new Color(Integer.parseInt(c, 16));
} catch (Exception e) {
}
}
gd.setColor(color);
//画矩形框
gd.drawRect(0, 0, width - 1, height - 1);
//画字符串drawString(string,x,y)
//左起x像素,从上往下y像素这个(x,y)是字符串的左下角坐标(不是左上角)
gd.drawString(d, (float) ((width - dateW) / 2), (float) (height / 3));
gd.drawString(ip, (float) ((width - ipW) / 2), (float) (height / 3 * 2));
gd.drawString(me, (float) (width - meW) / 2, (float) (height - 3));
ImageIO.write(img, "png", response.getOutputStream());
}
/**
* //计算字符串的像素长度与高度
* //http://blog.chinaunix.net/uid-79084-id-97205.html
* Graphics2D g = (Graphics2D)Toolkit.getDefaultToolkit().getImage("imgname").getGraphics();
* //设置大字体
* Font font = new Font("楷体", Font.ITALIC | Font.BOLD, 72);
* g.setFont(font);
* FontRenderContext context = g.getFontRenderContext();
* //获取字体的像素范围对象
* Rectangle2D stringBounds = font.getStringBounds("text", context);
* double fontWidth = stringBounds.getWidth();
*/
private double getWidth(Font f, String str, FontRenderContext context) {
return f.getStringBounds(str, context).getWidth();
}
private double getHeight(Font f, String s, FontRenderContext c) {
return f.getStringBounds(s, c).getHeight();
}
//JSP 获取真实IP地址的代码
//http://www.jb51.net/article/21272.htm
public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
在浏览器输入 http://localhost:8080/Project-Name/ip.png 就能看到效果了。
类名使用了注解配置URL mapping,就不用到web.xml里配置了。先使用预定义的宽高创建了图像,然后设置画笔的字体,这样之后就可以计算字符串在这个字体下的像素大小了。生成重新透明背景的图像,使用相同的字体设置画笔,再设置颜色,把字符串画上图像,最后输出图像。
参考
见代码中注释的链接。
声明
- 本作品采用署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。除非特别注明, 霖博客文章均为原创。
- 转载请保留本文(《服务器端动态输出图像》)链接地址: https://youthlin.com/?p=1161
- 订阅本站:https://youthlin.com/feed/

“服务器端动态输出图像”上的7条回复
你的样式应该改下了
嗯?什么样式
这个在静态、动态验证码的应用倒是相当广泛。
在php里header定位到某个图像也可以实现随机图片。
不知道伪静态和header一块用会有啥效果,准备试试……
这个功能好厉害,要是能用作头像的话就好玩了
应该也可以做头像吧,改主题(然而我并不会
貌似我曾也用PHP试过给QQ空间插的图片做动态改变。记得是得加载PHP的什么GD画图的库。
我想到一个,现在浏览器支持SVG图像,所以我想,可以支持用代码输出XML代码浏览器解析成失量图像,对于你此文的输出IP、时间这类内容真是再合适不过了。
嗯嗯好主意(●’◡’●) 不过并没有研究过SVG ╮(╯-╰)╭