Skip to content

Image render #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@

**/target/

.idea/

### IntelliJ IDEA ###
.idea
out
*.iws
*.iml
*.ipr
out/

cov-int/
java-ascii-render.tgz

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ public interface ICanvas {
*/
String getText();

/**
* One line of canvas, without trailed new line symbol.
*
* @param index index of line, from top to bottom
* @return
*/
String getLine(int index);

/**
* Height of canvas.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.indvd00m.ascii.render.api;

import java.awt.image.BufferedImage;

/**
* An image render. Image render can create and render images from {@link ICanvas}.
*
* @author indvd00m (gotoindvdum[at]gmail[dot]com)
* @since 2.3.0
*/
public interface IImageRender {

/**
* Render canvas to image. Width of image will be calculated
*
* @param canvas canvas of text
* @param height height of image in pixels
* @return
*/
BufferedImage render(ICanvas canvas, int height);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.indvd00m.ascii.render.api.ICanvas;
import com.indvd00m.ascii.render.api.IRegion;
import com.indvd00m.ascii.render.util.AsciiUtils;

import java.util.ArrayList;
import java.util.Iterator;
Expand All @@ -13,7 +14,8 @@
*/
public class Canvas implements ICanvas {

public static final char NULL_CHAR = '\0';
@Deprecated
public static final char NULL_CHAR = AsciiUtils.NULL_CHAR;

protected final int width;
protected final int height;
Expand Down Expand Up @@ -149,6 +151,11 @@ public String getText() {
return cachedText;
}

@Override
public String getLine(int index) {
return lines.get(index).toString().replace(NULL_CHAR, ' ');
}

@Override
public String toString() {
return getText();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.indvd00m.ascii.render;

import com.indvd00m.ascii.render.api.ICanvas;
import com.indvd00m.ascii.render.api.IImageRender;
import com.indvd00m.ascii.render.util.AsciiUtils;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

import static com.indvd00m.ascii.render.util.AsciiUtils.repeatChar;

/**
* @author indvd00m (gotoindvdum[at]gmail[dot]com)
* @since 2.3.0
*/
public class ImageRender implements IImageRender {

public static final int FONT_REPLICA_STYLE = 24;
public static final char SAMPLE_SYMBOL = ' ';
protected final Font font;

public ImageRender() {
this(AsciiUtils.readDejaVuSansMonoFont());
}

/**
* @param font monospaced font
*/
public ImageRender(Font font) {
this.font = font;
}

@Override
public BufferedImage render(final ICanvas canvas, final int height) {
int textWidth = canvas.getWidth();
int textHeight = canvas.getHeight();

Font fontReplica = getFont().deriveFont(FONT_REPLICA_STYLE);

final int ascent;
final int leading;
final int linesWidth;
float lineHeight = ((float) height) / textHeight;

{
int sampleWidth = (int) ((float) height * textWidth / textHeight);
String sampleString = repeatChar(SAMPLE_SYMBOL, textWidth);
BufferedImage sampleImage = new BufferedImage(sampleWidth, height, BufferedImage.TYPE_INT_RGB);
Graphics2D sampleGraphics = sampleImage.createGraphics();
sampleGraphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
sampleGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);

FontMetrics fm = sampleGraphics.getFontMetrics(fontReplica);
Rectangle2D r2d = fm.getStringBounds(sampleString, sampleGraphics);
float leadingFactor = (float) fm.getLeading() / fm.getHeight();
float size = (float) (fontReplica.getSize2D() * lineHeight / (r2d.getHeight() - r2d.getHeight() * leadingFactor));
fontReplica = fontReplica.deriveFont(size);
fm = sampleGraphics.getFontMetrics(fontReplica);
ascent = fm.getAscent();
leading = fm.getLeading();
linesWidth = (int) fm.getStringBounds(sampleString, sampleGraphics).getWidth();
}

BufferedImage image = new BufferedImage(linesWidth, height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = image.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);

Color fontColor = Color.BLACK;
Color backgroundColor = Color.WHITE;

graphics.setFont(fontReplica);
graphics.setColor(backgroundColor);
graphics.fillRect(0, 0, linesWidth, height);
graphics.setColor(fontColor);
for (int i = 0; i < textHeight; i++) {
String line = canvas.getLine(i);
graphics.drawString(line, 0, lineHeight * i + ascent + leading);
}

return image;
}


public Font getFont() {
return font;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@
import com.indvd00m.ascii.render.api.IElement;
import com.indvd00m.ascii.render.api.IPoint;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import static com.indvd00m.ascii.render.util.AsciiUtils.readDejaVuSansMonoFont;

/**
* PseudoText element. Default font DejaVu Sans Mono.
Expand Down Expand Up @@ -149,7 +147,7 @@ public IPoint draw(ICanvas canvas, IContext context) {
graphics.setColor(fontColor);
graphics.drawString(text, 0, ascent + leading);

// writeImageToPNG(image, "/tmp/pseudotext.png");
// AsciiUtils.writeImageToPNG(image, "/tmp/pseudotext.png");

for (int imgX = 0; imgX < width; imgX++) {
for (int imgY = 0; imgY < height; imgY++) {
Expand Down Expand Up @@ -205,35 +203,6 @@ protected double getColorDistance(Color c1, Color c2) {
return Math.sqrt(weightR * r * r + weightG * g * g + weightB * b * b);
}

protected Font createFont() {
InputStream is = null;
try {
is = getClass().getResourceAsStream("/fonts/DejaVuSansMono/DejaVuSansMono.ttf");
Font font = Font.createFont(Font.TRUETYPE_FONT, is);
return font;
} catch (FontFormatException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}

protected void writeImageToPNG(BufferedImage image, String path) {
try {
ImageIO.write(image, "png", new File(path));
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public String getText() {
return text;
}
Expand All @@ -252,7 +221,7 @@ public int getHeight() {

public Font getFont() {
if (font == null) {
font = createFont();
font = readDejaVuSansMonoFont();
}
return font;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.indvd00m.ascii.render.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
* @author indvd00m (gotoindvdum[at]gmail[dot]com)
* @since 2.3.0
*/
public class AsciiUtils {

public static final char NULL_CHAR = '\0';
public static final String PNG_FORMAT = "png";

public static String repeatChar(char c, int count) {
return repeatString(c + "", count);
}

public static String repeatString(String s, int count) {
String repeated = new String(new char[count]).replace(NULL_CHAR + "", s);
return repeated;
}

public static Font readDejaVuSansMonoFont() {
InputStream is = null;
try {
is = AsciiUtils.class.getResourceAsStream("/fonts/DejaVuSansMono/DejaVuSansMono.ttf");
Font font = Font.createFont(Font.TRUETYPE_FONT, is);
return font;
} catch (FontFormatException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}

public static void writeImageToPNG(BufferedImage image, String path) {
try {
ImageIO.write(image, PNG_FORMAT, new File(path));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Loading