001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.img;
020
021import java.awt.image.BufferedImage;
022import java.awt.image.ColorModel;
023import java.awt.image.IndexColorModel;
024import java.io.IOException;
025
026import javax.imageio.stream.ImageInputStream;
027
028import lucee.commons.io.IOUtil;
029import lucee.commons.io.res.Resource;
030import lucee.commons.io.res.util.ResourceUtil;
031import lucee.commons.lang.ExceptionUtil;
032import lucee.commons.lang.StringUtil;
033import lucee.runtime.img.coder.Coder;
034
035import org.apache.commons.codec.binary.Base64;
036
037public class ImageUtil {
038        
039        private static Coder coder;
040        
041        static {
042                coder = Coder.getInstance();
043        }
044        
045
046
047        public static String[] getWriterFormatNames() {
048                return coder.getWriterFormatNames();
049        }
050        public static String[] getReaderFormatNames() {
051                return coder.getReaderFormatNames();
052        }
053        
054
055        /**
056         * translate a file resource to a buffered image
057         * @param res
058         * @return
059         * @throws IOException
060         */
061        public static BufferedImage toBufferedImage(Resource res,String format) throws IOException {
062                return coder.toBufferedImage(res, format);
063        }
064
065        /**
066         * translate a binary array to a buffered image
067         * @param binary
068         * @return
069         * @throws IOException
070         */
071        public static BufferedImage toBufferedImage(byte[] bytes,String format) throws IOException {
072                return coder.toBufferedImage(bytes, format);
073        }
074
075        
076        
077        
078
079        public static byte[] readBase64(String b64str, StringBuilder mimetype) throws IOException {
080                if(StringUtil.isEmpty(b64str))
081                        throw new IOException("base64 string is empty");
082                
083                // data:image/png;base64,
084                int index = b64str.indexOf("base64,");
085                if(index!=-1){
086                        int semiIndex=b64str.indexOf(";");
087                        if(mimetype!=null && semiIndex<index && StringUtil.startsWithIgnoreCase(b64str, "data:")){
088                                mimetype.append(b64str.substring(5,semiIndex).trim());
089                        }
090                        
091                        b64str=b64str.substring(index + 7);
092                }
093                
094                return Base64.decodeBase64(b64str.getBytes());
095        }
096        
097        public static String getFormat(Resource res) throws IOException {
098                String ext=getFormatFromExtension(res,null);
099                if(ext!=null) return ext;
100                String mt=ResourceUtil.getMimeType(res, null);
101                if(mt==null) return null;//throw new IOException("can't extract mimetype from ["+res+"]");
102                return getFormatFromMimeType(mt);
103        }
104
105        public static String getFormat(byte[] binary) throws IOException {
106                return getFormatFromMimeType(IOUtil.getMimeType(binary, ""));
107        }
108
109        public static String getFormat(byte[] binary,String defaultValue) {
110                return getFormatFromMimeType(IOUtil.getMimeType(binary, ""),defaultValue);
111        }
112
113        public static String getFormatFromExtension(Resource res, String defaultValue) {
114                String ext=ResourceUtil.getExtension(res,null);
115                if("gif".equalsIgnoreCase(ext))return "gif";
116                if("jpg".equalsIgnoreCase(ext))return "jpg";
117                if("jpe".equalsIgnoreCase(ext))return "jpg";
118                if("jpeg".equalsIgnoreCase(ext))return "jpg";
119                if("png".equalsIgnoreCase(ext))return "png";
120                if("tiff".equalsIgnoreCase(ext))return "tiff";
121                if("tif".equalsIgnoreCase(ext))return "tiff";
122                if("bmp".equalsIgnoreCase(ext))return "bmp";
123                if("bmp".equalsIgnoreCase(ext))return "bmp";
124                if("wbmp".equalsIgnoreCase(ext))return "wbmp";
125                if("ico".equalsIgnoreCase(ext))return "bmp";
126                if("wbmp".equalsIgnoreCase(ext))return "wbmp";
127                if("psd".equalsIgnoreCase(ext))return "psd";
128                if("fpx".equalsIgnoreCase(ext))return "fpx";
129                
130                if("pnm".equalsIgnoreCase(ext))return "pnm";
131                if("pgm".equalsIgnoreCase(ext))return "pgm";
132                if("pbm".equalsIgnoreCase(ext))return "pbm";
133                if("ppm".equalsIgnoreCase(ext))return "ppm";
134                return defaultValue;    
135        }
136        
137        
138        
139        
140        public static String getFormatFromMimeType(String mt) throws IOException {
141                String format = getFormatFromMimeType(mt, null);
142                if(format!=null) return format;
143                
144                if(StringUtil.isEmpty(mt))throw new IOException("cannot find Format of given image");//31
145                throw new IOException("can't find Format ("+mt+") of given image");
146        }
147        
148        public static String getFormatFromMimeType(String mt, String defaultValue) {
149                if("image/gif".equals(mt)) return "gif";
150                if("image/gi_".equals(mt)) return "gif";
151                
152                if("image/jpeg".equals(mt)) return "jpg";
153                if("image/jpg".equals(mt)) return "jpg";
154                if("image/jpe".equals(mt)) return "jpg";
155                if("image/pjpeg".equals(mt)) return "jpg";
156                if("image/vnd.swiftview-jpeg".equals(mt)) return "jpg";
157                if("image/pipeg".equals(mt)) return "jpg";
158                if("application/x-jpg".equals(mt)) return "jpg";
159                if("application/jpg".equals(mt)) return "jpg";
160                if("image/jp_".equals(mt)) return "jpg";
161                
162                if("image/png".equals(mt)) return "png";
163                if("image/x-png".equals(mt))return "png";
164                if("application/x-png".equals(mt)) return "png";
165                if("application/png".equals(mt)) return "png";
166                
167                if("image/tiff".equals(mt)) return "tiff";
168                if("image/tif".equals(mt)) return "tiff";
169                if("image/x-tif".equals(mt)) return "tiff";
170                if("image/x-tiff".equals(mt)) return "tiff";
171                if("application/tif".equals(mt)) return "tiff";
172                if("application/x-tif".equals(mt)) return "tiff";
173                if("application/tiff".equals(mt)) return "tiff";
174                if("application/x-tiff".equals(mt)) return "tiff";
175                
176                if("image/bmp".equals(mt)) return "bmp";
177                if("image/vnd.wap.wbmp".equals(mt)) return "wbmp";
178                
179                if("image/fpx".equals(mt)) return "fpx";
180                if("image/x-fpx".equals(mt)) return "fpx";
181                if("image/vnd.fpx".equals(mt)) return "fpx";
182                if("image/vnd.netfpx".equals(mt)) return "fpx";
183                if("image/vnd.fpx".equals(mt)) return "fpx";
184                if("application/vnd.netfpx".equals(mt)) return "fpx";
185                if("application/vnd.fpx".equals(mt)) return "fpx";
186                
187                if("image/x-portable-anymap".equals(mt)) return "pnm";
188                if("image/x-portable/anymap".equals(mt)) return "pnm";
189                if("image/x-pnm".equals(mt)) return "pnm";
190                if("image/pnm".equals(mt)) return "pnm";
191                
192                if("image/x-portable-graymap".equals(mt)) return "pgm";
193                if("image/x-portable/graymap".equals(mt)) return "pgm";
194                if("image/x-pgm".equals(mt)) return "pgm";
195                if("image/pgm".equals(mt)) return "pgm";
196                
197                if("image/portable bitmap".equals(mt)) return "pbm";
198                if("image/x-portable-bitmap".equals(mt)) return "pbm";
199                if("image/x-portable/bitmap".equals(mt)) return "pbm";
200                if("image/x-pbm".equals(mt)) return "pbm";
201                if("image/pbm".equals(mt)) return "pbm";
202                
203                if("image/x-portable-pixmap".equals(mt)) return "ppm";
204                if("application/ppm".equals(mt)) return "ppm";
205                if("application/x-ppm".equals(mt)) return "ppm";
206                if("image/x-p".equals(mt)) return "ppm";
207                if("image/x-ppm".equals(mt)) return "ppm";
208                if("image/ppm".equals(mt)) return "ppm";
209
210                if("image/ico".equals(mt)) return "ico";
211                if("image/x-icon".equals(mt)) return "ico";
212                if("application/ico".equals(mt)) return "ico";
213                if("application/x-ico".equals(mt)) return "ico";
214
215                if("image/photoshop".equals(mt)) return "psd";
216                if("image/x-photoshop".equals(mt)) return "psd";
217                if("image/psd".equals(mt)) return "psd";
218                if("application/photoshop".equals(mt)) return "psd";
219                if("application/psd".equals(mt)) return "psd";
220                if("zz-application/zz-winassoc-psd".equals(mt)) return "psd";
221                
222                // can not terminate this types exactly
223                // image/x-xbitmap
224                // application/x-win-bitmap
225                // image/x-win-bitmap
226                // application/octet-stream
227                return defaultValue;
228        }
229        
230        
231        public static String getMimeTypeFromFormat(String mt) throws IOException {
232                if("gif".equals(mt)) return "image/gif";
233                if("jpeg".equals(mt)) return "image/jpg";
234                if("jpg".equals(mt)) return "image/jpg";
235                if("jpe".equals(mt)) return "image/jpg";
236                if("png".equals(mt)) return "image/png";
237                if("tiff".equals(mt)) return "image/tiff";
238                if("tif".equals(mt)) return "image/tiff";
239                if("bmp".equals(mt)) return "image/bmp";
240                if("bmp".equals(mt)) return "image/bmp";
241                if("wbmp".equals(mt)) return "image/vnd.wap.wbmp";
242                if("fpx".equals(mt)) return "image/fpx";
243                
244                if("pgm".equals(mt)) return "image/x-portable-graymap";
245                if("pnm".equals(mt)) return "image/x-portable-anymap";
246                if("pbm".equals(mt)) return "image/x-portable-bitmap";
247                if("ppm".equals(mt)) return "image/x-portable-pixmap";
248
249                if("ico".equals(mt)) return "image/ico";
250                if("psd".equals(mt)) return "image/psd";
251                
252                if(StringUtil.isEmpty(mt))throw new IOException("can't find Format of given image");//31
253                throw new IOException("can't find Format ("+mt+") of given image");
254        }
255
256        public static void closeEL(ImageInputStream iis) {
257                 try {
258                 if(iis!=null)iis.close();
259         } 
260         catch (Throwable t) {
261                        ExceptionUtil.rethrowIfNecessary(t);
262                }
263                
264                
265        }
266
267        public static BufferedImage createBufferedImage(BufferedImage image, int columns, int rows) {
268        ColorModel colormodel = image.getColorModel();
269        BufferedImage newImage;
270        if(colormodel instanceof IndexColorModel) {
271            if(colormodel.getTransparency() != 1)
272                newImage = new BufferedImage(columns, rows, 2);
273            else
274                newImage = new BufferedImage(columns, rows, 1);
275        } 
276        else {
277            newImage = new BufferedImage(colormodel, image.getRaster().createCompatibleWritableRaster(columns, rows), colormodel.isAlphaPremultiplied(), null);
278        }
279        return newImage;
280    }
281    
282    public static BufferedImage createBufferedImage(BufferedImage image) {
283        return createBufferedImage(image, image.getWidth(), image.getHeight());
284    }
285}