--- /dev/null
+package be.nikiroo.jvcard.tui;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+
+import com.googlecode.lanterna.TerminalSize;
+
+public class ImageText {
+ private Image image;
+ private TerminalSize size;
+ private String text;
+ private boolean ready;
+
+ public ImageText(Image image, TerminalSize size) {
+ setImage(image, size);
+ }
+
+ public void setImage(Image image) {
+ setImage(image, size);
+ }
+
+ public void setImage(TerminalSize size) {
+ setImage(image, size);
+ }
+
+ public void setImage(Image image, TerminalSize size) {
+ this.text = null;
+ this.ready = false;
+ this.size = size;
+ if (image != null) {
+ this.image = image;
+ }
+ }
+
+ public String getText() {
+ if (text == null) {
+ if (image == null)
+ return "";
+
+ int w = size.getColumns() * 2;
+ int h = size.getRows() * 2;
+ BufferedImage buff = new BufferedImage(w, h,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics gfx = buff.getGraphics();
+
+ TerminalSize srcSize = getSize(image);
+ int x = 0;
+ int y = 0;
+ if (srcSize.getColumns() > srcSize.getRows()) {
+ double ratio = (double) srcSize.getRows()
+ / (double) srcSize.getColumns();
+ h = (int) Math.round(ratio * h);
+ y = (buff.getHeight() - h) / 2;
+ } else {
+ double ratio = (double) srcSize.getColumns()
+ / (double) srcSize.getRows();
+ w = (int) Math.round(ratio * w);
+ x = (buff.getWidth() - w) / 2;
+
+ }
+
+ if (gfx.drawImage(image, x, y, w, h, new ImageObserver() {
+ @Override
+ public boolean imageUpdate(Image img, int infoflags, int x,
+ int y, int width, int height) {
+ ImageText.this.ready = true;
+ return true;
+ }
+ })) {
+ ready = true;
+ }
+
+ while (!ready) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ gfx.dispose();
+
+ int[][] square = new int[2][2];
+ StringBuilder builder = new StringBuilder();
+ for (int row = 0; row < buff.getHeight(); row += 2) {
+ if (row > 0)
+ builder.append('\n');
+
+ for (int col = 0; col < buff.getWidth(); col += 2) {
+ square[0][0] = buff.getRGB(col, row);
+ square[0][1] = buff.getRGB(col, row + 1);
+ square[1][0] = buff.getRGB(col + 1, row);
+ square[1][1] = buff.getRGB(col + 1, row + 1);
+ builder.append(getChar(square));
+ }
+ }
+
+ text = builder.toString();
+ }
+
+ return text;
+ }
+
+ @Override
+ public String toString() {
+ return getText();
+ }
+
+ static private TerminalSize getSize(Image img) {
+ TerminalSize size = null;
+ while (size == null) {
+ int w = img.getWidth(null);
+ int h = img.getHeight(null);
+ if (w > -1 && h > -1) {
+ size = new TerminalSize(w, h);
+ } else {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ return size;
+ }
+
+ static private char getChar(int[][] square) {
+ int choice = 0;
+ if (rgb2hsl(square[0][0])[3] > 50)
+ choice += 1;
+ if (rgb2hsl(square[0][1])[3] > 50)
+ choice += 2;
+ if (rgb2hsl(square[1][0])[3] > 50)
+ choice += 4;
+ if (rgb2hsl(square[1][1])[3] > 50)
+ choice += 8;
+
+ switch (choice) {
+ case 0:
+ return ' ';
+ case 1:
+ return '▘';
+ case 2:
+ return '▝';
+ case 3:
+ return '▀';
+ case 4:
+ return '▖';
+ case 5:
+ return '▌';
+ case 6:
+ return '▞';
+ case 7:
+ return '▛';
+ case 8:
+ return '▗';
+ case 9:
+ return '▚';
+ case 10:
+ return '▐';
+ case 11:
+ return '▜';
+ case 12:
+ return '▄';
+ case 13:
+ return '▙';
+ case 14:
+ return '▟';
+ case 15:
+ return '█';
+ }
+
+ return ' ';
+ }
+
+ // return [a, h, s, l]; a/s/l: 0 to 100%, h = 0 to 359°
+ static int[] rgb2hsl(int argb) {
+ double a, r, g, b;
+ a = ((argb & 0xff000000) >> 24) / 255.0;
+ r = ((argb & 0x00ff0000) >> 16) / 255.0;
+ g = ((argb & 0x0000ff00) >> 8) / 255.0;
+ b = ((argb & 0x000000ff)) / 255.0;
+
+ double rgbMin, rgbMax;
+ rgbMin = Math.min(r, Math.min(g, b));
+ rgbMax = Math.max(r, Math.max(g, b));
+
+ double l;
+ l = (rgbMin + rgbMax) / 2;
+
+ double s;
+ if (rgbMin == rgbMax) {
+ s = 0;
+ } else {
+ if (l <= 0.5) {
+ s = (rgbMax - rgbMin) / (rgbMax + rgbMin);
+ } else {
+ s = (rgbMax - rgbMin) / (2.0 - rgbMax - rgbMin);
+ }
+ }
+
+ double h;
+ if (r > g && r > b) {
+ h = (g - b) / (rgbMax - rgbMin);
+ } else if (g > b) {
+ h = 2.0 + (b - r) / (rgbMax - rgbMin);
+ } else {
+ h = 4.0 + (r - g) / (rgbMax - rgbMin);
+ }
+
+ int aa = (int) Math.round(100 * a);
+ int hh = (int) (60 * h);
+ if (hh < 0)
+ hh += 360;
+ int ss = (int) Math.round(100 * s);
+ int ll = (int) Math.round(100 * l);
+
+ return new int[] { aa, hh, ss, ll };
+ }
+}
--- /dev/null
+package be.nikiroo.jvcard.tui.panes;
+
+import java.awt.Image;
+import java.util.Base64;
+import java.util.List;
+
+import javax.swing.ImageIcon;
+
+import be.nikiroo.jvcard.Contact;
+import be.nikiroo.jvcard.Data;
+import be.nikiroo.jvcard.TypeInfo;
+import be.nikiroo.jvcard.tui.ImageText;
+import be.nikiroo.jvcard.tui.KeyAction;
+import be.nikiroo.jvcard.tui.KeyAction.DataType;
+
+import com.googlecode.lanterna.TerminalSize;
+import com.googlecode.lanterna.gui2.BorderLayout;
+import com.googlecode.lanterna.gui2.Panel;
+import com.googlecode.lanterna.gui2.TextBox;
+
+public class ContactDetails extends MainContent {
+ private Contact contact;
+
+ @Override
+ public DataType getDataType() {
+ return DataType.DATA;
+ }
+
+ @Override
+ public List<KeyAction> getKeyBindings() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ContactDetails(Contact contact) {
+ this.contact = contact;
+
+ BorderLayout blayout = new BorderLayout();
+ setLayoutManager(blayout);
+
+ Panel top = new Panel();
+ if (contact != null) {
+ Data photo = contact.getPreferredData("PHOTO");
+ if (photo != null) {
+ TypeInfo encoding = null;
+ TypeInfo type = null;
+ for (TypeInfo info : photo.getTypes()) {
+ if (info.getName() != null) {
+ if (info.getName().equalsIgnoreCase("ENCODING"))
+ encoding = info;
+ if (info.getName().equalsIgnoreCase("TYPE"))
+ type = info;
+ }
+ }
+
+ if (encoding != null && encoding.getValue() != null
+ && encoding.getValue().equalsIgnoreCase("b")) {
+
+ Image img = new ImageIcon(Base64.getDecoder().decode(
+ photo.getValue())).getImage();
+
+ TerminalSize size = new TerminalSize(40, 20);
+ size = new TerminalSize(120, 50);
+
+ String str = new ImageText(img, size).getText();
+ top.addComponent(new TextBox(size, str));
+ }
+ }
+ }
+
+ addComponent(top, BorderLayout.Location.TOP);
+ }
+}