Coverage Report - com.buckosoft.PicMan.business.mosaic.engine.HSVRibbon
 
Classes in this File Line Coverage Branch Coverage Complexity
HSVRibbon
0%
0/126
0%
0/48
6
 
 1  
 /******************************************************************************
 2  
  * HSVRibbon.java - Make a Mosaic with the HSV color model
 3  
  * 
 4  
  * PicMan - The BuckoSoft Picture Manager in Java
 5  
  * Copyright(c) 2008 - Dick Balaska
 6  
  * 
 7  
  */
 8  
 package com.buckosoft.PicMan.business.mosaic.engine;
 9  
 
 10  
 import java.awt.Color;
 11  
 import java.awt.Graphics2D;
 12  
 import java.awt.image.BufferedImage;
 13  
 import java.util.Iterator;
 14  
 import java.util.List;
 15  
 
 16  
 import org.apache.commons.logging.Log;
 17  
 import org.apache.commons.logging.LogFactory;
 18  
 
 19  
 import com.buckosoft.PicMan.business.mosaic.MosaicEngine;
 20  
 import com.buckosoft.PicMan.domain.MosaicTile;
 21  
 import com.buckosoft.PicMan.domain.Pic;
 22  
 
 23  
 /** Rework FirstMosaic using an HSV color model instead of an RGB color model. <br>
 24  
  * This engine walks through each row of a Pic and places the best tile there. <br>
 25  
  * "Best" is determined by subtracting the tile from the Pic and summing the different in each pixel.
 26  
  * This is performed from each tile in the set, and the one with the least difference is chosen.  
 27  
  * @author Dick Balaska
 28  
  * @since 2008/05/27
 29  
  * @see <a href="http://cvs.buckosoft.com/Projects/java/PicMan/PicMan/src/main/java/com/buckosoft/PicMan/business/mosaic/engine/HSVRibbon.java">HSVRibbon.java</a>
 30  
  */
 31  0
 public class HSVRibbon extends MosaicEngine {
 32  
         private static final boolean DEBUG = true;
 33  0
         private final Log logger = LogFactory.getLog(getClass());
 34  
         
 35  0
         private        int                mosaicId = 2;
 36  0
         private        int                curRow = 0;
 37  
         private        int[]        curCols;
 38  
         private        int                curCol;
 39  
         private        int                maxRow;
 40  
         private        int                maxCol;
 41  
         private        int                p;
 42  
         private        List<Pic>        picList;
 43  0
         private        String        info = "N/A";
 44  
         private        int[]        used;
 45  
         private        int                tileRows;
 46  0
         private        String        buildStep = "Idle";
 47  0
         private        int                pass = -1;
 48  
         
 49  
         /** Return our current build status
 50  
          * @return The status
 51  
          */
 52  
         public        String        getStatus() {
 53  0
                 StringBuilder sb = new StringBuilder();
 54  0
                 sb.append(buildStep);
 55  0
                 sb.append(": pass=");
 56  0
                 sb.append(pass);
 57  0
                 if (!buildStep.equals("Calc")) {
 58  0
                         sb.append(" curRow = ");
 59  0
                         sb.append(curRow);
 60  0
                         sb.append(" curCol = ");
 61  0
                         sb.append(curCol);
 62  
                 }
 63  0
                 sb.append(" p=");
 64  0
                 sb.append(p);
 65  0
                 return(sb.toString());
 66  
         }
 67  
 
 68  
         /** Return a semi-static info string
 69  
          * @return "tileRows= y maxCol= x pics=n
 70  
          */
 71  
         public String getInfo() {
 72  0
                 return(info);
 73  
         }
 74  
 
 75  
         protected boolean _build() {
 76  0
                 Graphics2D        gd = bi.createGraphics();
 77  
                 
 78  
                 // 75, pull from this size set even though the size calc should be able to deal with, say, a 50 and figure it out.
 79  0
                 picList = pmf.getDB().getPics(this.mosaicSet, 75);
 80  
                 if (DEBUG)
 81  0
                         logger.info("Working from " + picList.size() + " pics");
 82  0
                 maxRow = this.masterPic.getHeight();
 83  0
                 maxCol = this.masterPic.getWidth();
 84  0
                 tileRows = maxRow / tileHeight;
 85  0
                 if (tileRows * tileHeight < maxRow)
 86  0
                         tileRows++;
 87  0
                 curCols = new int[tileRows];
 88  
                 
 89  0
                 float[][]        rate = new float[tileRows][picList.size()];                // rate each pic for this location
 90  0
                                         used = new int[picList.size()];                // number of times each pic is used
 91  0
                 info = "tileRows=" + tileRows + " maxCol=" + maxCol + " pics=" + picList.size();
 92  
                 if (DEBUG)
 93  0
                         logger.info("tileRows=" + tileRows + " rowHeight=" + tileHeight);
 94  0
                 restoreBuild(gd);
 95  0
                 boolean workDone = true;
 96  0
                 float[] mpxHsb = new float[3];
 97  0
                 float[] ppxHsb = new float[3];
 98  0
                 while (workDone) {
 99  0
                         pass++;
 100  0
                         workDone = false;
 101  
                         BufferedImage mbi;
 102  
                         int        x,y;
 103  0
                         buildStep = "Calc";
 104  0
                         for (p=0; p<picList.size(); p++) {
 105  0
                                 mbi = pmf.getMosaicThumbNail(picList.get(p), tileHeight).getImage();
 106  0
                                 for (curRow=0; curRow<tileRows; curRow++) {
 107  0
                                         curCol = curCols[curRow];
 108  0
                                         int        cr = curRow * tileHeight;
 109  
 //                                        if (DEBUG) {
 110  
 //                                                if (curRow == 28 && pass == 4)
 111  
 //                                                        logger.info("pass 4 row 28");
 112  
 //                                        }
 113  0
                                         if (curCol < maxCol) {
 114  0
                                                 workDone = true;
 115  
                                                 //BufferedImage mbi = pmf.getThumbNail(null, tileHeight).getImage();
 116  0
                                                 rate[curRow][p] = used[p];
 117  0
                                                 rate[curRow][p] = 0;
 118  0
                                                 for (x=0; x<mbi.getWidth(); x++) {
 119  0
                                                         for (y=0; y<mbi.getHeight(); y++) {
 120  0
                                                                 int mpx = mbi.getRGB(x, y);
 121  
                                                                 int        ppx;
 122  0
                                                                 if (x+curCol >= bi.getWidth() || y+cr >= bi.getHeight())
 123  0
                                                                         ppx = mpx;
 124  
                                                                 else
 125  0
                                                                         ppx = bi.getRGB(x+curCol, y+cr);
 126  
                                                                 
 127  0
                                                                 Color.RGBtoHSB((mpx>>16) & 0xFF, (mpx>>8) & 0xFF, mpx&0xFF, mpxHsb);
 128  0
                                                                 Color.RGBtoHSB((ppx>>16) & 0xFF, (ppx>>8) & 0xFF, ppx&0xFF, ppxHsb);
 129  0
                                                                 if (ppxHsb[0] > mpxHsb[0]) ppxHsb[0] += 1.0;
 130  0
                                                                 rate[curRow][p] += Math.abs(mpxHsb[0] - ppxHsb[0]);
 131  0
                                                                 rate[curRow][p] += Math.abs(mpxHsb[0] - ppxHsb[0]);
 132  0
                                                                 rate[curRow][p] += Math.abs(mpxHsb[0] - ppxHsb[0]);
 133  
 
 134  
                                                                 //rate[curRow][p] += Math.abs(((mpx)&0xFF)     - ((ppx)&0xFF))     * 1;
 135  
                                                                 //rate[curRow][p] += Math.abs(((mpx>>8)&0xFF)  - ((ppx>>8)&0xFF))  * 1;
 136  
                                                                 //rate[curRow][p] += Math.abs(((mpx>>16)&0xFF) - ((ppx>>16)&0xFF)) * 1;
 137  
                                                         }
 138  
                                                 }
 139  
                                                 // Portrait always wins over landscape because there is less pixels to go wrong.
 140  
                                                 // Give equal weight per pixel column
 141  0
                                                 rate[curRow][p] /= mbi.getWidth();
 142  
                                                 //logger.info("rate[" + p + "]=" + rate[p] + " ("+ picList.get(p).getName() + ")");
 143  
                                         }
 144  
                                 }
 145  
                         }
 146  0
                         buildStep = "Draw";
 147  0
                         for (curRow=0; curRow<tileRows; curRow++) {
 148  0
                                 curCol = curCols[curRow];
 149  0
                                 int cr = curRow * tileHeight;
 150  0
                                 if (curCol >= maxCol)
 151  0
                                         continue;
 152  0
                                 float        best = Float.MAX_VALUE;
 153  0
                                 int                besti = -1;
 154  0
                                 int                besti2 = -1;
 155  0
                                 for (x=0; x<rate.length; x++) {
 156  0
                                         if (rate[curRow][x] < best) {
 157  0
                                                 besti2 = besti;
 158  0
                                                 best = rate[curRow][x];
 159  0
                                                 besti = x;
 160  
                                         }
 161  
                                 }
 162  0
                                 p = besti;
 163  
                                 if (DEBUG) {
 164  0
                                         if (besti == -1)
 165  0
                                                 logger.info("row=" + curRow + " besti == -1");
 166  
                                         else
 167  0
                                                 logger.info("besti = " + besti + " (" + picList.get(besti).getName() + ") = " + rate[curRow][besti]);
 168  0
                                         if (besti2 == -1)
 169  0
                                                 logger.info("row=" + curRow + " besti2 == -1");
 170  
                                         else
 171  0
                                                 logger.info("besti2 = " + besti2 + " (" + picList.get(besti2).getName() + ") = " + rate[curRow][besti2]);
 172  
                                 }
 173  0
                                 used[besti]++;
 174  0
                                 mbi = pmf.getThumbNail(picList.get(besti), tileHeight).getImage();
 175  0
                                 MosaicTile        tile = new MosaicTile(mosaicId, picList.get(besti).getPid(), curCol, cr, mbi.getWidth(), mbi.getHeight());
 176  0
                                 pmf.getDB().storeMosaicTile(tile);
 177  0
                                 gd.drawImage(mbi, null, curCol, cr);
 178  0
                                 curCols[curRow] += mbi.getWidth();
 179  0
                                 setLastMosaicUpdate();
 180  
                         }
 181  
                 }
 182  0
                 buildStep = "Done";
 183  0
                 return(false);
 184  
         }
 185  
 
 186  
         private        void restoreBuild(Graphics2D gd) {
 187  0
                 List<MosaicTile> lmt = pmf.getDB().getMosaicTiles(mosaicId);
 188  
                 if (DEBUG)
 189  0
                         logger.info("Restoring " + lmt.size() + " tiles");
 190  0
                 boolean workDone = true;
 191  0
                 buildStep = "Restore";
 192  0
                 while (workDone) {
 193  0
                         workDone = false;
 194  0
                         pass++;
 195  0
                         updateRestoreStatus();
 196  0
                         for (curRow=0; curRow<tileRows; curRow++) {
 197  0
                                 curCol = curCols[curRow];
 198  0
                                 int        cr = curRow * tileHeight;
 199  0
                                 Iterator<MosaicTile> iter = lmt.iterator();
 200  0
                                 while (iter.hasNext()) {
 201  0
                                         MosaicTile mt = iter.next();
 202  0
                                         if (mt.getX() == curCol && mt.getY() == cr) {
 203  0
                                                 int besti = getPicListIndex(mt.getPid());
 204  
                                                 if (DEBUG)
 205  0
                                                         logger.info("restore: besti = " + besti + " (" + picList.get(besti).getName() + ")");
 206  0
                                                 used[besti]++;
 207  0
                                                 BufferedImage mbi = pmf.getThumbNail(picList.get(besti), tileHeight).getImage();
 208  0
                                                 gd.drawImage(mbi, null, curCol, cr);
 209  0
                                                 curCols[curRow] += mbi.getWidth();
 210  0
                                                 setLastMosaicUpdate();
 211  0
                                                 workDone = true;
 212  0
                                                 break;
 213  
                                         }
 214  0
                                 }
 215  
                         }
 216  
                 }
 217  0
         }
 218  
         
 219  
         private        void updateRestoreStatus() {
 220  0
                 buildStep = "Restore";
 221  0
         }
 222  
 
 223  
         private        int        getPicListIndex(int pid) {
 224  0
                 for (int i=0; i<picList.size(); i++) {
 225  0
                         Pic p = picList.get(i);
 226  0
                         if (p.getPid() == pid)
 227  0
                                 return(i);
 228  
                 }
 229  0
                 return(-1);
 230  
         }
 231  
 }