import java.lang.*; import java.io.*; import java.awt.*; import java.awt.font.*; import java.awt.image.*; import java.awt.geom.*; import Acme.JPM.Encoders.*; import com.sun.image.codec.jpeg.*; class IDSCompose { //AffineTransform scaler; //AffineTransformOp scaleOp; BufferedImage dst, tmpsrc; Image tmpdst; Graphics2D dstgraphics; Canvas dummycanvas; IDTree root; int charsize, idsIndex; GifEncoder gifwriter; Color bgColor, fgColor; int bgRGB, fgRGB; public IDSCompose(String ids, int size, String filename) { //scaler = new AffineTransform(); charsize = size; // Set up the color scheme bgColor = Color.white; fgColor = Color.black; bgRGB = bgColor.getRGB(); fgRGB = fgColor.getRGB(); // Decode ideographic description sequence into a tree of IDTree nodes idsIndex = 0; root = decodeIDS(ids); dst = new BufferedImage(size, size, BufferedImage.TYPE_BYTE_BINARY); dstgraphics = dst.createGraphics(); dstgraphics.setColor(bgColor); dstgraphics.fill(new Rectangle(0, 0, size, size)); dstgraphics.setColor(fgColor); // Traverse tree and draw character dummycanvas = new Canvas(); traverseIDT(root, 0, 0, size, size, 0); try { // Output GIF FileOutputStream out = new FileOutputStream(filename); GifEncoder chargif = new GifEncoder(dst, out); chargif.encode(); /* // Output JPEG FileOutputStream out = new FileOutputStream("shufa.jpg"); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(dst); param.setQuality(1.0f, false); encoder.setJPEGEncodeParam(param); encoder.encode(dst); */ } catch (Exception e) { System.out.println(e); } } public void traverseIDT(IDTree idt, float x, float y, float w, float h, int level) { // See the structure of the tree (for debugging) for (int i = 0; i < level; i++) { System.out.print(" "); } System.out.println(Integer.toHexString((int)idt.sinograph) + " " + x + " " + y + " " + " " + w + " " + h); //dstgraphics.drawRect((int)x, (int)y, (int)w, (int)h); // Draw the character if (0x3400 <= idt.sinograph && idt.sinograph <= 0x9fa0) { // Set up background of component character Font componentFont = new Font("Dialog", Font.PLAIN, charsize); //FontMetrics componentMetrics = new FontMetrics(componentFont); Rectangle2D charRect = componentFont.getStringBounds(new Character(idt.sinograph).toString(), dstgraphics.getFontRenderContext()); System.out.println("X: " + charRect.getX() + " Y: " + charRect.getY() + " W: " + charRect.getWidth() + " H: " + charRect.getHeight() ); LineMetrics complm = componentFont.getLineMetrics(new Character(idt.sinograph).toString(), dstgraphics.getFontRenderContext()); System.out.println("Ascent: " + complm.getAscent() + " Descent : " + complm.getDescent()); tmpsrc = new BufferedImage((int)charRect.getWidth(), (int)(complm.getAscent() - complm.getDescent()), BufferedImage.TYPE_BYTE_BINARY); Graphics2D tmpgraphics = tmpsrc.createGraphics(); tmpgraphics.setColor(bgColor); tmpgraphics.fill(new Rectangle(0, 0, (int)charRect.getWidth(), (int)(complm.getAscent()- complm.getDescent()))); // Draw the component character tmpgraphics.setFont(componentFont); tmpgraphics.setColor(fgColor); tmpgraphics.drawString(new Character(idt.sinograph).toString(), 0, complm.getAscent() - complm.getDescent()); // Scale it to fit in the final character tmpdst = tmpsrc.getScaledInstance((int)w, (int)h, Image.SCALE_DEFAULT); BufferedImage tmpdst2 = new BufferedImage((int)w, (int)h, BufferedImage.TYPE_BYTE_BINARY); tmpdst2.createGraphics().drawImage(tmpdst, 0, 0, dummycanvas); // Draw it on the final image, being sure not to erase any previous drawing for (int i = 0; i < tmpdst2.getWidth(); i++) { for (int j = 0; j < tmpdst2.getHeight(); j++) { if (tmpdst2.getRGB(i, j) == fgRGB) { dst.setRGB((int)x+i, (int)y+j, fgRGB); } } } //dstgraphics.drawImage(tmpdst, (int)x, (int)y, dummycanvas); } else if (idt.sinograph == 0x2ff0) { traverseIDT(idt.d1, x, y, w/2, h, level+1); traverseIDT(idt.d2, x + w/2, y, w/2, h, level+1); } else if (idt.sinograph == 0x2ff1) { traverseIDT(idt.d1, x, y, w, h/2, level+1); traverseIDT(idt.d2, x, y + h/2, w, h/2, level+1); } else if (idt.sinograph == 0x2ff2) { traverseIDT(idt.d1, x, y, w/3, h, level+1); traverseIDT(idt.d2, x + w/3, y, w/3, h, level+1); traverseIDT(idt.d3, x + 2*w/3, y, w/3, h, level+1); } else if (idt.sinograph == 0x2ff3) { traverseIDT(idt.d1, x, y, w, h/3, level+1); traverseIDT(idt.d2, x, y + h/3, w, h/3, level+1); traverseIDT(idt.d3, x, y + 2*h/3, w, h/3, level+1); } else if (idt.sinograph == 0x2ff4) { traverseIDT(idt.d1, x, y, w, h, level+1); traverseIDT(idt.d2, x + w/5, y + w/5, w * 3/5, h * 3/5, level+1); } else if (idt.sinograph == 0x2ff5) { traverseIDT(idt.d1, x, y, w, h, level+1); traverseIDT(idt.d2, x + w/5, y + 2*w/5, w * 3/5, h * 3/5, level+1); } else if (idt.sinograph == 0x2ff6) { traverseIDT(idt.d1, x, y, w, h, level+1); traverseIDT(idt.d2, x + w/5, y, w * 3/5, h * 4/5, level+1); } else if (idt.sinograph == 0x2ff7) { traverseIDT(idt.d1, x, y, w, h, level+1); traverseIDT(idt.d2, x + w/5, y + w/5, w * 4/5, h * 3/5, level+1); } else if (idt.sinograph == 0x2ff8) { traverseIDT(idt.d1, x, y, w, h, level+1); traverseIDT(idt.d2, x + w/5, y + w/5, w * 4/5, h * 4/5, level+1); } else if (idt.sinograph == 0x2ff9) { traverseIDT(idt.d1, x, y, w, h, level+1); traverseIDT(idt.d2, x, y + w/5, w * 4/5, h * 4/5, level+1); } else if (idt.sinograph == 0x2ffa) { traverseIDT(idt.d1, x, y, w, h, level+1); traverseIDT(idt.d2, x + w/5, y, w * 4/5, h * 4/5, level+1); } else if (idt.sinograph == 0x2ffb) { traverseIDT(idt.d1, x, y, w, h, level+1); traverseIDT(idt.d2, x, y, w, h, level+1); } } public IDTree decodeIDS(String ids) { IDTree idnode = new IDTree(); if ((0x2ff0 <= ids.charAt(idsIndex) && ids.charAt(idsIndex) <= 0x2ff1) || (0x2ff4 <= ids.charAt(idsIndex) && ids.charAt(idsIndex) <= 0x2ffb)) { // Dual combination idnode.sinograph = ids.charAt(idsIndex); idsIndex++; idnode.d1 = decodeIDS(ids); idnode.d2 = decodeIDS(ids); idnode.d3 = null; } else if (0x2ff2 == ids.charAt(idsIndex) || ids.charAt(idsIndex) == 0x2ff3) { // Triple combination idnode.sinograph = ids.charAt(idsIndex); idsIndex++; idnode.d1 = decodeIDS(ids); idnode.d2 = decodeIDS(ids); idnode.d3 = decodeIDS(ids); } else if (0x3440 <= ids.charAt(idsIndex) && ids.charAt(idsIndex) <= 0x9f00) { // Ideograph idnode.sinograph = ids.charAt(idsIndex); idsIndex++; idnode.d1 = null; idnode.d2 = null; idnode.d3 = null; } else { return null; } return idnode; } public static void main(String[] argc) { String chao2 = "\u2ff0\u2ff3\u5341\u65e5\u5341\u6708"; // chao2, dynasty String guo2 = "\u2ff4\u56d7\u7389"; // guo2, simplified country String zhe4 = "\u2ffa\u8fb6\u8a00"; // zhe4, (traditional) "this" String jian1 = "\u2ff5\u9580\u65e5"; // jian1, (traditional) "indirect" String de5 = "\u2FF0\u767D\u2FF9\u52F9\u4E36"; //new IDSCompose(de5, 192); String idsline, filename, idsstring; int currentindex = 0; try { FileInputStream idsin = new FileInputStream("ids.txt"); BufferedReader r = new BufferedReader(new InputStreamReader(idsin, "UTF8")); while ((idsline = r.readLine()) != null) { filename = Integer.toHexString(idsline.charAt(0)).toUpperCase() + ".gif"; if (idsline.length() > 2) { System.out.println("Composing " + filename + " " + currentindex); idsstring = idsline.substring(2, idsline.length()); new IDSCompose(idsstring, 192, filename); } currentindex++; } idsin.close(); } catch (Exception ioexc) { System.out.println("Error! " + ioexc); } System.exit(0); } } class IDTree { public char sinograph; public IDTree d1, d2, d3; public IDTree() { sinograph = '\u0000'; d1 = null; d2 = null; d3 = null; } }