1
2
3
4
5
6
7
8 package com.buckosoft.PicMan.business.mosaic.engine;
9
10 import java.awt.Graphics2D;
11 import java.awt.image.BufferedImage;
12 import java.util.HashMap;
13 import java.util.List;
14
15 import org.apache.commons.logging.Log;
16 import org.apache.commons.logging.LogFactory;
17
18 import com.buckosoft.PicMan.business.mosaic.MosaicEngine;
19 import com.buckosoft.PicMan.domain.MosaicTile;
20 import com.buckosoft.PicMan.domain.Pic;
21 import com.buckosoft.PicMan.domain.Thumbnail;
22
23
24
25
26
27
28
29 public class ThirdRibbon extends MosaicEngine {
30 private static final boolean DEBUG = true;
31 private static final boolean DEBUGDRAW = false;
32 private final Log logger = LogFactory.getLog(getClass());
33
34 private int curRow = 0;
35 private int[] curColsL;
36 private int[] curColsR;
37 private int[] pixels;
38 private int curCol;
39 private int maxRow;
40 private int maxCol;
41 private int startRow;
42 private int p;
43 private String curPicName;
44 private List<Pic> picList;
45 private HashMap<String, Double> rateMap;
46 private String info = "N/A";
47 private int[] used;
48 private int tileRows;
49 private String buildStep = "Idle";
50 private int pass = -1;
51 private long[][] rateL;
52 private long[][] rateR;
53 private Graphics2D gd;
54 private int baseX;
55 private int baseY;
56 private double rateWeight = 1.0;
57 private double usedWeight = 0.0;
58 private boolean workDoneL = false;
59 private boolean workDoneR = false;
60 private int reduceStyle = 0;
61
62 public ThirdRibbon() {
63 addConfig("baseX", "X offset of the base point", ConfigItem.TYPE_INT, 0);
64 addConfig("baseY", "Y offset of the base point", ConfigItem.TYPE_INT, 0);
65 addConfig("usedWeight", "Multiplier to reduce used pics", ConfigItem.TYPE_DOUBLE, 1.0);
66 addConfig("reduceStyle", "0=calc, 1=draw", ConfigItem.TYPE_INT, 1);
67 }
68
69
70
71
72 public String getStatus() {
73 StringBuilder sb = new StringBuilder();
74 sb.append(buildStep);
75 sb.append(": pass=");
76 sb.append(pass);
77 if (workDoneL || workDoneR)
78 sb.append(" ");
79 if (workDoneL)
80 sb.append("L");
81 if (workDoneR)
82 sb.append("R");
83 if (!buildStep.equals("Calc")) {
84 sb.append(" curRow = ");
85 sb.append(curRow);
86 sb.append(" curCol = ");
87 sb.append(curCol);
88 }
89 sb.append(" p=");
90 sb.append(p);
91 return(sb.toString());
92 }
93
94
95
96
97 public String getInfo() {
98 return(info);
99 }
100
101 protected boolean _build() {
102 jobLogEntry.setNote("Setup");
103 gd = bi.createGraphics();
104 baseX = (Integer)buildParameters.get("baseX");
105 baseY = (Integer)buildParameters.get("baseY");
106 rateWeight = (Double)buildParameters.get("rateWeight");
107 usedWeight = (Double)buildParameters.get("usedWeight");
108 reduceStyle = (Integer)buildParameters.get("reduceStyle");
109
110 picList = dbf.getPics(this.mosaicSet, tileHeight);
111 rateMap = new HashMap<String, Double>();
112 for (Pic pic : picList) {
113 double d = dbf.getPicRate(pic.getName(), this.mosaicSet, tileHeight);
114 rateMap.put(pic.getName(), new Double(d));
115
116
117 }
118 if (DEBUG)
119 logger.info("Working from " + picList.size() + " pics");
120 startRow = 0 - (baseY % tileHeight);
121 startRow = baseY % tileHeight;
122 if (startRow > 0)
123 startRow -= tileHeight;
124 maxRow = this.masterPic.getHeight();
125 maxCol = this.masterPic.getWidth();
126 pixels = bi.getRGB(0, 0, maxCol, maxRow, null, 0, maxCol);
127 tileRows = maxRow / tileHeight;
128 if (tileRows * tileHeight + startRow < maxRow)
129 tileRows++;
130 if (tileRows * tileHeight + startRow < maxRow)
131 tileRows++;
132 curColsL = new int[tileRows];
133 curColsR = new int[tileRows];
134 for (int i=0; i<tileRows; i++) {
135 curColsL[i] = baseX;
136 curColsR[i] = baseX;
137 }
138 rateL = new long[tileRows][picList.size()];
139 rateR = new long[tileRows][picList.size()];
140 used = new int[picList.size()];
141 info = "tileRows=" + tileRows + " startRow=" + startRow + " pics=" + picList.size();
142 if (DEBUG)
143 logger.info("tileRows=" + tileRows + " rowHeight=" + tileHeight);
144 if (baseX > maxCol)
145 baseX = maxCol;
146 if (baseY > maxRow)
147 baseY = maxRow;
148
149 BufferedImage mbi;
150 workDoneL = true;
151 workDoneR = true;
152 while (workDoneL || workDoneR) {
153 pass++;
154 jobLogEntry.setNote("pass: " + pass);
155 if (!pmf.isEngineOn())
156 return(false);
157 buildStep = "Calc";
158 for (p=0; p<picList.size(); p++) {
159 Pic xp = picList.get(p);
160
161 if (tileHeight*xp.getWidth()/xp.getHeight() < 1) {
162 for (curRow=0; curRow<tileRows; curRow++) {
163 rateL[curRow][p] = Integer.MAX_VALUE;
164 rateR[curRow][p] = Integer.MAX_VALUE;
165 }
166 continue;
167 }
168 curPicName = xp.getName();
169
170
171 Thumbnail xtn = pmf.getMosaicThumbNail(xp, tileHeight);
172 mbi = xtn.getImage();
173
174 if (workDoneL)
175 workDoneL = _calcLeft(mbi);
176 if (workDoneR)
177 workDoneR = _calcRight(mbi);
178 if (!workDoneL && !workDoneR)
179 break;
180 }
181 buildStep = "Draw";
182 if (workDoneL)
183 workDoneL = _drawLeft();
184 if (workDoneR)
185 workDoneR = _drawRight();
186 if (!mosaic.isBatch())
187 dbf.storeMosaic(mosaic);
188 }
189
190 buildStep = "Done";
191 return(false);
192 }
193
194 private boolean _calcLeft(BufferedImage mbi) {
195 boolean workDone = false;
196 int x,y;
197 int mw = mbi.getWidth();
198 int mh = mbi.getHeight();
199 for (curRow=0; curRow<tileRows; curRow++) {
200 curCol = curColsL[curRow];
201 int cr = curRow * tileHeight + startRow;
202 if (curCol > 0) {
203 workDone = true;
204 if (reduceStyle == 0)
205 rateL[curRow][p] = -(long)(used[p]*this.usedWeight);
206 else
207 rateL[curRow][p] = 0;
208 for (x=0; x<mw; x++) {
209 y=0;
210 if (cr<0)
211 y = -startRow;
212 for (; y<mh; y++) {
213 int mpx = mbi.getRGB(x, y);
214 int ppx;
215 if (curCol+x-mw < 0 || y+cr >= maxRow)
216 ppx = mpx;
217 else
218
219 ppx = pixels[x+curCol-mw+((y+cr)*maxCol)];
220
221
222
223 rateL[curRow][p] += Math.abs(((mpx)&0xFF) - ((ppx)&0xFF)) * 1;
224 rateL[curRow][p] += Math.abs(((mpx>>8)&0xFF) - ((ppx>>8)&0xFF)) * 1;
225 rateL[curRow][p] += Math.abs(((mpx>>16)&0xFF) - ((ppx>>16)&0xFF)) * 1;
226 }
227 }
228
229
230 rateL[curRow][p] /= mw;
231
232 rateL[curRow][p] *= (1+(rateWeight * (9-rateMap.get(curPicName))));
233
234 }
235 }
236 return(workDone);
237 }
238
239 private boolean _calcRight(BufferedImage mbi) {
240 boolean workDone = false;
241 int mw = mbi.getWidth();
242 int mh = mbi.getHeight();
243 int x,y;
244 for (curRow=0; curRow<tileRows; curRow++) {
245 curCol = curColsR[curRow];
246 int cr = curRow * tileHeight + startRow;
247 if (curCol < maxCol) {
248 workDone = true;
249 if (reduceStyle == 0)
250 rateR[curRow][p] = -(long)(used[p]*this.usedWeight);
251 else
252 rateR[curRow][p] = 0;
253 for (x=0; x<mw; x++) {
254 y=0;
255 if (cr<0)
256 y = -startRow;
257 for (; y<mh; y++) {
258 int mpx = mbi.getRGB(x, y);
259 int ppx;
260 if (x+curCol >= maxCol || y+cr >= maxRow)
261 ppx = mpx;
262 else
263
264 ppx = pixels[x+curCol+((y+cr)*maxCol)];
265
266
267
268 rateR[curRow][p] += Math.abs(((mpx)&0xFF) - ((ppx)&0xFF)) * 1;
269 rateR[curRow][p] += Math.abs(((mpx>>8)&0xFF) - ((ppx>>8)&0xFF)) * 1;
270 rateR[curRow][p] += Math.abs(((mpx>>16)&0xFF) - ((ppx>>16)&0xFF)) * 1;
271 }
272 }
273
274
275 rateR[curRow][p] /= mw;
276
277 rateR[curRow][p] *= (1+(rateWeight * (9-rateMap.get(curPicName))));
278 }
279 }
280 return(workDone);
281 }
282
283 private boolean _drawLeft() {
284 boolean workDone = false;
285 BufferedImage bi;
286 int x;
287 for (curRow=0; curRow<tileRows; curRow++) {
288 curCol = curColsL[curRow];
289 int cr = curRow * tileHeight + startRow;
290 if (curCol < 0)
291 continue;
292 long best = Long.MAX_VALUE;
293 int besti = 0;
294 int besti2 = 0;
295 for (x=0; x<rateL[curRow].length; x++) {
296 if (rateL[curRow][x] < best) {
297 besti2 = besti;
298 best = rateL[curRow][x];
299 besti = x;
300 }
301 }
302
303 if (DEBUGDRAW) {
304 if (besti == -1)
305 logger.info("row=" + curRow + " besti == -1");
306 else
307 logger.info("besti = " + besti + " (" + picList.get(besti).getName() + ") = " + rateL[curRow][besti]);
308 if (besti2 == -1)
309 logger.info("row=" + curRow + " besti2 == -1");
310 else
311 logger.info("besti2 = " + besti2 + " (" + picList.get(besti2).getName() + ") = " + rateL[curRow][besti2]);
312 }
313 used[besti]++;
314 bi = pmf.getMosaicThumbNail(picList.get(besti), tileHeight).getImage();
315 if (!mosaic.isBatch()) {
316 MosaicTile tile = new MosaicTile(this.mid, picList.get(besti).getPid(), curCol-bi.getWidth(), cr, bi.getWidth(), bi.getHeight());
317 dbf.storeMosaicTile(tile);
318 }
319 gd.drawImage(bi, null, curCol-bi.getWidth(), cr);
320 workDone = true;
321 curColsL[curRow] -= bi.getWidth();
322 if (reduceStyle == 1) {
323 String name = picList.get(besti).getName();
324 double dd = rateMap.get(name) - (rateMap.get(name) * this.usedWeight);
325 rateMap.put(name, dd);
326 }
327 setLastMosaicUpdate();
328 }
329 return(workDone);
330 }
331
332 private boolean _drawRight() {
333 boolean workDone = false;
334 BufferedImage bi;
335 int x;
336 for (curRow=0; curRow<tileRows; curRow++) {
337 curCol = curColsR[curRow];
338 int cr = curRow * tileHeight + startRow;
339 if (curCol >= maxCol)
340 continue;
341 long best = Long.MAX_VALUE;
342 int besti = 0;
343 int besti2 = 0;
344 for (x=0; x<rateR[curRow].length; x++) {
345 if (rateR[curRow][x] < best) {
346 besti2 = besti;
347 best = rateR[curRow][x];
348 besti = x;
349 }
350 }
351
352 if (DEBUGDRAW) {
353 if (besti == -1)
354 logger.info("row=" + curRow + " besti == -1");
355 else
356 logger.info("besti = " + besti + " (" + picList.get(besti).getName() + ") = " + rateR[curRow][besti]);
357 if (besti2 == -1)
358 logger.info("row=" + curRow + " besti2 == -1");
359 else
360 logger.info("besti2 = " + besti2 + " (" + picList.get(besti2).getName() + ") = " + rateR[curRow][besti2]);
361 }
362 used[besti]++;
363 bi = pmf.getMosaicThumbNail(picList.get(besti), tileHeight).getImage();
364 if (!mosaic.isBatch()) {
365 MosaicTile tile = new MosaicTile(this.mid, picList.get(besti).getPid(), curCol, cr, bi.getWidth(), bi.getHeight());
366 dbf.storeMosaicTile(tile);
367 }
368 gd.drawImage(bi, null, curCol, cr);
369 workDone = true;
370 curColsR[curRow] += bi.getWidth();
371 if (reduceStyle == 1) {
372 String name = picList.get(besti).getName();
373 double dd = rateMap.get(name) - (rateMap.get(name) * this.usedWeight);
374 rateMap.put(name, dd);
375 }
376 setLastMosaicUpdate();
377 }
378 return(workDone);
379 }
380 }