摘要
本文记录了服务器端(php,java)直接输出图像的一种方法。可用于论坛签名实时显示IP及时间。
java版效果:
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 ╮(╯-╰)╭