View Javadoc
1   /******************************************************************************
2    * PosterEngine.java - Base class for the plugin contact making engines
3    * 
4    * PicMan - The BuckoSoft Picture Manager in Java
5    * Copyright(c) 2012 - Dick Balaska
6    * 
7    */
8   package com.buckosoft.PicMan.business.contact;
9   
10  import java.awt.BasicStroke;
11  import java.awt.Color;
12  import java.awt.Font;
13  import java.awt.Graphics2D;
14  import java.awt.RenderingHints;
15  import java.awt.geom.Rectangle2D;
16  import java.awt.image.BufferedImage;
17  import java.util.Collections;
18  import java.util.Iterator;
19  import java.util.LinkedList;
20  import java.util.List;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  import com.buckosoft.PicMan.domain.MosaicTile;
26  import com.buckosoft.PicMan.domain.Pic;
27  import com.buckosoft.PicMan.domain.Poster;
28  import com.buckosoft.PicMan.domain.PosterParams;
29  import com.buckosoft.PicMan.domain.Thumbnail;
30  
31  /** Extend ContactEngine to build Posters
32   * @author Dick Balaska
33   * @since 2012/08/17
34   * @see <a href="http://cvs.buckosoft.com/Projects/PicMan/PicMan/src/main/java/com/buckosoft/PicMan/business/contact/PosterEngine.java">PosterEngine.java</a>
35   */
36  public class PosterEngine extends ContactEngine {
37  	private final Log log = LogFactory.getLog(getClass());
38  
39  	private	PosterParams pp;
40  	
41  	protected class WorkTile implements Comparable<WorkTile> {
42  		WorkTile(int pid, double x, double y, double w, double h) {
43  			this.pid = pid; this.x = x; this.y = y; this.w = w; this.h = h;
44  		}
45  		int pid;
46  		double	x;
47  		double	y;
48  		double	w;
49  		double	h;
50  
51  		@Override
52  		public int compareTo(WorkTile wt) {
53  			if (wt.x > this.x) return -1;
54  			if (wt.x < this.x) return 1; 
55  			return(0);
56  		}
57  		
58  	}
59  	/* (non-Javadoc)
60  	 * @see com.buckosoft.PicMan.business.contact.ContactEngine#_makeContact()
61  	 */
62  	@Override
63  	protected boolean _makeContact() {
64  		pp = (PosterParams)contactParams;
65  		Poster p = pp.getPoster();
66  		int prWidth  = (int)(p.getPaperWidth()  * p.getDpi());
67  		int prHeight = (int)(p.getPaperHeight() * p.getDpi());
68  		log.info("_makeContact: prWidth = " + prWidth + " prHeight = " + prHeight);
69  //		int	leftMargin = p.getMarginL();
70  		int	topMargin = p.getMarginT();
71  		BufferedImage bi = new BufferedImage(prWidth+p.getOverSprayL()+p.getOverSprayR(), prHeight+p.getOverSprayT()+p.getOverSprayB(), BufferedImage.TYPE_3BYTE_BGR);
72  		Graphics2D 	g = bi.createGraphics();
73  		log.info("_makeContact: actual width = " + bi.getWidth() + " height = " + bi.getHeight());
74  		g.setColor(Color.white);
75  		g.fillRect(0, 0, bi.getWidth(), bi.getHeight());
76  		if (pp.isCalibration()) {
77  			return(makeCalibrationSheet(pp, bi, g));
78  		}
79  		cPath = p.getOutputPath() + pp.getSheetXY().y + "_" + pp.getSheetXY().x;
80  		List<MosaicTile> mtList = pmf.getDB().getMosaicTiles(p.getMasterMid());
81  		List<WorkTile> workList = new LinkedList<WorkTile>();
82  		for (MosaicTile mt : mtList)
83  			workList.add(new WorkTile(mt.getPid(), mt.getX()* p.getMultiplier(), mt.getY()*p.getMultiplier(),
84  									  mt.getWidth()*p.getMultiplier(), mt.getHeight()*p.getMultiplier()));
85  		double tileHeight = workList.get(0).h;			// All tiles are the same height
86  		pmf.setupMosaicThumbCache(0, (int)tileHeight);
87  		int startX = pp.getGeneratedOffsetXY().x;
88  		int endX = pp.getGeneratedOffsetXY().x + (int)((p.getPaperWidth() * p.getDpi()));
89  		int startY = pp.getGeneratedOffsetXY().y;
90  		int endY = pp.getGeneratedOffsetXY().y + (int)((p.getPaperHeight() * p.getDpi()));
91  		log.info("startXY=" + startX + "/" + startY + "  endXY=" + endX + "/" + endY);
92  //		boolean firstRow = true;
93  		int	x;
94  		int	y;
95  		int debugY;
96  		for (y = 0, debugY=0; y<prHeight+tileHeight; debugY++) {
97  			log.debug("************ row " + debugY);
98  			List<WorkTile> wlist = getListForY(workList, y+startY+topMargin);
99  			Iterator<WorkTile> iter = wlist.iterator();
100 			WorkTile wt = null;
101 //			x = leftMargin;
102 			x = 0;
103 			log.debug("Check x = " + startX);
104 			while (iter.hasNext()) {
105 				WorkTile w = iter.next();
106 				log.debug("tile? " + w.pid + " " + w.x + "/" + w.y);
107 				if (w.x <= startX && w.x+w.w >= startX
108 				 || startX < 0) {
109 					wt = w;
110 					x = (int)(w.x-startX);
111 					log.debug("Got one " + w.pid);
112 					break;
113 				}
114 			}
115 			while (wt != null) {
116 				Pic pic = this.pmf.getDB().getPic(wt.pid);
117 				Thumbnail tn = this.pmf.getMosaicThumbNail(pic, (int)tileHeight);
118 				g.drawImage(tn.getImage(), null, (int)wt.x-startX, (int)wt.y-startY);
119 				log.debug("draw " + wt.pid + " (x=" + x + ") " + (wt.x-startX) + "/" + (wt.y-startY) + " tW=" + tn.getImage().getWidth() + " " + pic.getName());
120 				x += tn.getImage().getWidth();
121 				if ((wt.x-startX+tn.getImage().getWidth()) > (p.getPaperWidth() * p.getDpi())+ p.getMarginR())
122 					break;
123 				if (!iter.hasNext())
124 					break;
125 				wt = iter.next();
126 			}
127 			y+=tileHeight;
128 		}
129 		// trim the pic with a border
130 		g.setColor(Color.white);
131 		if (startX < 0) {	// left border
132 			g.fillRect(0, 0, -startX, bi.getHeight());
133 		}
134 		if (startY < 0) {	// top border
135 			g.fillRect(0, 0, bi.getWidth(), -startY);
136 		}
137 		x = (int)(p.getProjectWidth()*p.getDpi());
138 		if (x < endX ) {	// right border
139 			g.fillRect(prWidth-(endX-x), 0, endX-x+p.getMarginR(), bi.getHeight());
140 		}
141 		y = (int)(p.getProjectHeight()*p.getDpi());
142 		if (y < endY) {		// bottom border
143 			g.fillRect(0, prHeight-(endY-y), bi.getWidth(), endY-y);
144 		}
145 		boolean success = writePic(bi, true);
146 		return(success);
147 	}
148 
149 	private	List<WorkTile> getListForY(List<WorkTile> wlist, double y) {
150 		List<WorkTile> l = new LinkedList<WorkTile>();
151 		for (WorkTile wt : wlist) {
152 			if (wt.y <= y && wt.y+wt.h >y)
153 				l.add(wt);
154 		}
155 		Collections.sort(l);
156 		return(l);
157 	}
158 
159 	/* ======================================================================================== */
160 	final static float dash1[] = {20.0f};
161     final static BasicStroke dashed =
162         new BasicStroke(1.0f,
163                         BasicStroke.CAP_BUTT,
164                         BasicStroke.JOIN_MITER,
165                         20.0f, dash1, 0.0f);
166 
167 	private	boolean makeCalibrationSheet(PosterParams pp, BufferedImage bi, Graphics2D g) {
168 		Poster p = pp.getPoster();
169 		cPath = p.getOutputPath() + "calibration";
170 		int cWidth  = bi.getWidth();
171 		int cHeight = bi.getHeight();
172 		int	lMargin = p.getMarginL();
173 		int	tMargin = p.getMarginT();
174 		int	rMargin = p.getMarginR();
175 		int	bMargin = p.getMarginB();
176 		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
177 		g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
178 
179 		g.setColor(Color.red);
180 		drawRect(p, bi, g, 0);
181 		g.setColor(Color.green);
182 		drawRect(p, bi, g, 3);
183 
184 		int	lowHint = 0;
185 		int	highHint = 100;
186 		int	step = 5;
187 		int	numSteps = (highHint-lowHint)/step;
188 		int stepHeight = cHeight/2/numSteps;
189 		int	stepWidth = cWidth/2/numSteps;
190 		log.info("numSteps=" + numSteps + " stepHeight=" + stepHeight + " stepWidth=" + stepWidth);
191 		Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 48);
192 		Rectangle2D frect = font.getStringBounds("00", g.getFontRenderContext());
193 //		LineMetrics lm = font.getLineMetrics("00", g.getFontRenderContext());
194 //		int baseline = (int)Math.round(lm.getHeight()/2);
195 		int baseline = (int)Math.round(frect.getHeight()/2);
196 		int fWidth = (int)Math.round(frect.getHeight()+3);
197 		g.setFont(font);
198 		for (int curStep = 0; curStep<numSteps; curStep++) {
199 			int curX = curStep*step;
200 			int startY = stepHeight*curStep;
201 			int endY =  startY+stepHeight;
202 			g.setColor(Color.black);
203 			g.drawLine(curX, startY, curX, endY);
204 			g.drawString("" + curX, curX+3, endY-baseline);
205 			g.drawLine(curX, cHeight-startY, curX, cHeight-endY);
206 			g.drawString("" + curX, curX+3, cHeight-startY-baseline);
207 
208 			g.drawLine(cWidth-curX, startY, cWidth-curX, endY);
209 			g.drawString("" + curX, cWidth-curX-fWidth, endY-baseline);
210 			g.drawLine(cWidth-curX, cHeight-startY, cWidth-curX, cHeight-endY);
211 			g.drawString("" + curX, cWidth-curX-fWidth, cHeight-startY-baseline);
212 			
213 			int y = curX;
214 			int x = curStep*stepWidth;
215 			g.drawLine(x, y, x+stepWidth, y);
216 			g.drawString("" + y, (int)(x+(stepWidth/2)-frect.getCenterX()), (int)(y+frect.getHeight() + 3));
217 			g.drawLine(cWidth-x, y, cWidth-x-stepWidth, y);
218 			g.drawString("" + y, (int)(cWidth-x-(stepWidth/2)-frect.getCenterX()), (int)(y+frect.getHeight() + 3));
219 
220 			g.drawLine(x, cHeight-y, x+stepWidth, cHeight-y);
221 			g.drawString("" + y, (int)(x+(stepWidth/2)-frect.getCenterX()), (int)(cHeight-y-3));
222 			g.drawLine(cWidth-x, cHeight-y, cWidth-x-stepWidth, cHeight-y);
223 			g.drawString("" + y, (int)(cWidth-x-(stepWidth/2)-frect.getCenterX()), (int)(cHeight-y-3));
224 		}
225 
226 		g.setStroke(dashed);
227 		g.setColor(Color.black);
228 		g.drawLine(lMargin, tMargin, 			cWidth-rMargin, cHeight-bMargin);
229 		g.drawLine(lMargin, cHeight-bMargin,	cWidth-rMargin, tMargin);
230 		
231 		boolean success = writePic(bi, true);
232 		return(success);
233 	}
234 
235 	private void drawRect(Poster p, BufferedImage bi, Graphics2D g, int offset) {
236 		int cWidth  = bi.getWidth();
237 		int cHeight = bi.getHeight();
238 		int	lMargin = p.getMarginL();
239 		int	tMargin = p.getMarginT();
240 		int	rMargin = p.getMarginR();
241 		int	bMargin = p.getMarginB();
242 		g.drawRect(lMargin + offset, tMargin+offset, cWidth-lMargin-rMargin-(offset*2)-1, cHeight-tMargin-bMargin-(offset*2)-1);
243 	}
244 }