BookLine: fixed size and highlight colour for the *
[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;
18import be.nikiroo.fanfix.data.MetaData;
19import be.nikiroo.fanfix.library.BasicLibrary;
20import be.nikiroo.fanfix.reader.ui.GuiReaderBookInfo;
21import be.nikiroo.utils.Image;
22import be.nikiroo.utils.ui.ImageUtilsAwt;
23import be.nikiroo.utils.ui.UIUtils;
24
25/**
26 * This class can create a cover icon ready to use for the graphical
27 * application.
28 *
29 * @author niki
30 */
31class BookCoverImager {
32 // TODO: export some of the configuration options?
33 static final int COVER_WIDTH = 100;
34 static final int COVER_HEIGHT = 150;
35 static final int SPINE_WIDTH = 5;
36 static final int SPINE_HEIGHT = 5;
37 static final int HOFFSET = 20;
38 static final Color SPINE_COLOR_BOTTOM = new Color(180, 180, 180);
39 static final Color SPINE_COLOR_RIGHT = new Color(100, 100, 100);
40 static final Color BORDER = Color.black;
41
89f2c479
NR
42 public static final Color UNCACHED_ICON_COLOR = new Color(0, 80, 220);
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
109 if (!cached) {
89f2c479 110 UIUtils.drawEllipse3D(g, UNCACHED_ICON_COLOR, COVER_WIDTH + HOFFSET + 30, 10, 20, 20);
3cdf3fd8
NR
111 }
112 }
113
114 /**
115 * Generate a cover icon based upon the given {@link MetaData}.
116 *
117 * @param lib the library the meta comes from
118 * @param meta the {@link MetaData}
119 *
120 * @return the image
121 */
122 static public java.awt.Image generateCoverImage(BasicLibrary lib, MetaData meta) {
123 return generateCoverImage(lib, BookInfo.fromMeta(lib, meta));
124 }
125
126 /**
127 * The width of a cover image.
128 *
129 * @return the width
130 */
131 static public int getCoverWidth() {
132 return SPINE_WIDTH + COVER_WIDTH;
133 }
134
135 /**
136 * The height of a cover image.
137 *
138 * @return the height
139 */
140 static public int getCoverHeight() {
141 return COVER_HEIGHT + HOFFSET;
142 }
143
144 /**
145 * Generate a cover icon based upon the given {@link GuiReaderBookInfo}.
146 *
147 * @param lib the library the meta comes from (can be NULL)
148 * @param info the {@link GuiReaderBookInfo}
149 *
150 * @return the image
151 */
152 static public java.awt.Image generateCoverImage(BasicLibrary lib, BookInfo info) {
153 BufferedImage resizedImage = null;
154 String id = getIconId(info);
155
156 InputStream in = Instance.getInstance().getCache().getFromCache(id);
157 if (in != null) {
158 try {
159 resizedImage = ImageUtilsAwt.fromImage(new Image(in));
160 in.close();
161 in = null;
162 } catch (IOException e) {
163 Instance.getInstance().getTraceHandler().error(e);
164 }
165 }
166
167 if (resizedImage == null) {
168 try {
169 Image cover = null;
170 if (info != null) {
171 cover = info.getBaseImage(lib);
172 }
173
174 resizedImage = new BufferedImage(getCoverWidth(), getCoverHeight(), BufferedImage.TYPE_4BYTE_ABGR);
175
176 Graphics2D g = resizedImage.createGraphics();
177 try {
178 g.setColor(Color.white);
179 g.fillRect(0, HOFFSET, COVER_WIDTH, COVER_HEIGHT);
180
181 if (cover != null) {
182 BufferedImage coverb = ImageUtilsAwt.fromImage(cover);
183 g.drawImage(coverb, 0, HOFFSET, COVER_WIDTH, COVER_HEIGHT, null);
184 } else {
185 g.setColor(Color.black);
186 g.drawLine(0, HOFFSET, COVER_WIDTH, HOFFSET + COVER_HEIGHT);
187 g.drawLine(COVER_WIDTH, HOFFSET, 0, HOFFSET + COVER_HEIGHT);
188 }
189 } finally {
190 g.dispose();
191 }
192
193 // Only save image with a cover, not the X thing
194 if (id != null && cover != null) {
195 ByteArrayOutputStream out = new ByteArrayOutputStream();
196 ImageIO.write(resizedImage, "png", out);
197 byte[] imageBytes = out.toByteArray();
198 in = new ByteArrayInputStream(imageBytes);
199 Instance.getInstance().getCache().addToCache(in, id);
200 in.close();
201 in = null;
202 }
203 } catch (MalformedURLException e) {
204 Instance.getInstance().getTraceHandler().error(e);
205 } catch (IOException e) {
206 Instance.getInstance().getTraceHandler().error(e);
207 }
208 }
209
210 return resizedImage;
211 }
212
213 /**
214 * Manually clear the icon set for this item.
215 *
216 * @param info the info about the story or source/type or author
217 */
218 static public void clearIcon(BookInfo info) {
219 String id = getIconId(info);
220 Instance.getInstance().getCache().removeFromCache(id);
221 }
222
223 /**
224 * Get a unique ID from this {@link GuiReaderBookInfo} (note that it can be a
225 * story, a fake item for a source/type or a fake item for an author).
226 *
227 * @param info the info or NULL for a generic (non unique!) ID
228 * @return the unique ID
229 */
230 static private String getIconId(BookInfo info) {
231 return (info == null ? "" : info.getId() + ".") + "book-thumb_" + SPINE_WIDTH + "x" + COVER_WIDTH + "+"
232 + SPINE_HEIGHT + "+" + COVER_HEIGHT + "@" + HOFFSET;
233 }
234}