View Javadoc
1   /******************************************************************************
2    * PosterController.java - The Spring controller to fetch posters
3    * 
4    * BuckoVidLib - The BuckoSoft Video Library
5    * Copyright(c) 2014 - Dick Balaska
6    * 
7    */
8   package com.buckosoft.BuckoVidLib.web;
9   
10  import java.awt.Graphics2D;
11  import java.awt.Image;
12  import java.awt.image.BufferedImage;
13  import java.io.IOException;
14  import java.io.OutputStream;
15  import java.net.URL;
16  import java.util.Iterator;
17  
18  import javax.imageio.ImageIO;
19  import javax.imageio.ImageWriter;
20  import javax.imageio.stream.ImageOutputStream;
21  import javax.servlet.http.HttpServletRequest;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.springframework.beans.factory.annotation.Autowired;
26  import org.springframework.stereotype.Controller;
27  import org.springframework.web.bind.annotation.PathVariable;
28  import org.springframework.web.bind.annotation.RequestMapping;
29  
30  import com.buckosoft.BuckoVidLib.business.BuckoVidLib;
31  import com.buckosoft.BuckoVidLib.domain.TVSeason;
32  import com.buckosoft.BuckoVidLib.domain.VideoBase;
33  import com.buckosoft.BuckoVidLib.util.DomainConverter;
34  
35  /** The Spring controller to fetch posters
36   * @author dick
37   * @since 2014-10-07
38   */
39  @Controller(value="poster")
40  @RequestMapping("/poster")
41  public class PosterController {
42  	private final Log log = LogFactory.getLog(getClass());
43  
44  	@Autowired
45  	private BuckoVidLib		bvl;
46  
47  	private	int	defaultWidth = 150;
48  	private	int	defaultHeight = 225;
49  	
50  	@RequestMapping("/{key}")
51  	public void handleRequest(@PathVariable("key") String key,
52  			HttpServletRequest request,
53  			OutputStream outputStream) throws Exception {
54  		handleRequest(key, defaultWidth, defaultHeight, request, outputStream);
55  	}
56  	
57  	@RequestMapping("/{key}/{width}/{height}")
58  	public void handleRequest(@PathVariable("key") String key, 
59  			@PathVariable("width") Integer w, @PathVariable("height") Integer h,
60  			HttpServletRequest request,
61  			OutputStream outputStream) {
62  
63  		VideoBase v;
64  		TVSeason tvs;
65  		String printedTitle = null;
66  		String vurl;
67  		String s;
68  		boolean b = false;
69  		if (request == null)
70  			b = true;
71  		else
72  			b = bvl.isAllowRestricted(request);
73  		v = bvl.getVideoBaseFromKey(DomainConverter.keyToInt(key), b);
74  		if (v == null) {
75  			tvs = bvl.getTVSeasonFromHashKey(DomainConverter.keyToInt(key));
76  			if (tvs == null) {
77  				s = "Video not found for key: " + key;
78  				log.warn(s);
79  				if (request == null)
80  					throw new RuntimeException(s);
81  				return;
82  			} else {
83  				printedTitle = tvs.getTitle();
84  				vurl = bvl.getPlexUrl() + getPosterUrl(tvs.getPlexKey());
85  			}
86  		} else {
87  			printedTitle = v.getTitle() + " (" + v.getYear() + ")";
88  			vurl = bvl.getPlexUrl() + getPosterUrl(v.getPlexKey());
89  		}
90  		BufferedImage img;
91  		try {
92  			URL url = new URL(vurl);
93  			img = ImageIO.read(url);
94  		} catch (IOException e1) {
95  			s = "Failed to read image for '" + printedTitle + "'";
96  			log.warn(s);
97  			log.warn("url was '" + vurl + "'");
98  			if (request == null)
99  				throw new RuntimeException(s, e1);
100 			return;
101 		}
102 		log.info("Fetch poster for: " + printedTitle);
103 		log.debug("original w/h: " + img.getWidth() + "/" + img.getHeight());
104 
105 		if (w > 1 && h > 1) {
106 			// scale the image
107 			int	targetw;
108 			int	targeth;
109 			double wp = (double)img.getWidth() / (double)w;
110 			double hp = (double)img.getHeight() / (double)h;
111 			log.debug("wp/hp: " + wp + " / " + hp);
112 			if (hp < wp) {
113 				targetw = (int)((double)img.getWidth() / hp);
114 				if (targetw < w)
115 					targetw = w;
116 				targeth = h;
117 			} else {
118 				targeth = (int)((double)img.getHeight() / wp);
119 				if (targeth < h)
120 					targeth = h;
121 				targetw = w;
122 			}
123 			log.debug("target w/h: " + targetw + "/" + targeth);
124 			BufferedImage scaled = new BufferedImage(targetw, targeth, BufferedImage.TYPE_INT_BGR);
125 			Graphics2D g;
126 			g = scaled.createGraphics();
127 			g.drawImage(img.getScaledInstance(targetw, targeth, Image.SCALE_SMOOTH), null, null);
128 			// replace outgoing image with scaled version
129 			img = scaled;
130 			g.dispose();
131 			// pick an exact sized slice out of the image
132 			int overw = img.getWidth() - w;
133 			int	overh = img.getHeight() - h;
134 			int shiftw = overw/2;
135 			int shifth = overh/2;
136 			log.debug("final: over: " + overw + "/" + overh + " shift: " + shiftw + "/" + shifth);
137 			img = img.getSubimage(shiftw, shifth, w-0, h-0);
138 		}
139 	
140 		// write the image to the stream
141 		
142 		ImageOutputStream ios;
143 		try {
144 			ios = ImageIO.createImageOutputStream(outputStream);
145 		} catch (IOException e) {
146 			s = "Failed to create image for writing from " + vurl + " : " + e.getMessage();
147 			log.warn(s);
148 			if (request == null)
149 				throw new RuntimeException(s);
150 			return;
151 		}
152 		Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
153 		ImageWriter writer = (ImageWriter)writers.next();
154 		writer.setOutput(ios);
155 		try {
156 			writer.write(img);
157 		} catch (IOException e) {
158 			s = "Failed to write image from " + vurl + " : " + e.getMessage();
159 			log.warn(s);
160 			log.warn("Try alternate...");
161 			BufferedImage bi = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_BGR);
162 			for (int y=0; y<img.getHeight(); y++) {
163 				for (int x=0; x<img.getWidth(); x++) {
164 					bi.setRGB(x, y, img.getRGB(x, y));
165 				}
166 			}
167 			try {
168 				writer.write(bi);
169 			} catch (IOException e1) {
170 				log.warn("That failed too", e1);
171 				writers = ImageIO.getImageWritersByFormatName("png");
172 				writer = (ImageWriter)writers.next();
173 				writer.setOutput(ios);
174 				try {
175 					log.warn("Try png");
176 					writer.write(img);
177 					ios.close();
178 					ios = null;
179 					// png was successful
180 					log.warn("png writing successful");
181 					return;
182 				} catch (IOException e2) {
183 					log.warn("Writing as png failed too", e2);
184 					if (request == null)
185 						throw new RuntimeException(s);
186 					return;
187 				}
188 			}
189 			log.warn("Alternate jpg passed");
190 			return;			
191 		} finally {
192 			try {
193 				if (ios != null)
194 					ios.close();
195 			} catch (IOException e) {
196 				log.warn("finally tipped", e);
197 			}
198 		}
199 	}
200 	
201 	private	String getPosterUrl(int plexKey) {
202 		return(String.format("library/metadata/%d/thumb", plexKey));
203 	}
204 
205 
206 }