Index: src/com/caucho/quercus/lib/ImageModule.java =================================================================== --- src/com/caucho/quercus/lib/ImageModule.java (revision 4182) +++ src/com/caucho/quercus/lib/ImageModule.java (working copy) @@ -44,11 +44,13 @@ import javax.imageio.ImageIO; import java.awt.*; import java.awt.color.ColorSpace; +import java.awt.font.FontRenderContext; import java.awt.geom.Arc2D; import java.awt.geom.Ellipse2D; import java.awt.geom.FlatteningPathIterator; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ColorConvertOp; @@ -1094,6 +1096,170 @@ } + /** + * finds the ttf font specified or returns the default system font + */ + private static Font loadFontFromFile(QuercusImage image, String fontFile, float size) + { + Font ttf = null; + Env env = Env.getInstance(); + + // find the font file + if (fontFile != null && !fontFile.isEmpty()) + { + Path ttfPath = null; + + if (!fontFile.startsWith("/")) + { + if (!fontFile.toLowerCase().endsWith(".ttf")) + fontFile = fontFile + ".ttf"; + + String fontPath = null; + Value fontPathValue = OptionsModule.getenv(env, (StringValue)StringValue.create("GDFONTPATH")); + if (fontPathValue != null && fontPathValue.getValueType() == ValueType.STRING) + fontPath = fontPathValue.toString(); + + String oldIncludePath = null; + if (fontPath != null && !fontPath.isEmpty()) + oldIncludePath = env.setIncludePath(fontPath); + + ttfPath = env.lookupPwd(StringValue.create(fontFile)); + if (ttfPath == null) + ttfPath = env.lookup(fontFile); + + if (oldIncludePath != null) + env.setIncludePath(oldIncludePath); + } + else + ttfPath = env.lookup(fontFile); + + // load the font + if (ttfPath != null && ttfPath.isFile() && ttfPath.canRead()) + { + try + { + ttf = Font.createFont(Font.TRUETYPE_FONT, ttfPath.openRead()); + } + catch (Exception e) + { + env.warning(L.l("failed to recognize font format: font file '{0}' is not true type. Using default system font.", ttfPath.getFullPath()), e); + } + } + else + env.warning(L.l("Could not find/open font file '{0}'. using system font number 1", fontFile)); + } + else + { + ttf = null; + } + + if (ttf == null && image != null) + { + env.warning(L.l("no font specified, using default font number 1")); + ttf = image.getFont(1); + } + else if (ttf == null) + { + env.warning(L.l("no font specified, using default font 'sans serife'")); + ttf = new Font("sansserif", 0, 8); + } + + // convert the Zend PHP pixel size into Java point size + ttf = ttf.deriveFont(40f); // increased font size to minimize rounding errors + FontRenderContext frc = new FontRenderContext(null, true, true); + Rectangle2D bounds = ttf.getStringBounds("Tg", frc); + int descent = image.getGraphics().getFontMetrics(ttf).getDescent(); + float pointSize = (float)Math.abs(size * (double)ttf.getSize2D() / (Math.abs(bounds.getY()) - descent) ); + ttf = ttf.deriveFont(pointSize); + + + return ttf; + } + + /** + * Draw a string horizontally with true type font. Note size is in POINTs + */ + public static boolean imagettftext(QuercusImage image, float size, float angle, + int x, int y, int color, String fontFile, String s) + { + Env env = Env.getInstance(); + if (image == null) + { + env.error(L.l("no image object specified.")); + return false; + } + + if (s == null || s.isEmpty()) + return true; + + // convert text from UTF-8 + try {s = new String(s.getBytes("ISO-8859-1"), "UTF-8");} catch(Exception e) {} + + Font ttf = loadFontFromFile(image, fontFile, size); + + Graphics2D g = image.getGraphics(); + Font oldFont = g.getFont(); + AffineTransform oldTransform = g.getTransform(); + + g.setFont(ttf); + g.setColor(intToColor(color)); + + if (angle != 0f) + g.rotate(Math.toRadians(angle)); + + // Zend PHP always uses antialiasing for writing text + Object oldAntialiasingValue = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + g.drawString(s, x, y); + + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAntialiasingValue); + g.setFont(oldFont); + g.setTransform(oldTransform); + return true; + } + + + /** + * returns the bounding box for a true type text - NOTE. size is in PIXEL + */ + public static Value imagettfbbox(float size, float angle, + String fontFile, String s) + { + // use a dummy image for graphics context + QuercusImage image = new QuercusImage(2, 2); + + if (s == null) + s = ""; + + // convert text from UTF-8 + try {s = new String(s.getBytes("ISO-8859-1"), "UTF-8");} catch(Exception e) {} + + + Graphics2D g = image.getGraphics(); + Font oldFont = g.getFont(); + Font ttf = loadFontFromFile(image, fontFile, size); + + + g.setFont(ttf); + Rectangle2D rect = ttf.getStringBounds(s, g.getFontRenderContext()); + int descent = g.getFontMetrics(ttf).getDescent(); + g.setFont(oldFont); + + ArrayValue bbox = new ArrayValueImpl(); + bbox.put(new LongValue(Math.round(rect.getX()))); + bbox.put(new LongValue(Math.round(rect.getY() + rect.getHeight() ))); + bbox.put(new LongValue(Math.round(rect.getX() + rect.getWidth() ))); + bbox.put(new LongValue(Math.round(rect.getY() + rect.getHeight() ))); + + bbox.put(new LongValue(Math.round(rect.getX() + rect.getWidth() ))); + bbox.put(new LongValue(Math.round(rect.getY()) + descent -1 ) ); + bbox.put(new LongValue(Math.round(rect.getX() ))); + bbox.put(new LongValue(Math.round(rect.getY()) + descent -1 ) ); + + return bbox; + } + // BitBlts ////////////////////////////////////////////////////////// /**