前面介绍了一篇java实现图片灰度化处理的小demo,接下来再介绍一个有意思的东西,将一个图片转换成字符图片。
借助前面图片灰度化处理的知识点,若我们希望将一张图片转成字符图片,同样可以遍历每个像素点,然后将像素点由具体的字符来替换,从而实现字符化处理。
基于上面这个思路,具体的实现就很清晰了。
@TestpublicvoidtestRender()throwsIOException{Stringfile="http://i0.download.fd.52shubiao.com/t_960x600/g1/M00/10/17/oYYBAFWvR5-IeXHuAAd5kPb8eSgAACm0QF50xIAB3mo414.jpg";//从网络上下载图片BufferedImageimg=ImageIO.read(FileReadUtil.getStreamByFileName(file));intw=img.getWidth(),h=img.getHeight();//创建新的字符图片画板BufferedImagegray=newBufferedImage(w,h,img.getType());Graphics2Dg2d=gray.createGraphics();g2d.setColor(null);g2d.fillRect(0,0,w,h);Fontfont=newFont("宋体",Font.BOLD,1);g2d.setFont(font);for(intx=0;x<w;x++){for(inty=0;y<h;y++){g2d.setColor(ColorUtil.int2color(img.getRGB(x,y)));g2d.drawString("灰",x,y);}}g2d.dispose();System.out.printf("渲染完成");}
注意上面的实现,在会字符的时候,先取出源像素点的色彩,然后重新设置给g2d,这个int转color也比较简单,实现如下
publicstaticColorint2color(intcolor){inta=(0xff000000&color)>>>24;intr=(0x00ff0000&color)>>16;intg=(0x0000ff00&color)>>8;intb=(0x000000ff&color);returnnewColor(r,g,b,a);}
这样就实现了一个基础版的转字符图了,实际跑一下看看效果
这下尴尬了,输出的并不是我们预期的字符图,那么问题出在哪呢?
仔细看上面的文字大小为1,文字太小,导致即使是有字符组件的图,最终肉眼看起来和原图也没啥区别
那么我们就试一下将这个文字搞大点,将n*n个像素点作为一个文字渲染区域,这样我们需要调整一下遍历的步长;其次就是这个区域的颜色怎么定
直接取均值
/***求取多个颜色的平均值**@return*/ColorgetAverage(BufferedImageimage,intx,inty,intw,inth){intred=0;intgreen=0;intblue=0;intsize=0;for(inti=y;(i<h+y)&&(i<image.getHeight());i++){for(intj=x;(j<w+x)&&(j<image.getWidth());j++){intcolor=image.getRGB(j,i);red+=((color&0xff0000)>>16);green+=((color&0xff00)>>8);blue+=(color&0x0000ff);++size;}}red=Math.round(red/(float)size);green=Math.round(green/(float)size);blue=Math.round(blue/(float)size);returnnewColor(red,green,blue);}
另外的就是改一下遍历的步长
@TestpublicvoidtestRender()throwsIOException{Stringfile="http://i0.download.fd.52shubiao.com/t_960x600/g1/M00/10/17/oYYBAFWvR5-IeXHuAAd5kPb8eSgAACm0QF50xIAB3mo414.jpg";//从网络上下载图片BufferedImageimg=ImageIO.read(FileReadUtil.getStreamByFileName(file));intw=img.getWidth(),h=img.getHeight();//创建新的灰度图片画板BufferedImagegray=newBufferedImage(w,h,img.getType());Graphics2Dg2d=gray.createGraphics();g2d.setColor(null);g2d.fillRect(0,0,w,h);intsize=12;Fontfont=newFont("宋体",Font.BOLD,size);g2d.setFont(font);for(intx=0;x<w;x+=size){for(inty=0;y<h;y+=size){ColoravgColor=getAverage(img,x,y,size,size);g2d.setColor(avgColor);g2d.drawString("灰",x,y);}}g2d.dispose();System.out.printf("渲染完成");}
再次执行之后结果如下,实现了我们的预期效果
最后再介绍一个更好用的姿势,直接使用开源项目 https://github.com/liuyueyi/quick-media 来实现图片字符画
使用这个项目的 image-plugins
之后,生成一个灰度图就很简单了
publicvoidtestCharImg()throwsIOException{Stringimg="http://hbimg.b0.upaiyun.com/2b79e7e15883d8f8bbae0b1d1efd6cf2c0c1ed1b10753-cusHEA_fw236";BufferedImageout=ImgPixelWrapper.build().setSourceImg(img).setBlockSize(2).setPixelType(PixelStyleEnum.CHAR_COLOR).setChars("小灰灰blog").build().asBufferedImg();System.out.println(out);}
注意这个ImgPixelWrapper
封装类,处理基础的字符处理之外,还支持生成灰度图,gif图转字符动画,图片像素化(如马赛克...)
至于quick-media这个项目就更有意思了,java侧若想生成酷炫的二维码,选择它绝对不会让你失望;有兴趣的小伙伴可以瞅一瞅
公众号:一灰灰blog