replace manual image manipulation with our own new clj-image2ascii lib
This commit is contained in:
parent
7c29069559
commit
aae01476a0
|
@ -13,6 +13,7 @@
|
|||
[environ "0.4.0"]
|
||||
[clj-metasearch "0.1.1"]
|
||||
[clj-figlet "0.1.1"]
|
||||
[clj-image2ascii "0.1.0-SNAPSHOT"]
|
||||
[com.cemerick/url "0.1.1"]
|
||||
[criterium "0.4.3" :scope "test"]]
|
||||
:source-paths ["src/clojure"]
|
||||
|
|
|
@ -1,57 +1,19 @@
|
|||
(ns toascii.models.image
|
||||
(:import (java.awt RenderingHints Graphics2D Image)
|
||||
(java.awt.image BufferedImage Raster)
|
||||
(javax.imageio ImageIO)
|
||||
(java.io File)
|
||||
(java.net URL)
|
||||
(toascii.images ImageToAscii))
|
||||
(:require [clojure.string :as str]
|
||||
[cemerick.url :as url]
|
||||
[toascii.util :refer [query-param-url->java-url]])
|
||||
(:import (java.awt.image BufferedImage))
|
||||
(:require [toascii.util :refer [query-param-url->java-url]]
|
||||
[clj-image2ascii.core :as i2a])
|
||||
(:use hiccup.core))
|
||||
|
||||
(defn get-image-by-url
|
||||
(^BufferedImage [^String url]
|
||||
(try
|
||||
(let [java-url (query-param-url->java-url url)]
|
||||
(ImageIO/read java-url))
|
||||
(catch Exception ex))))
|
||||
|
||||
(defn get-image-by-file
|
||||
"returns a BufferedImage loaded from the file specified, or null if an error occurs."
|
||||
(^BufferedImage [^File file]
|
||||
(try
|
||||
(ImageIO/read file)
|
||||
(catch Exception ex))))
|
||||
|
||||
(defn scale-image
|
||||
"takes a source image specified by the uri (a filename or a URL) and scales it proportionally
|
||||
using the new width, returning the newly scaled image."
|
||||
(^BufferedImage [^BufferedImage image new-width]
|
||||
(let [new-height (* (/ new-width (.getWidth image))
|
||||
(.getHeight image))
|
||||
scaled-image (BufferedImage. new-width new-height BufferedImage/TYPE_INT_RGB)
|
||||
gfx2d (doto (.createGraphics scaled-image)
|
||||
(.setRenderingHint RenderingHints/KEY_INTERPOLATION
|
||||
RenderingHints/VALUE_INTERPOLATION_BILINEAR)
|
||||
(.drawImage image 0 0 new-width new-height nil)
|
||||
(.dispose))]
|
||||
scaled-image)))
|
||||
|
||||
(defn convert-image
|
||||
"converts the image to an ascii representation. a multiline string will be returned,
|
||||
which will be formatted for html if color? is true, or plain text if false. if
|
||||
scale-to-width is specified the resulting image will be scaled proportionally from
|
||||
the source image."
|
||||
([^BufferedImage image color?]
|
||||
(convert-image image nil color?))
|
||||
([^BufferedImage image scale-to-width color?]
|
||||
(let [current-width (.getWidth image)
|
||||
new-width (or scale-to-width current-width)
|
||||
final-image (if-not (= new-width current-width)
|
||||
(scale-image image new-width)
|
||||
image)]
|
||||
(ImageToAscii/convert final-image color?))))
|
||||
(defn get-image [^String url]
|
||||
(let [java-url (query-param-url->java-url url)]
|
||||
(i2a/get-image-by-url java-url)))
|
||||
|
||||
(defn wrap-pre-tag [s]
|
||||
(str "<pre style=\"font-size:6pt; letter-spacing:1px; line-height:5pt; font-weight:bold;\">" s "</pre>"))
|
||||
(str "<pre style=\"font-size:6pt; letter-spacing:1px; line-height:5pt; font-weight:bold;\">" s "</pre>"))
|
||||
|
||||
(defn image->ascii [^BufferedImage image scale-to-width color? html?]
|
||||
(let [converted (i2a/convert-image image scale-to-width color?)
|
||||
ascii (:image converted)]
|
||||
(if html?
|
||||
(wrap-pre-tag ascii)
|
||||
ascii)))
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
[liberator.core :refer [defresource]]
|
||||
[compojure.core :refer [ANY]]
|
||||
[toascii.route-utils :refer [register-routes]]
|
||||
[toascii.models.image :refer [convert-image get-image-by-url wrap-pre-tag]]
|
||||
[toascii.models.image :refer [image->ascii get-image]]
|
||||
[toascii.util :refer [parse-int parse-boolean]]))
|
||||
|
||||
(defresource render-image [{:keys [url width color format] :as params}]
|
||||
|
@ -26,21 +26,15 @@
|
|||
(parse-boolean color)) {:error "Cannot output colored plain text version of image."}))
|
||||
:exists?
|
||||
(fn [_]
|
||||
(if-let [image (get-image-by-url url)]
|
||||
(if-let [image (get-image url)]
|
||||
{:image image}
|
||||
[false {:error "Image could not be loaded."}]))
|
||||
:handle-ok
|
||||
(fn [ctx]
|
||||
(let [html? (= "text/html" (get-in ctx [:representation :media-type]))
|
||||
color? (or (and html? (nil? color))
|
||||
(parse-boolean color))
|
||||
output (convert-image
|
||||
(:image ctx)
|
||||
(parse-int width)
|
||||
color?)]
|
||||
(if html?
|
||||
(wrap-pre-tag output)
|
||||
output)))
|
||||
(parse-boolean color))]
|
||||
(image->ascii (:image ctx) (parse-int width) color? html?)))
|
||||
:handle-malformed
|
||||
(fn [ctx]
|
||||
(:error ctx))
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
package toascii.images;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class ImageToAscii {
|
||||
static final char[] asciiChars = {'#', 'A', '@', '%', '$', '+', '=', '*', ':', ',', '.', ' '};
|
||||
static final int numAsciiChars = asciiChars.length - 1;
|
||||
static final int spanLength = "<span style=\"color:#112233;\">X</span>".length();
|
||||
static final int lineTerminatorLength = "<br>".length();
|
||||
|
||||
// copied from java.lang.Integer.digits (which is private so we can't just reference it, boourns)
|
||||
static final char[] digits = {
|
||||
'0' , '1' , '2' , '3' , '4' , '5' ,
|
||||
'6' , '7' , '8' , '9' , 'a' , 'b' ,
|
||||
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
|
||||
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
|
||||
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
|
||||
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
|
||||
};
|
||||
|
||||
// modification of java.lang.Integer.toUnsignedString -- no garbage generated, but limited to max value
|
||||
// of 255 ...hence the 'unsigned byte' thing :)
|
||||
private static void unsignedByteToHex(int unsignedByte, StringBuilder sb) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
int index = sb.length + 1 - i;
|
||||
if (unsignedByte != 0) {
|
||||
sb.chars[index] = digits[unsignedByte & 15];
|
||||
unsignedByte >>>= 4;
|
||||
} else
|
||||
sb.chars[index] = '0';
|
||||
}
|
||||
sb.length += 2;
|
||||
}
|
||||
|
||||
public static String convert(BufferedImage image, boolean useColor) {
|
||||
final int width = image.getWidth();
|
||||
final int height = image.getHeight();
|
||||
|
||||
final int maxLength = (useColor ?
|
||||
(width * height * spanLength) + (height * lineTerminatorLength) :
|
||||
(width * height) + height);
|
||||
|
||||
final StringBuilder sb = new StringBuilder(maxLength);
|
||||
|
||||
final int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
|
||||
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
final int argb = pixels[(y * width) + x];
|
||||
final int r = (0x00ff0000 & argb) >> 16;
|
||||
final int g = (0x0000ff00 & argb) >> 8;
|
||||
final int b = (0x000000ff & argb);
|
||||
final double brightness = Math.sqrt((r * r * 0.241f) +
|
||||
(g * g * 0.691f) +
|
||||
(b * b * 0.068f));
|
||||
int charIndex;
|
||||
if (brightness == 0.0f)
|
||||
charIndex = numAsciiChars;
|
||||
else
|
||||
charIndex = (int)((brightness / 255.0f) * numAsciiChars);
|
||||
|
||||
final char pixelChar = asciiChars[charIndex > 0 ? charIndex : 0];
|
||||
|
||||
if (useColor) {
|
||||
sb.append("<span style=\"color:#");
|
||||
unsignedByteToHex(r, sb);
|
||||
unsignedByteToHex(g, sb);
|
||||
unsignedByteToHex(b, sb);
|
||||
sb.append(";\">");
|
||||
sb.append(pixelChar);
|
||||
sb.append("</span>");
|
||||
} else
|
||||
sb.append(pixelChar);
|
||||
}
|
||||
if (useColor)
|
||||
sb.append("<br>");
|
||||
else
|
||||
sb.append('\n');
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
Binary file not shown.
Before Width: | Height: | Size: 135 KiB |
Reference in a new issue