commit fe2870c64133471c6f15315655ebdc0e98f81bad Author: Jonas Thiel Date: Mon Mar 11 16:56:43 2013 +0100 Initial version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0bdf67b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/tagcloud.iml +/tagcloud.jar +/out/ +/.idea/ +/out.png \ No newline at end of file diff --git a/input.txt b/input.txt new file mode 100644 index 0000000..c4fbb21 --- /dev/null +++ b/input.txt @@ -0,0 +1,156 @@ +mythology,25 +children,25 +lemonade,25 +compression,25 +usa,25 +Lemon,25 +out,25 +darkness,25 +Brain,25 +puppy,24 +django,24 +customers,24 +Mask,23 +full moon,23 +bus,23 +html,23 +Internet,23 +zombies,22 +bored,22 +yarn,22 +career,22 +pen,22 +computers,22 +Black,22 +potato,21 +Pills,21 +bank,21 +One,21 +investments,21 +Green,21 +web,21 +paper,21 +book,20 +anger,20 +Pencil,20 +read,20 +tricycle,19 +linux,19 +super,19 +ugly,19 +Japan,19 +site,19 +Chocolate,18 +money,18 +danger,18 +White,18 +widget,18 +Penguin,18 +Mint,18 +Low,18 +roof,17 +venture,17 +favorites,17 +nose,17 +sun,17 +clients,17 +dog,17 +ocean,16 +Handle,16 +Pink,16 +find,15 +venture,15 +life,15 +customers,15 +hate microsoft,15 +run,15 +sky,14 +fun,14 +software,14 +wmd,14 +Internet,14 +tomato,14 +SAAS,14 +tag,14 +Orient,14 + +life,14 +bloody,14 +framework,13 +Door,13 +type,13 +firefox,13 +chocolate,13 +Dragon,13 +Cellphone,13 +startup,13 +vodka,13 +china,13 +linux,13 +job,13 +fair,13 +tag,12 +software,12 +Color,12 +pizza,12 +gothic,11 +murder,11 +usa,11 +wordpress,11 +SAAS,11 +High,11 +Knob,11 +farm,11 +Speaker,11 +Knife,11 +Light,10 +startup,10 +Wood,10 +Love,10 +Cat,10 +georgeous,10 +pencil,10 +broken,10 +service,10 +career,10 +cloud,10 +money,10 +html,10 +fun,9 +hippo,9 +service,9 +flag,9 +opera,9 +fallen,9 +vodka,9 +europe,8 +computers,8 +ubuntu,8 +job,8 +web,8 +beer,8 +Dark,8 +development,8 +cruel,8 +google,8 +ubuntu,8 +cloud,7 +Dog,7 +coconut,7 +europe,7 +Brush,7 +early riser,7 +wordpress,7 +development,6 +bank,6 +georgeous,6 +hit,6 +early riser,6 +speaker,6 +investments,6 +opera,6 +firefox,5 +site,5 +china,5 +clients,5 +widget,5 \ No newline at end of file diff --git a/lib/WordCram.jar b/lib/WordCram.jar new file mode 100644 index 0000000..498596e Binary files /dev/null and b/lib/WordCram.jar differ diff --git a/lib/core.jar b/lib/core.jar new file mode 100644 index 0000000..4f9ba2c Binary files /dev/null and b/lib/core.jar differ diff --git a/lib/cue.language.jar b/lib/cue.language.jar new file mode 100644 index 0000000..c4a4db6 Binary files /dev/null and b/lib/cue.language.jar differ diff --git a/lib/gluegen-rt-natives-linux-amd64.jar b/lib/gluegen-rt-natives-linux-amd64.jar new file mode 100644 index 0000000..97c1bee Binary files /dev/null and b/lib/gluegen-rt-natives-linux-amd64.jar differ diff --git a/lib/gluegen-rt-natives-linux-armv6hf.jar b/lib/gluegen-rt-natives-linux-armv6hf.jar new file mode 100644 index 0000000..ceaf74d Binary files /dev/null and b/lib/gluegen-rt-natives-linux-armv6hf.jar differ diff --git a/lib/gluegen-rt-natives-linux-i586.jar b/lib/gluegen-rt-natives-linux-i586.jar new file mode 100644 index 0000000..14acddc Binary files /dev/null and b/lib/gluegen-rt-natives-linux-i586.jar differ diff --git a/lib/gluegen-rt-natives-macosx-universal.jar b/lib/gluegen-rt-natives-macosx-universal.jar new file mode 100644 index 0000000..8e506a3 Binary files /dev/null and b/lib/gluegen-rt-natives-macosx-universal.jar differ diff --git a/lib/gluegen-rt-natives-windows-amd64.jar b/lib/gluegen-rt-natives-windows-amd64.jar new file mode 100644 index 0000000..9b88644 Binary files /dev/null and b/lib/gluegen-rt-natives-windows-amd64.jar differ diff --git a/lib/gluegen-rt-natives-windows-i586.jar b/lib/gluegen-rt-natives-windows-i586.jar new file mode 100644 index 0000000..8fefd17 Binary files /dev/null and b/lib/gluegen-rt-natives-windows-i586.jar differ diff --git a/lib/gluegen-rt.jar b/lib/gluegen-rt.jar new file mode 100644 index 0000000..4a5337b Binary files /dev/null and b/lib/gluegen-rt.jar differ diff --git a/lib/jogl-all-natives-linux-amd64.jar b/lib/jogl-all-natives-linux-amd64.jar new file mode 100644 index 0000000..64d13e9 Binary files /dev/null and b/lib/jogl-all-natives-linux-amd64.jar differ diff --git a/lib/jogl-all-natives-linux-armv6hf.jar b/lib/jogl-all-natives-linux-armv6hf.jar new file mode 100644 index 0000000..e7e417d Binary files /dev/null and b/lib/jogl-all-natives-linux-armv6hf.jar differ diff --git a/lib/jogl-all-natives-linux-i586.jar b/lib/jogl-all-natives-linux-i586.jar new file mode 100644 index 0000000..7e472d7 Binary files /dev/null and b/lib/jogl-all-natives-linux-i586.jar differ diff --git a/lib/jogl-all-natives-macosx-universal.jar b/lib/jogl-all-natives-macosx-universal.jar new file mode 100644 index 0000000..ec11e7f Binary files /dev/null and b/lib/jogl-all-natives-macosx-universal.jar differ diff --git a/lib/jogl-all-natives-windows-amd64.jar b/lib/jogl-all-natives-windows-amd64.jar new file mode 100644 index 0000000..2a4c7d2 Binary files /dev/null and b/lib/jogl-all-natives-windows-amd64.jar differ diff --git a/lib/jogl-all-natives-windows-i586.jar b/lib/jogl-all-natives-windows-i586.jar new file mode 100644 index 0000000..97de705 Binary files /dev/null and b/lib/jogl-all-natives-windows-i586.jar differ diff --git a/lib/jogl-all.jar b/lib/jogl-all.jar new file mode 100644 index 0000000..58e6958 Binary files /dev/null and b/lib/jogl-all.jar differ diff --git a/lib/jsoup-1.7.2.jar b/lib/jsoup-1.7.2.jar new file mode 100644 index 0000000..8eeb5c7 Binary files /dev/null and b/lib/jsoup-1.7.2.jar differ diff --git a/lib/pja.jar b/lib/pja.jar new file mode 100644 index 0000000..9d0cbf2 Binary files /dev/null and b/lib/pja.jar differ diff --git a/lib/pjatools.jar b/lib/pjatools.jar new file mode 100644 index 0000000..3365df4 Binary files /dev/null and b/lib/pjatools.jar differ diff --git a/lib/servlet.jar b/lib/servlet.jar new file mode 100755 index 0000000..38f73d4 Binary files /dev/null and b/lib/servlet.jar differ diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..037d98e --- /dev/null +++ b/run.sh @@ -0,0 +1,5 @@ +#!/bin/sh +APP_DIR=$(pwd) +Xvfb :1 -screen 0 1024x768x24 & +DISPLAY=:1 java -jar tagcloud.jar +killall -9 Xvfb \ No newline at end of file diff --git a/shape.png b/shape.png new file mode 100644 index 0000000..b1ade07 Binary files /dev/null and b/shape.png differ diff --git a/src/Configuration.java b/src/Configuration.java new file mode 100644 index 0000000..afb08b5 --- /dev/null +++ b/src/Configuration.java @@ -0,0 +1,9 @@ +public class Configuration { + public static String shape_file = "shape.png"; + public static String input_file = "input.txt"; + public static String output_file = "out.png"; + public static int width = 600; + public static int height = 636; + public static int minSize = 8; + public static int maxSize = 34; +} diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF new file mode 100644 index 0000000..ef660ad --- /dev/null +++ b/src/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: TagCloud + diff --git a/src/ShapeBasedPlacer.java b/src/ShapeBasedPlacer.java new file mode 100644 index 0000000..a6cfdd8 --- /dev/null +++ b/src/ShapeBasedPlacer.java @@ -0,0 +1,181 @@ +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.Area; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.Random; + +import javax.imageio.ImageIO; + +import processing.core.PVector; +import wordcram.Word; +import wordcram.WordNudger; +import wordcram.WordPlacer; + +class ShapeBasedPlacer implements WordPlacer, WordNudger { + + public static int TOLERANCE = 5; + public static boolean PRECISE = false; + public static int GLYPH_SIZE = 500; + public static int FONT_STYLE = Font.PLAIN; + + Area area; + float minX; + float minY; + float maxX; + float maxY; + Random random; + BufferedImage image = null; + + public ShapeBasedPlacer(Shape shape) { + this.area = new Area(shape); + init(); + } + + private void init() { + random = new Random(); + Rectangle2D areaBounds = area.getBounds2D(); + this.minX = (float) areaBounds.getMinX(); + this.minY = (float) areaBounds.getMinY(); + this.maxX = (float) areaBounds.getMaxX(); + this.maxY = (float) areaBounds.getMaxY(); + } + + public static ShapeBasedPlacer fromTextGlyphs(String text, String fontName) { + Font font = null; + Graphics2D g2d; + FontRenderContext frc; + GlyphVector gv; + font = new Font(fontName,FONT_STYLE,GLYPH_SIZE); + BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + g2d = img.createGraphics(); + frc = g2d.getFontRenderContext(); + gv = font.createGlyphVector(frc, text); + return new ShapeBasedPlacer(gv.getOutline(GLYPH_SIZE / 10,GLYPH_SIZE)); + } + + private ShapeBasedPlacer(BufferedImage image) { + this.image = image; + } + + public static ShapeBasedPlacer fromFile(String path, Color color) { + BufferedImage image = null; + try { + image = ImageIO.read(new File(path)); + } catch (IOException e) { + e.printStackTrace(); + } + ShapeBasedPlacer result = new ShapeBasedPlacer(image); + if (PRECISE) { + result.fromImagePrecise(color); + } else { + result.fromImageSloppy(color); + } + result.init(); + return result; + } + + private void fromImagePrecise(Color color) { + Area area = new Area(); + for (int x = 0; x < image.getWidth(); x++) { + for (int y = 0; y < image.getHeight(); y++) { + Color pixel = new Color(image.getRGB(x, y)); + if (isIncluded(color, pixel)) { + Rectangle r = new Rectangle(x, y, 1, 1); + area.add(new Area(r)); + } + } + } + this.area = area; + } + + private void fromImageSloppy(Color color) { + Area area = new Area(); + Rectangle r; + int y1, y2; + for (int x = 0; x < image.getWidth(); x++) { + y1 = 99; + y2 = -1; + for (int y = 0; y < image.getHeight(); y++) { + Color pixel = new Color(image.getRGB(x, y)); + if (isIncluded(color, pixel)) { + if (y1 == 99) { + y1 = y; + y2 = y; + } + if (y > (y2 + 1)) { + r = new Rectangle(x, y1, 1, y2 - y1); + area.add(new Area(r)); + y1 = y; + y2 = y; + } + y2 = y; + } + } + if ((y2 - y1) >= 0) { + r = new Rectangle(x, y1, 1, y2 - y1); + area.add(new Area(r)); + } + } + this.area = area; + } + + public PVector place(Word w, int rank, int count, int ww, int wh, int fw, + int fh) { + + w.setProperty("width", ww); + w.setProperty("height", wh); + + for (int i = 0; i < 1000; i++) { + float newX = randomBetween(minX, maxX); + float newY = randomBetween(minY, maxY); + if (area.contains(newX, newY, ww, wh)) { + return new PVector(newX, newY); + } + } + + return new PVector(-1, -1); + } + + public PVector nudgeFor(Word word, int attempt) { + PVector target = word.getTargetPlace(); + float wx = target.x; + float wy = target.y; + float ww = (Integer) word.getProperty("width"); + float wh = (Integer) word.getProperty("height"); + + for (int i = 0; i < 1000; i++) { + float newX = randomBetween(minX, maxX); + float newY = randomBetween(minY, maxY); + + if (area.contains(newX, newY, ww, wh)) { + return new PVector(newX - wx, newY - wy); + } + } + + return new PVector(-1, -1); + } + + float randomBetween(float a, float b) { + return a + random.nextFloat() * (b - a); + } + + boolean isIncluded(Color target, Color pixel) { + int rT = target.getRed(); + int gT = target.getGreen(); + int bT = target.getBlue(); + int rP = pixel.getRed(); + int gP = pixel.getGreen(); + int bP = pixel.getBlue(); + return ((rP - TOLERANCE <= rT) && (rT <= rP + TOLERANCE) + && (gP - TOLERANCE <= gT) && (gT <= gP + TOLERANCE) + && (bP - TOLERANCE <= bT) && (bT <= bP + TOLERANCE)); + } +} diff --git a/src/TagCloud.java b/src/TagCloud.java new file mode 100644 index 0000000..995c5fb --- /dev/null +++ b/src/TagCloud.java @@ -0,0 +1,18 @@ +import processing.core.PApplet; + +public class TagCloud { + + public static void main(String[] args){ + if(args.length < 3){ + System.out.println("Use can provide 3 arguments: 1st: shape file, 2nd text file, 3rd output file name"); + System.out.println("Defaults to: shape.png, input.txt, out.png"); + } + else{ + Configuration.shape_file = args[0]; + Configuration.input_file = args[1]; + Configuration.output_file = args[2]; + } + + PApplet.main(new String[] { "--present", "Tree" }); + } +} diff --git a/src/Tree.java b/src/Tree.java new file mode 100644 index 0000000..de04801 --- /dev/null +++ b/src/Tree.java @@ -0,0 +1,78 @@ +import processing.core.*; +import wordcram.WordCram; + +import java.awt.*; +import java.io.*; +import java.util.ArrayList; + +import wordcram.*; +import wordcram.text.TextSource; + +public class Tree extends PApplet { + + private WordCram cram; + private boolean draw = true; + + public void setup(){ + size(Configuration.width,Configuration.height); + background(255); + + ShapeBasedPlacer placer = ShapeBasedPlacer.fromFile(Configuration.shape_file, Color.black); + + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(Configuration.input_file)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + ArrayList words = new ArrayList(); + + String line = null; + try { + while((line = reader.readLine()) != null){ + String[] values = line.split(","); + if(values.length == 2){ + words.add( new Word(values[0].trim(), Float.parseFloat(values[1].trim()))); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + + cram = new WordCram(this) + .fromWords(words.toArray(new Word[words.size()])) + .withPlacer(placer) + .withNudger(placer) + .sizedByWeight(Configuration.minSize,Configuration.maxSize); + } + + public void draw() { + if(this.draw){ + System.out.println("Start drawing tag cloud..."); + cram.drawAll(); + this.draw = false; + System.out.println("Finished drawing"); + //tell me what didn’t get drawn + + int noSpace = 0; + int tooSmall = 0; + Word[] skippedWords = cram.getSkippedWords(); + Word[] placedWords = cram.getWords(); + for (Word skipped: skippedWords) { + if (skipped.wasSkippedBecause() == WordCram.NO_SPACE) { + noSpace++; + } else if (skipped.wasSkippedBecause() == WordCram.SHAPE_WAS_TOO_SMALL) { + tooSmall++; + } + } + System.out.println("Total placed Words: " + placedWords.length); + System.out.println("Total Skipped Words: " + skippedWords.length); + System.out.println("Skipped because no Space: " + noSpace); + System.out.println("Skipped because too small: " + tooSmall); + System.out.println("Finished"); + + save(Configuration.output_file); + exit(); + } + } +}