001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030/**
031 * 
032 */
033package org.openimaj.web.flickr;
034
035import java.io.File;
036import java.io.IOException;
037import java.net.URI;
038import java.net.URL;
039import java.util.regex.Matcher;
040import java.util.regex.Pattern;
041
042import org.openimaj.image.ImageUtilities;
043import org.openimaj.image.MBFImage;
044
045/**
046 *      A wrapper for Flickr images, and their URLs and what not. This is different
047 *      to using the Photo class from com.aetrion as it specifically does not
048 *      require access to Flickr and will not attempt to get any information from
049 *      Flickr itself (except the image through the {@link #getImage()} method).
050 *      It's just a placeholder for any information known about a Flickr image. 
051 *
052 *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
053 *  @created 12 Aug 2013
054 *      @version $Author$, $Revision$, $Date$
055 */
056public class FlickrImage
057{
058        /** The allowable size suffixes */
059        public static final String sizeSuffixes = "sqtnm-zcbo"; 
060        
061        /** The photo id */
062        private long id;
063        
064        /** The URI of the image (generated) */
065        private URI url;
066        
067        /** The farm ID */
068        private int farm;
069        
070        /** The server ID */
071        private int server;
072        
073        /** The image secret */
074        private String secret;
075        
076        /** The size identifier */
077        private char size;
078        
079        /** Whether it's the original image or not */
080        private boolean isOriginal;
081        
082        /** The original image file extension */
083        private String extension;
084        
085        /** If the file is cached locally, then this is its location */
086        private File localFile;
087
088        /**
089         *      @param id
090         *      @param farm 
091         *      @param server 
092         *      @param secret 
093         *      @param size 
094         *      @param extension 
095         */
096        public FlickrImage( long id, int farm, int server, String secret, 
097                        char size, String extension )
098        {
099                this.id = id;
100                this.farm = farm;
101                this.server = server;
102                this.secret = secret;
103                this.size = size;
104                this.extension = extension;
105                this.url = createURI();
106                
107                if( !sizeSuffixes.contains( ""+size ) )
108                        throw new IllegalArgumentException( "Size suffixes must be one "+
109                                        "of "+sizeSuffixes );
110        }
111        
112        /**
113         *      Parses a Flickr URL and updates this object. 
114         *      @param url The URL
115         *      @return The new FlickrImage instance
116         */
117        public static FlickrImage create( URL url )
118        {
119                int farm = 0;
120                long id = 0;
121                int server = 0;
122                String secret = null;
123                char size = 'o';
124                String extension = "jpg";
125                
126                // Patterns from http://www.flickr.com/services/api/misc.urls.html
127                Pattern p1 = Pattern.compile( "http://farm([0-9]+).static.flickr.com/([0-9]+)/"
128                                + "([0-9]+)_([0-9a-f]+).jpg" );
129                Pattern p2 = Pattern.compile( "http://farm([0-9]+).static.flickr.com/([0-9]+)/"
130                                + "([0-9]+)_([0-9a-f]+)_([mstzb]).jpg" );
131                Pattern p3 = Pattern.compile( "http://farm([0-9]+).static.flickr.com/([0-9]+)/"
132                                + "([0-9]+)_([0-9a-f]+)_o.(jpg|png|gif)" );
133                Pattern p4 = Pattern.compile( "http://flic.kr/p/([0-9A-Za-z]+)" );
134                
135                FlickrImage f = null;
136                Matcher m = null;
137                if( (m = p1.matcher( url.toString() )).find() )
138                {
139                        farm = Integer.parseInt( m.group(1) );
140                        server = Integer.parseInt( m.group(2) );
141                        id = Long.parseLong( m.group(3) );
142                        secret = m.group(4);
143                        f = new FlickrImage( id, farm, server, secret, size, extension );
144                }
145                else
146                if( (m = p2.matcher( url.toString() )).find() )
147                {
148                        farm = Integer.parseInt( m.group(1) );
149                        server = Integer.parseInt( m.group(2) );
150                        id = Long.parseLong( m.group(3) );
151                        secret = m.group(4);
152                        size = m.group(5).charAt(0);
153                        f = new FlickrImage( id, farm, server, secret, size, extension );
154                }
155                else
156                if( (m = p3.matcher( url.toString() )).find() )
157                {
158                        farm = Integer.parseInt( m.group(1) );
159                        server = Integer.parseInt( m.group(2) );
160                        id = Long.parseLong( m.group(3) );
161                        secret = m.group(4);
162                        size = 'o';
163                        extension = m.group(5);
164                        f = new FlickrImage( id, farm, server, secret, size, extension );
165                        f.setOriginal( true );
166                }
167                else
168                if( p4.matcher( url.toString() ).find() )
169                {
170                        id = FlickrBaseEncoder.decode( url.toString() );
171                        f = new FlickrImage( id, 0, 0, null, 'z', null );
172                }
173                else
174                {
175                        System.err.println( "WARNING: No pattern matched the Flickr "+
176                                        "URL "+url.toString() );
177                }
178
179                return f;
180        }
181        
182        /**
183         * 
184         *      @return
185         */
186        private URI createURI()
187        {
188                URI url = null;
189                if( size == 'o' )
190                {
191                        // http://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}_[mstzb].jpg
192                        url = URI.create( "http://farm"+farm+".staticflickr.com/"+server+"/"
193                                        +id+"_"+secret+"_"+size+"."+extension );
194                }
195                else
196                {
197                        // http://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}_o.[jpg|gif|png]
198                        url = URI.create( "http://farm"+farm+".staticflickr.com/"+server
199                                        +"/"+id+"_"+secret+"_"+size+".jpg" );
200                }
201                
202                return url;
203        }
204        
205        /**
206         *      @return the id
207         */
208        public long getId()
209        {
210                return id;
211        }
212
213        /**
214         *      @param id the id to set
215         */
216        public void setId( long id )
217        {
218                this.id = id;
219        }
220
221        /**
222         *      @return the url
223         */
224        public URI getUrl()
225        {
226                return url;
227        }
228
229        /**
230         *      @param url the url to set
231         */
232        public void setUrl( URI url )
233        {
234                this.url = url;
235        }
236
237        /**
238         *      @return the farm
239         */
240        public int getFarm()
241        {
242                return farm;
243        }
244
245        /**
246         *      @param farm the farm to set
247         */
248        public void setFarm( int farm )
249        {
250                this.farm = farm;
251        }
252
253        /**
254         *      @return the server
255         */
256        public int getServer()
257        {
258                return server;
259        }
260
261        /**
262         *      @param server the server to set
263         */
264        public void setServer( int server )
265        {
266                this.server = server;
267        }
268
269        /**
270         *      @return the secret
271         */
272        public String getSecret()
273        {
274                return secret;
275        }
276
277        /**
278         *      @param secret the secret to set
279         */
280        public void setSecret( String secret )
281        {
282                this.secret = secret;
283        }
284
285        /**
286         *      @return the size
287         */
288        public char getSize()
289        {
290                return size;
291        }
292
293        /**
294         *      @param size the size to set
295         */
296        public void setSize( char size )
297        {
298                this.size = size;
299        }
300
301        /**
302         *      @return the isOriginal
303         */
304        public boolean isOriginal()
305        {
306                return isOriginal;
307        }
308
309        /**
310         *      @param isOriginal the isOriginal to set
311         */
312        public void setOriginal( boolean isOriginal )
313        {
314                this.isOriginal = isOriginal;
315        }
316
317        /**
318         *      @return the localFile
319         */
320        public File getLocalFile()
321        {
322                return localFile;
323        }
324
325        /**
326         *      @param localFile the localFile to set
327         */
328        public void setLocalFile( File localFile )
329        {
330                this.localFile = localFile;
331        }
332        
333        /**     
334         *      Reads the actual flickr image. If it's cached then it will read
335         *      the cache, otherwise it will contact Flickr.
336         *      @return The image
337         *      @throws IOException
338         */
339        public MBFImage getImage() throws IOException
340        {
341                if( localFile != null )
342                                return ImageUtilities.readMBF( localFile );
343                else    return ImageUtilities.readMBF( url.toURL() );
344        }
345}