Add text-image control and separate Edit/View contact
[jvcard.git] / src / be / nikiroo / jvcard / tui / ImageText.java
1 package be.nikiroo.jvcard.tui;
2
3 import java.awt.Graphics;
4 import java.awt.Image;
5 import java.awt.image.BufferedImage;
6 import java.awt.image.ImageObserver;
7
8 import com.googlecode.lanterna.TerminalSize;
9
10 public class ImageText {
11 private Image image;
12 private TerminalSize size;
13 private String text;
14 private boolean ready;
15
16 public ImageText(Image image, TerminalSize size) {
17 setImage(image, size);
18 }
19
20 public void setImage(Image image) {
21 setImage(image, size);
22 }
23
24 public void setImage(TerminalSize size) {
25 setImage(image, size);
26 }
27
28 public void setImage(Image image, TerminalSize size) {
29 this.text = null;
30 this.ready = false;
31 this.size = size;
32 if (image != null) {
33 this.image = image;
34 }
35 }
36
37 public String getText() {
38 if (text == null) {
39 if (image == null)
40 return "";
41
42 int w = size.getColumns() * 2;
43 int h = size.getRows() * 2;
44 BufferedImage buff = new BufferedImage(w, h,
45 BufferedImage.TYPE_INT_ARGB);
46 Graphics gfx = buff.getGraphics();
47
48 TerminalSize srcSize = getSize(image);
49 int x = 0;
50 int y = 0;
51 if (srcSize.getColumns() > srcSize.getRows()) {
52 double ratio = (double) srcSize.getRows()
53 / (double) srcSize.getColumns();
54 h = (int) Math.round(ratio * h);
55 y = (buff.getHeight() - h) / 2;
56 } else {
57 double ratio = (double) srcSize.getColumns()
58 / (double) srcSize.getRows();
59 w = (int) Math.round(ratio * w);
60 x = (buff.getWidth() - w) / 2;
61
62 }
63
64 if (gfx.drawImage(image, x, y, w, h, new ImageObserver() {
65 @Override
66 public boolean imageUpdate(Image img, int infoflags, int x,
67 int y, int width, int height) {
68 ImageText.this.ready = true;
69 return true;
70 }
71 })) {
72 ready = true;
73 }
74
75 while (!ready) {
76 try {
77 Thread.sleep(100);
78 } catch (InterruptedException e) {
79 }
80 }
81
82 gfx.dispose();
83
84 int[][] square = new int[2][2];
85 StringBuilder builder = new StringBuilder();
86 for (int row = 0; row < buff.getHeight(); row += 2) {
87 if (row > 0)
88 builder.append('\n');
89
90 for (int col = 0; col < buff.getWidth(); col += 2) {
91 square[0][0] = buff.getRGB(col, row);
92 square[0][1] = buff.getRGB(col, row + 1);
93 square[1][0] = buff.getRGB(col + 1, row);
94 square[1][1] = buff.getRGB(col + 1, row + 1);
95 builder.append(getChar(square));
96 }
97 }
98
99 text = builder.toString();
100 }
101
102 return text;
103 }
104
105 @Override
106 public String toString() {
107 return getText();
108 }
109
110 static private TerminalSize getSize(Image img) {
111 TerminalSize size = null;
112 while (size == null) {
113 int w = img.getWidth(null);
114 int h = img.getHeight(null);
115 if (w > -1 && h > -1) {
116 size = new TerminalSize(w, h);
117 } else {
118 try {
119 Thread.sleep(100);
120 } catch (InterruptedException e) {
121 }
122 }
123 }
124
125 return size;
126 }
127
128 static private char getChar(int[][] square) {
129 int choice = 0;
130 if (rgb2hsl(square[0][0])[3] > 50)
131 choice += 1;
132 if (rgb2hsl(square[0][1])[3] > 50)
133 choice += 2;
134 if (rgb2hsl(square[1][0])[3] > 50)
135 choice += 4;
136 if (rgb2hsl(square[1][1])[3] > 50)
137 choice += 8;
138
139 switch (choice) {
140 case 0:
141 return ' ';
142 case 1:
143 return '▘';
144 case 2:
145 return '▝';
146 case 3:
147 return '▀';
148 case 4:
149 return '▖';
150 case 5:
151 return '▌';
152 case 6:
153 return '▞';
154 case 7:
155 return '▛';
156 case 8:
157 return '▗';
158 case 9:
159 return '▚';
160 case 10:
161 return '▐';
162 case 11:
163 return '▜';
164 case 12:
165 return '▄';
166 case 13:
167 return '▙';
168 case 14:
169 return '▟';
170 case 15:
171 return '█';
172 }
173
174 return ' ';
175 }
176
177 // return [a, h, s, l]; a/s/l: 0 to 100%, h = 0 to 359°
178 static int[] rgb2hsl(int argb) {
179 double a, r, g, b;
180 a = ((argb & 0xff000000) >> 24) / 255.0;
181 r = ((argb & 0x00ff0000) >> 16) / 255.0;
182 g = ((argb & 0x0000ff00) >> 8) / 255.0;
183 b = ((argb & 0x000000ff)) / 255.0;
184
185 double rgbMin, rgbMax;
186 rgbMin = Math.min(r, Math.min(g, b));
187 rgbMax = Math.max(r, Math.max(g, b));
188
189 double l;
190 l = (rgbMin + rgbMax) / 2;
191
192 double s;
193 if (rgbMin == rgbMax) {
194 s = 0;
195 } else {
196 if (l <= 0.5) {
197 s = (rgbMax - rgbMin) / (rgbMax + rgbMin);
198 } else {
199 s = (rgbMax - rgbMin) / (2.0 - rgbMax - rgbMin);
200 }
201 }
202
203 double h;
204 if (r > g && r > b) {
205 h = (g - b) / (rgbMax - rgbMin);
206 } else if (g > b) {
207 h = 2.0 + (b - r) / (rgbMax - rgbMin);
208 } else {
209 h = 4.0 + (r - g) / (rgbMax - rgbMin);
210 }
211
212 int aa = (int) Math.round(100 * a);
213 int hh = (int) (60 * h);
214 if (hh < 0)
215 hh += 360;
216 int ss = (int) Math.round(100 * s);
217 int ll = (int) Math.round(100 * l);
218
219 return new int[] { aa, hh, ss, ll };
220 }
221 }