Advertisement
Guest User

Generating Images from RegEx

a guest
Mar 24th, 2014
640
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.11 KB | None | 0 0
  1. package com.ignatieff.rei;
  2.  
  3. import java.awt.Color;
  4. import java.awt.Graphics;
  5. import java.awt.Point;
  6. import java.awt.image.BufferedImage;
  7.  
  8. import java.io.File;
  9. import java.io.IOException;
  10.  
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. import java.util.regex.Pattern;
  14.  
  15. import javax.imageio.ImageIO;
  16.  
  17. public class Generator {
  18.    
  19.     public static String TRIANGLE_FRACTAL = "(1+2+3)*0(1+3)*0(0+1+2+3)*";
  20.    
  21.     private int resolution, size;
  22.    
  23.     private Color WHITE = Color.white, BLACK = Color.black;
  24.    
  25.     /**
  26.      * Creates a new generator with as a high a resolution as possible.
  27.      * @param size The width / height of the image to create. This variable must be a power of 2.
  28.      */
  29.     public Generator(int size){
  30.         this((int)log2(size), size);
  31.     }
  32.    
  33.     /**
  34.      * Creates new generator, for creating images based on regular expresions.
  35.      * Keep in mind that the size needs to be a power of 2, for this to work properly.
  36.      * If 'size' is not a power of 2, it'll be converted to the closest power of 2 relative to 'size.
  37.      *
  38.      * Also note that 'resolution' cannot exceed log2(size). If 'resolution' is higher than log2(size) it'll be changed to log2(size).
  39.      *
  40.      * @param resolution The resolution of the images to create. Higher resolution results in better image quality, but longer render time.
  41.      * @param size The width / height of the image to create. This variable must be a power of 2.
  42.      */
  43.     public Generator(int resolution, int size){
  44.  
  45.         this.resolution = resolution;
  46.         this.size = size;
  47.    
  48.         if(!isPow2(size)){
  49.             this.size = (int)Math.pow(2, Math.round(log2(size)));
  50.             System.out.println("Error: size is not a power of 2, changing size to '"+this.size+"'.");
  51.         }
  52.        
  53.         if(Math.pow(2,resolution)>size){
  54.             this.resolution = (int)log2(this.size);
  55.             System.out.println("Error: resolution too large, changing resolution to '"+this.resolution+"'.");
  56.         }
  57.     }
  58.    
  59.     private static char[] regExps = "!$%^&*_+|~-=`(){}[]:\";'<>?,./".toCharArray();
  60.     private static char[] valids = "!$%^&*_+|~-=`(){}[]:\";'<>?,./0123".toCharArray();
  61.    
  62.     /**
  63.      * Checks whether or not a character is a regular expression-symbol or a character.
  64.      * @param c The character to check.
  65.      * @return True, if it's a regular expression symbol, false if it's a character.
  66.      */
  67.     private static boolean isRegExp(char c){
  68.         for(char k : regExps){
  69.             if(k==c)return true;
  70.         }
  71.         return false;
  72.     }
  73.    
  74.     /**
  75.      * Will evaluate whether a regular expression is valid for this generator or not.
  76.      * @param regex The regex to evaluate.
  77.      * @return True, it it's valid. False, if it's invalid.
  78.      */
  79.     private static boolean isValid(String regex){
  80.         char[] chars = regex.toCharArray();
  81.         for(char c : chars){
  82.             boolean valid = false;
  83.             for(char k : valids){
  84.                 if(k==c){
  85.                     valid=true;
  86.                     break;
  87.                 }
  88.             }
  89.             if(!valid)return false;
  90.         }
  91.         return true;
  92.     }
  93.    
  94.     /*public static String getRegexFromImage(BufferedImage img){
  95.        
  96.     }*/
  97.    
  98.     /**
  99.      * Will clean an arbitrary regular expression, making it available to use for generating images,
  100.      * even though it was created for a different purpose.
  101.      *
  102.      * It works by mapping all the non-regular expression symbols (+, [, ], *) unto the characters 0, 1, 2, 3.
  103.      * @param regex The regular expression to clean.
  104.      * @return A cleaned regular expression.
  105.      */
  106.     private static String cleanRegEx(String regex){
  107.        
  108.         if(isValid(regex))return regex;
  109.        
  110.         int i = 0;
  111.         Map<Character, Integer> map = new HashMap<Character, Integer>();
  112.        
  113.         char[] regs = regex.toCharArray();
  114.         char[] clean = new char[regs.length];
  115.        
  116.         for(char c : regs){
  117.             if(map.containsKey(c))continue;
  118.             if(isRegExp(c))continue;
  119.             map.put(c, i);
  120.             i = (i + 1) % 4;
  121.         }
  122.        
  123.         for(int j=0; j<regs.length; j++){
  124.             if(map.containsKey(regs[j])){
  125.                 clean[j] = Integer.toString(map.get(regs[j])).charAt(0);
  126.                 continue;
  127.             }
  128.             clean[j] = regs[j];
  129.         }
  130.         System.out.println(new String(clean));
  131.         return new String(clean);
  132.     }
  133.    
  134.     /**
  135.      * Returns log2 of a double. Uses the identity log_b(x) = ln(x)/ln(b)
  136.      * @param d The double to get the log2 of.
  137.      * @return log2(d)
  138.      */
  139.     private static double log2(double d){
  140.         return Math.log(d)/Math.log(2);
  141.     }
  142.    
  143.     /**
  144.      * Checks whether an integer is a power of 2.
  145.      * @param k The integer to perform the check on
  146.      * @return True if the integer is a power of 2, false otherwise.
  147.      */
  148.     private static boolean isPow2(int k){
  149.         return (Math.pow(2, Math.floor(log2(k))) == k);
  150.     }
  151.    
  152.     /**
  153.      * Will change all (,{,< to [ and all ),},> to ] because Java thinks they are characters, not symbols.
  154.      * @param s
  155.      * @return
  156.      */
  157.     private static String removeParentheses(String s){
  158.         return s.replace("(", "[")
  159.                 .replace(")", "]")
  160.                 .replace("{", "[")
  161.                 .replace("}", "]")
  162.                 .replace("<", "[")
  163.                 .replace(">", "]");
  164.     }      
  165.    
  166.     /**
  167.      * Generate an image from a regular expressions and save it to the file system.
  168.      * @param regex The regular expression to use for generating the image.
  169.      * @param path The relative path to save the image to.
  170.      */
  171.     public void generateAndExport(String regex, String path){
  172.         try {
  173.             BufferedImage img = generate(regex);
  174.             ImageIO.write(img, "png", new File(path));
  175.         } catch (IOException e) {
  176.             e.printStackTrace();
  177.         }
  178.     }
  179.    
  180.     /**
  181.      * Generate an image from a regular expression and return it as a BufferedImage.
  182.      * @param regex The regular expression to use for generating the image.
  183.      * @return The image generated as a BufferedImage.
  184.      */
  185.     public BufferedImage generate(String regex){
  186.         return generate(
  187.                 Pattern.compile(
  188.                         cleanRegEx(
  189.                                 removeParentheses(regex))));
  190.     }
  191.    
  192.     /**
  193.      * Generate an image from a regular expression and return it as a BufferedImage.
  194.      * @param p The regular expression as a 'Pattern' to use for generating the image.
  195.      * If you're confused, just parse a string instead, it'll be handled anyway.
  196.      * @return The image generated as a BufferedImage.
  197.      */
  198.     public BufferedImage generate(Pattern p){
  199.         BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
  200.         Graphics g = img.createGraphics();
  201.        
  202.         g.setColor(WHITE);
  203.         g.fillRect(0, 0, size, size);
  204.         g.setColor(BLACK);
  205.        
  206.         int pointSize = (int) ((int) size/Math.pow(2, resolution));
  207.        
  208.         String[] s = getAllStrings();
  209.        
  210.         for(String q : s){
  211.            
  212.             if(!p.matcher(q).matches())continue;
  213.        
  214.             Point x = stringToPoint(q, size);
  215.             g.fillRect(x.x, x.y, pointSize, pointSize);
  216.         }
  217.        
  218.         return img;
  219.     }
  220.    
  221.     /**
  222.      * Pads a string with 0's to ensure that all strings are of equal length.
  223.      * @param s The string to pad.
  224.      * @param length The length the string must match.
  225.      * @return A padded version of 's' with length 'length'.
  226.      */
  227.     private String pad(String s, int length){
  228.         StringBuilder sb = new StringBuilder();
  229.         int dx = length - s.length();
  230.         for(int i=0; i<dx; i++){
  231.             sb.append("0");
  232.         }
  233.         sb.append(s);
  234.         return sb.toString();
  235.     }
  236.    
  237.     /**
  238.      * Gets all strings of length 'size'. Depends on the generator.
  239.      * @return All strings of length 'size'.
  240.      */
  241.     private String[] getAllStrings(){
  242.         int max = (int) Math.pow(4, resolution);
  243.         String[] strings = new String[max];
  244.         for(int i=0; i<max; i++){
  245.             strings[i] = pad(Integer.toString(i, 4), resolution);
  246.         }
  247.         return strings;
  248.     }
  249.    
  250.     /**
  251.      * Gets the relative position of a character, only matches 0, 1, 2, 3.
  252.      *
  253.      * It uses the placement
  254.      *
  255.      * 1 2
  256.      * 0 3
  257.      *
  258.      * @param c The character to get the relative position of.
  259.      * @param size The width / height of the virtual frame.
  260.      * @return A point, representing the virtual position of the character. Will return null if the character isn't valid (0,1,2,3).
  261.      */
  262.     private static Point charToPoint(char c, int size){
  263.        
  264.         int x = size/2;
  265.        
  266.         switch(c){
  267.             case '0':
  268.                 return new Point(0, x);
  269.             case '1':
  270.                 return new Point(0, 0);
  271.             case '2':
  272.                 return new Point(x, 0);
  273.             case '3':
  274.                 return new Point(x, x);
  275.         }
  276.        
  277.         return null;
  278.     }
  279.    
  280.     /**
  281.      * Recursive function for finding the position (x,y) of a string.
  282.      * @param s The string to get the position of.
  283.      * @param size The width / height of the frame.
  284.      * @return A point representing the position of the string.
  285.      */
  286.     private static Point stringToPoint(String s, int size){
  287.         if(s.length() == 1){
  288.             return charToPoint(s.charAt(0), size);
  289.         }
  290.        
  291.         Point p = charToPoint(s.charAt(0), size);
  292.         Point q = stringToPoint(s.substring(1), size/2);
  293.        
  294.         return new Point(p.x + q.x, p.y + q.y);
  295.     }
  296.    
  297.     private static double decreaseAmount = 0.75;
  298.     private static double[] probs = {0.333, 0.333, 0.333};
  299.    
  300.     /**
  301.      * Generate a random regular expression.
  302.      * @param x The 'length' of the expression.
  303.      * @return A random regular expression.
  304.      */
  305.     public static String randomRegExp(double x){
  306.         double newX = x * decreaseAmount;
  307.         double s = Math.random();
  308.        
  309.         if(s <= probs[0]*x){
  310.             return randomRegExp(newX) + "+" + randomRegExp(newX);
  311.         }
  312.         s-= probs[0]*x;
  313.        
  314.         if(s <= probs[1]*x){
  315.             return "[" + randomRegExp(newX) + "][" + randomRegExp(newX) + "]";
  316.         }
  317.         s-= probs[1]*x;
  318.        
  319.         if(s <= probs[2]*x){
  320.             return "[" + randomRegExp(newX) + "]*";
  321.         }
  322.        
  323.         return Integer.toString((int)Math.floor(4*Math.random()));
  324.        
  325.     }
  326. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement