working on ui refresh for books
[fanfix.git] / src / be / nikiroo / fanfix_swing / gui / book / BookCoverImager.java
CommitLineData
3cdf3fd8
NR
1package be.nikiroo.fanfix_swing.gui.book;
2
3import java.awt.Color;
4import java.awt.Graphics;
5import java.awt.Graphics2D;
6import java.awt.Polygon;
7import java.awt.Rectangle;
8import java.awt.image.BufferedImage;
9import java.io.ByteArrayInputStream;
10import java.io.ByteArrayOutputStream;
11import java.io.IOException;
12import java.io.InputStream;
13import java.net.MalformedURLException;
14
15import javax.imageio.ImageIO;
16
17import be.nikiroo.fanfix.Instance;
3cdf3fd8
NR
18import be.nikiroo.fanfix.library.BasicLibrary;
19import be.nikiroo.fanfix.reader.ui.GuiReaderBookInfo;
20import be.nikiroo.utils.Image;
21import be.nikiroo.utils.ui.ImageUtilsAwt;
22import be.nikiroo.utils.ui.UIUtils;
23
24/**
25 * This class can create a cover icon ready to use for the graphical
26 * application.
27 *
28 * @author niki
29 */
30class BookCoverImager {
31 // TODO: export some of the configuration options?
32 static final int COVER_WIDTH = 100;
33 static final int COVER_HEIGHT = 150;
34 static final int SPINE_WIDTH = 5;
35 static final int SPINE_HEIGHT = 5;
36 static final int HOFFSET = 20;
37 static final Color SPINE_COLOR_BOTTOM = new Color(180, 180, 180);
38 static final Color SPINE_COLOR_RIGHT = new Color(100, 100, 100);
39 static final Color BORDER = Color.black;
40
6bf49e68
NR
41 public static final Color UNCACHED_ICON_COLOR = Color.green.darker();
42 // new Color(0, 80, 220);
89f2c479 43
3cdf3fd8
NR
44 public static final int TEXT_HEIGHT = 50;
45 public static final int TEXT_WIDTH = COVER_WIDTH + 40;
46
47 //
48
49 static public Color getBackground(boolean enabled, boolean selected, boolean hovered) {
50 Color color = new Color(255, 255, 255, 0);
51 if (!enabled) {
52 } else if (selected && !hovered) {
53 color = new Color(80, 80, 100, 40);
54 } else if (!selected && hovered) {
55 color = new Color(230, 230, 255, 100);
56 } else if (selected && hovered) {
57 color = new Color(200, 200, 255, 100);
58 }
59
60 return color;
61 }
62
63 /**
64 * Draw a partially transparent overlay if needed depending upon the selection
65 * and mouse-hover states on top of the normal component, as well as a possible
66 * "cached" icon if the item is cached.
67 *
68 * @param g the {@link Graphics} to paint onto
69 * @param enabled draw an enabled overlay
70 * @param selected draw a selected overlay
71 * @param hovered draw a hovered overlay
72 * @param cached draw a non-cached overlay if needed
73 */
74 static public void paintOverlay(Graphics g, boolean enabled, boolean selected, boolean hovered, boolean cached) {
75 Rectangle clip = g.getClipBounds();
76 if (clip.getWidth() <= 0 || clip.getHeight() <= 0) {
77 return;
78 }
79
80 int h = COVER_HEIGHT;
81 int w = COVER_WIDTH;
82 int xOffset = (TEXT_WIDTH - COVER_WIDTH) - 1;
83 int yOffset = HOFFSET;
84
85 if (BORDER != null) {
86 if (BORDER != null) {
87 g.setColor(BORDER);
88 g.drawRect(xOffset, yOffset, COVER_WIDTH, COVER_HEIGHT);
89 }
90
91 xOffset++;
92 yOffset++;
93 }
94
95 int[] xs = new int[] { xOffset, xOffset + SPINE_WIDTH, xOffset + w + SPINE_WIDTH, xOffset + w };
96 int[] ys = new int[] { yOffset + h, yOffset + h + SPINE_HEIGHT, yOffset + h + SPINE_HEIGHT, yOffset + h };
97 g.setColor(SPINE_COLOR_BOTTOM);
98 g.fillPolygon(new Polygon(xs, ys, xs.length));
99 xs = new int[] { xOffset + w, xOffset + w + SPINE_WIDTH, xOffset + w + SPINE_WIDTH, xOffset + w };
100 ys = new int[] { yOffset, yOffset + SPINE_HEIGHT, yOffset + h + SPINE_HEIGHT, yOffset + h };
101 g.setColor(SPINE_COLOR_RIGHT);
102 g.fillPolygon(new Polygon(xs, ys, xs.length));
103
104 Color color = getBackground(enabled, selected, hovered);
105
106 g.setColor(color);
107 g.fillRect(clip.x, clip.y, clip.width, clip.height);
108
6bf49e68 109 UIUtils.drawEllipse3D(g, UNCACHED_ICON_COLOR, COVER_WIDTH + HOFFSET + 30, 10, 20, 20, cached);
3cdf3fd8
NR
110 }
111
3cdf3fd8
NR
112 /**
113 * The width of a cover image.
114 *
115 * @return the width
116 */
117 static public int getCoverWidth() {
118 return SPINE_WIDTH + COVER_WIDTH;
119 }
120
121 /**
122 * The height of a cover image.
123 *
124 * @return the height
125 */
126 static public int getCoverHeight() {
127 return COVER_HEIGHT + HOFFSET;
128 }
129
130 /**
131 * Generate a cover icon based upon the given {@link GuiReaderBookInfo}.
132 *
133 * @param lib the library the meta comes from (can be NULL)
134 * @param info the {@link GuiReaderBookInfo}
135 *
136 * @return the image
137 */
138 static public java.awt.Image generateCoverImage(BasicLibrary lib, BookInfo info) {
139 BufferedImage resizedImage = null;
140 String id = getIconId(info);
141
142 InputStream in = Instance.getInstance().getCache().getFromCache(id);
143 if (in != null) {
144 try {
145 resizedImage = ImageUtilsAwt.fromImage(new Image(in));
146 in.close();
147 in = null;
148 } catch (IOException e) {
149 Instance.getInstance().getTraceHandler().error(e);
150 }
151 }
152
153 if (resizedImage == null) {
154 try {
155 Image cover = null;
156 if (info != null) {
157 cover = info.getBaseImage(lib);
158 }
159
160 resizedImage = new BufferedImage(getCoverWidth(), getCoverHeight(), BufferedImage.TYPE_4BYTE_ABGR);
161
162 Graphics2D g = resizedImage.createGraphics();
163 try {
bdded4b5
NR
164 if (info != null && info.supportsCover()) {
165 g.setColor(Color.white);
166 g.fillRect(0, HOFFSET, COVER_WIDTH, COVER_HEIGHT);
167
168 if (cover != null) {
169 BufferedImage coverb = ImageUtilsAwt.fromImage(cover);
170 g.drawImage(coverb, 0, HOFFSET, COVER_WIDTH, COVER_HEIGHT, null);
171 } else {
172 g.setColor(Color.black);
173 g.drawLine(0, HOFFSET, COVER_WIDTH, HOFFSET + COVER_HEIGHT);
174 g.drawLine(COVER_WIDTH, HOFFSET, 0, HOFFSET + COVER_HEIGHT);
175 }
3cdf3fd8
NR
176 }
177 } finally {
178 g.dispose();
179 }
180
181 // Only save image with a cover, not the X thing
182 if (id != null && cover != null) {
183 ByteArrayOutputStream out = new ByteArrayOutputStream();
184 ImageIO.write(resizedImage, "png", out);
185 byte[] imageBytes = out.toByteArray();
186 in = new ByteArrayInputStream(imageBytes);
187 Instance.getInstance().getCache().addToCache(in, id);
188 in.close();
189 in = null;
190 }
191 } catch (MalformedURLException e) {
192 Instance.getInstance().getTraceHandler().error(e);
193 } catch (IOException e) {
194 Instance.getInstance().getTraceHandler().error(e);
195 }
196 }
197
198 return resizedImage;
199 }
200
201 /**
202 * Manually clear the icon set for this item.
203 *
204 * @param info the info about the story or source/type or author
205 */
206 static public void clearIcon(BookInfo info) {
207 String id = getIconId(info);
208 Instance.getInstance().getCache().removeFromCache(id);
209 }
210
211 /**
212 * Get a unique ID from this {@link GuiReaderBookInfo} (note that it can be a
213 * story, a fake item for a source/type or a fake item for an author).
214 *
215 * @param info the info or NULL for a generic (non unique!) ID
216 * @return the unique ID
217 */
218 static private String getIconId(BookInfo info) {
219 return (info == null ? "" : info.getId() + ".") + "book-thumb_" + SPINE_WIDTH + "x" + COVER_WIDTH + "+"
220 + SPINE_HEIGHT + "+" + COVER_HEIGHT + "@" + HOFFSET;
221 }
222}