Maison >développement back-end >tutoriel php >gd - php中如何获得双色图片的mask
在php中如何实现上图的效果?要求:“上”和“爱情”都是通过程序自动输出的,程序能共自动判断画布上得空白部分并输出文字。
在python中,有pygame库直接获得一个画布的mask,然后提供collide函数来判断两个mask是否有交集。php是否有类似功能?
换个问题:
php中如何获得双色图片的mask
在php中如何实现上图的效果?要求:“上”和“爱情”都是通过程序自动输出的,程序能共自动判断画布上得空白部分并输出文字。
在python中,有pygame库直接获得一个画布的mask,然后提供collide函数来判断两个mask是否有交集。php是否有类似功能?
换个问题:
php中如何获得双色图片的mask
更新下算法解释,貌似做成php版的还算简单
http://ued.ctrip.com/blog/?p=2471
携程的算法源码如下:
package com.ctrip; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Paint; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.imageio.ImageIO; public class WordsThumb { public static final int MIN_WIDTH = 320; public static final int MIN_HEIGHT = 240; public static final int MAX_WIDTH = 2560; public static final int MAX_HEIGHT = 1920; public static final int BLOCK = 4; public static final String DEF_FONT = "微软雅黑"; public static final int MIN_FONT_SIZE = 12; private static final int[] COLORS = { 11682842, 14439168, 13081114, 10300417, 14450176, 13052357, 11665801, 1739698, 101319, 84146, 15580865, 1722823, 6664705, 11257601, 7582257, 11665680, 14425600, 10768192, 14360836, 15515347, 111266, 49372, 15436032, 15436032 }; public BufferedImage createWordsThumb(Map<string integer> words, int width, int height, String fontName, Integer maxFontSize, Integer minFontSize) { if ((words == null) || (words.size() 2560) || (height 1920)) return null; fontName = validateFontName(fontName, "微软雅黑"); List sortedWords = sortWordsMap(words); BufferedImage bi = createBufferedImage(width, height); if (bi == null) { return null; } if (maxFontSize == null) { maxFontSize = Integer.valueOf(Math.min(width, height) / 5); } if (minFontSize == null) { minFontSize = Integer.valueOf(Math.min(width, height) / 40); } if (minFontSize.intValue() > sortWordsMap(Map<string integer> words) { if (words == null) return null; ArrayList wordsList = new ArrayList( words.entrySet()); Collections.sort(wordsList, new Comparator() { public int compare(Map.Entry<string integer> o1, Map.Entry<string integer> o2) { return o2 == null ? -1 : o1 == null ? 1 : ((Integer)o2 .getValue()).intValue() - ((Integer)o1.getValue()).intValue(); } }); return wordsList; } private BufferedImage createBufferedImage(int width, int height) { BufferedImage bi = new BufferedImage(width, height, 2); Graphics2D g2 = bi.createGraphics(); bi = g2.getDeviceConfiguration().createCompatibleImage(width, height, 3); g2.dispose(); return bi; } private int paintWords(BufferedImage bi, List<map.entry integer>> words, String fontName, int maxFontSize, int minFontSize) { BitMap bitMap = initBitMap(bi); Graphics2D g2 = bi.createGraphics(); int wordCount = 0; int fontSizeAdjust = 0; int maxFrequency = ((Integer)((Map.Entry)words.get(0)).getValue()).intValue(); int minFrequency = ((Integer)((Map.Entry)words.get(words.size() - 1)).getValue()).intValue(); for (Map.Entry entry : words) { while (true) { Font font = initFont(g2, fontName, Integer.valueOf(maxFontSize), Integer.valueOf(minFontSize), (Integer)entry.getValue(), Integer.valueOf(maxFrequency), Integer.valueOf(minFrequency), Integer.valueOf(fontSizeAdjust)); if (font.getSize() minFrequency.intValue()) { fs = (int)((frequency.intValue() - minFrequency.intValue()) * ( maxFontSize.intValue() - minFontSize.intValue()) / ( maxFrequency.intValue() - minFrequency.intValue()) + minFontSize.intValue()); } if (fontSizeAdjust != null) { fs += fontSizeAdjust.intValue(); } Font font = new Font(fontName, 1, fs); g2.setFont(font); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); return font; } private Rectangle2D getStringBounds(Graphics2D g2, Font font, String key) { FontRenderContext frc = g2.getFontRenderContext(); Rectangle2D rc = font.getStringBounds(key, frc); return rc; } private Rectangle2D findSpace(BitMap bitMap, Rectangle2D rect) { int w = pixel2bitMap((int)rect.getWidth()); int h = pixel2bitMap((int)rect.getHeight()); int boundW = bitMap.getWidth() - w; int boundH = bitMap.getHeight() - h; int start_x = boundW / 2; int start_y = boundH / 2; int maxBound = Math.max(boundW, boundH); double wRatio = boundW / maxBound; double hRatio = boundH / maxBound; double max_r = Math.sin(0.7853981633974483D) * maxBound; double r = 1.0D; double a = 0.0D; double a_tmp = 0.0D; double s = 1.0D; double step = 1.0D; int x = start_x; int y = start_y; while (r 0.7853981633974483D ? 0.7853981633974483D : s / r; a += a_tmp; r += step * (a_tmp / 6.283185307179586D); x = (int)(Math.sin(a) * r * wRatio + start_x); y = (int)(Math.cos(a) * r * hRatio + start_y); } return null; } private Rectangle2D findSpace2(BitMap bitMap, Rectangle2D rect) { int w = pixel2bitMap((int)rect.getWidth()); int h = pixel2bitMap((int)rect.getHeight()); int[] bounds = { bitMap.getWidth() - w, bitMap.getHeight() - h }; int[] step_len = new int[2]; int marchDir = 0; int x; int y; if (bounds[0] > bounds[1]) { int y = bounds[1] / 2; int x = y; bounds[0] -= bounds[1]; step_len[1] = 1; } else { marchDir = 3; x = bounds[0] / 2; y = x; step_len[0] = 1; bounds[1] -= bounds[0]; if (step_len[1] == 0) { step_len[1] = 1; } } int[] step = new int[4]; while (!isClean(bitMap, x, y, w, h)) { step[marchDir] += 1; if (step[marchDir] > step_len[(marchDir % 2)]) { step[marchDir] = 0; step_len[(marchDir % 2)] += 1; marchDir++; marchDir %= 4; if (step_len[(marchDir % 2)] > bounds[(marchDir % 2)]) { return null; } } switch (marchDir) { case 0: x++; break; case 1: y--; break; case 2: x--; break; case 3: y++; } } int targetX = bit2pixel(x); int targetY = bit2pixel(y); return new Rectangle(targetX, targetY, (int)rect.getWidth(), (int)rect.getHeight()); } private int pixel2bitMap(int v) { return (int)Math.ceil(v / 4.0D); } private boolean isClean(BitMap bitMap, int x, int y, int w, int h) { if ((x = bitMap.getWidth()) || (y = bitMap.getHeight())) return false; for (int i = x; i bi.getWidth()) r = bi.getWidth(); if (b > bi.getHeight()) b = bi.getHeight(); if ((r = bi.getWidth()) || (y2 >= bi.getHeight())) continue; if (bi.getRGB(x + i % 4, y + i / 4) != 0) { bitMap.setUsed(pixel2bitMap(x), pixel2bitMap(y), true); break; } } } public BufferedImage mixImages(BufferedImage[] images, Float[] alphas, int width, int height) { return mixImages(images, alphas, createBufferedImage(width, height)); } public BufferedImage mixImages(BufferedImage[] images, Float[] alphas, BufferedImage targetImage) { if ((images == null) || (images.length ..."); System.out.println("\t-o:\tOutput image file name"); System.out.println("\t-b:\tBackground image file name"); System.out.println("\t-m:\tWater mark image file name"); System.out.println("\t-w:\tWidth of target image"); System.out.println("\t-h:\tHeight of target image"); System.out.println("\t-f:\tFont name"); System.exit(1); } if (words.size() words) throws IOException { BufferedReader rd = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入词汇和词频,格式为每行一个词、一个空格、一个词频数字,以空行结束输入。"); String line = null; while ((line = rd.readLine()) != null) { line = line.trim(); if ("".equals(line)) { System.out.println("好,马上处理!"); break; } String[] parts = line.split("\\s+"); if (parts.length != 2) continue; try { words.put(parts[0], Integer.valueOf(Integer.parseInt(parts[1]))); } catch (NumberFormatException e) { System.out.println("无效的输入。"); } } } } package com.ctrip; import java.io.IOException; import java.io.PrintStream; public class BitMap { private byte[][] bitMap; private int width; private int height; private int byteWidth; public BitMap(int width, int height) { if ((width = 0 ? y : 0; for (int y2 = y1 - y; (y1 = 0 ? x : 0; for (int x2 = x1 - x; (x1 = 0 ? y : 0; for (int y2 = y1 - y; (y1 = 0 ? x : 0; for (int x2 = x1 - x; (x1 = this.byteWidth) || (y = this.height)) throw new IllegalArgumentException(); int mask = 1 = this.byteWidth) || (y = this.height)) throw new IllegalArgumentException(); int mask = 1 <p>反汇编工具jd-gui</p> <p>写了一个flex版本的,执行时间大约1~2s,效果如下:<br> <img data-src="http://segmentfault.com/img/cJHB5O" alt="gd - php中如何获得双色图片的mask" ></p> <p>源码layout.mxml:</p> <pre class="brush:php;toolbar:false"><?xml version="1.0" encoding="utf-8"?> <application xmlns:mx="http://www.adobe.com/2006/mxml" creationcomplete="onLoad();"> <style> @font-face{ src:url("fanghei.ttf"); font-family:myFont; } </style> <script> mxmlc layout.mxml /// import mx.controls.*; import mx.core.*; import mx.effects.*; import flash.geom.Rectangle private function clear():void { my_text_input_1.text="clear it!"; } private function add_text(text_array:Array, text:String):void { text_array.push(text); } private function get_bmp_text(text:String):Bitmap { var metrics:TextLineMetrics; var tempTextField:TextField = new TextField(); var tempTextFormat:TextFormat = new TextFormat(); tempTextFormat.font="myFont"; tempTextFormat.size = Math.floor(Math.random() * 40 + 20); tempTextFormat.color = 0xff00FF; tempTextField.width = 200; tempTextField.height = 100; tempTextField.embedFonts = true; tempTextField.appendText(text); tempTextField.setTextFormat(tempTextFormat); metrics = tempTextField.getLineMetrics(0); var myBitmapData:BitmapData = new BitmapData(metrics.width, metrics.height, true ,0x0000FF); myBitmapData.draw(tempTextField); var myBmp:Bitmap = new Bitmap(myBitmapData); //本版本不支持rotation //如果要支持rotation,请参考http://www.mikechambers.com/blog/2009/06/24/using-bitmapdata-hittest-for-collision-detection/ //myBmp.rotation = (Math.random() > 0.5)?0:90; return myBmp; } private function add_to_canvas(result:Array, bmpText:Bitmap):Boolean { var last_angle:Number = 0; var last_radius:Number = 1; var x:int = 0; var y:int = 0; var center_x:int = 256; var center_y:int = 256; var width:int = 512; var height:int = 512; var conflict:Boolean = false; while(true) { last_angle = last_angle + 0.1; last_radius = last_radius + 0.1; x = Math.floor(last_radius * Math.cos(last_angle) + center_x); y = Math.floor(last_radius * Math.sin(last_angle) + center_y); bmpText.x = x; bmpText.y = y; conflict = false; if (result.length > 0) { var i:int; for(i = 0; i "; if (last_radius > width || last_radius > height) { conflict = true; break; } } } return !conflict; } private function draw(result:Array):void { var s:Sprite = new Sprite; var i:int; for(i = 0; i </script> <label text="Hello World"></label> <label id="metrics_txt_1" text="Hello World" fontfamily="myFont"></label> <label id="metrics_txt_2" text="Hello World"></label> <textinput id="my_text_input_1" width="100" text=""></textinput> <button id="my_clear_button_1" label="clear" click="clear();"></button> <canvas backgroundcolor="0xFFFFFF" width="512" height="512" horizontalcenter="0" verticalcenter="0" id="canvas"></canvas> </application>