• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.chimpchat.core;
17 
18 import java.awt.Graphics;
19 import java.awt.image.BufferedImage;
20 import java.io.ByteArrayOutputStream;
21 import java.io.File;
22 import java.io.IOException;
23 import java.lang.ref.WeakReference;
24 import java.util.Iterator;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27 
28 import javax.imageio.ImageIO;
29 import javax.imageio.ImageWriter;
30 import javax.imageio.stream.ImageOutputStream;
31 
32 /**
33  * Base class with basic functionality for ChimpImage implementations.
34  */
35 public abstract class ChimpImageBase implements IChimpImage {
36     private static Logger LOG = Logger.getLogger(ChimpImageBase.class.getCanonicalName());
37 
38     /**
39      * Convert the ChimpImage to a BufferedImage.
40      *
41      * @return a BufferedImage for this ChimpImage.
42      */
43     @Override
createBufferedImage()44     public abstract BufferedImage createBufferedImage();
45 
46     // Cache the BufferedImage so we don't have to generate it every time.
47     private WeakReference<BufferedImage> cachedBufferedImage = null;
48 
49     /**
50      * Utility method to handle getting the BufferedImage and managing the cache.
51      *
52      * @return the BufferedImage for this image.
53      */
54     @Override
getBufferedImage()55     public BufferedImage getBufferedImage() {
56         // Check the cache first
57         if (cachedBufferedImage != null) {
58             BufferedImage img = cachedBufferedImage.get();
59             if (img != null) {
60                 return img;
61             }
62         }
63 
64         // Not in the cache, so create it and cache it.
65         BufferedImage img = createBufferedImage();
66         cachedBufferedImage = new WeakReference<BufferedImage>(img);
67         return img;
68     }
69 
70     @Override
convertToBytes(String format)71     public byte[] convertToBytes(String format) {
72       BufferedImage argb = convertSnapshot();
73 
74       ByteArrayOutputStream os = new ByteArrayOutputStream();
75       try {
76           ImageIO.write(argb, format, os);
77       } catch (IOException e) {
78           return new byte[0];
79       }
80       return os.toByteArray();
81     }
82 
83     @Override
writeToFile(String path, String format)84     public boolean writeToFile(String path, String format) {
85         if (format != null) {
86             return writeToFileHelper(path, format);
87         }
88         int offset = path.lastIndexOf('.');
89         if (offset < 0) {
90             return writeToFileHelper(path, "png");
91         }
92         String ext = path.substring(offset + 1);
93         Iterator<ImageWriter> writers = ImageIO.getImageWritersBySuffix(ext);
94         if (!writers.hasNext()) {
95             return writeToFileHelper(path, "png");
96         }
97         ImageWriter writer = writers.next();
98         BufferedImage image = convertSnapshot();
99         try {
100             File f = new File(path);
101             f.delete();
102 
103             ImageOutputStream outputStream = ImageIO.createImageOutputStream(f);
104             writer.setOutput(outputStream);
105 
106             try {
107                 writer.write(image);
108             } finally {
109                 writer.dispose();
110                 outputStream.flush();
111             }
112         } catch (IOException e) {
113             return false;
114         }
115         return true;
116     }
117 
118     @Override
getPixel(int x, int y)119     public int getPixel(int x, int y) {
120         BufferedImage image = getBufferedImage();
121         return image.getRGB(x, y);
122     }
123 
convertSnapshot()124     private BufferedImage convertSnapshot() {
125         BufferedImage image = getBufferedImage();
126 
127         // Convert the image to ARGB so ImageIO writes it out nicely
128         BufferedImage argb = new BufferedImage(image.getWidth(), image.getHeight(),
129                 BufferedImage.TYPE_INT_ARGB);
130         Graphics g = argb.createGraphics();
131         g.drawImage(image, 0, 0, null);
132         g.dispose();
133         return argb;
134     }
135 
writeToFileHelper(String path, String format)136     private boolean writeToFileHelper(String path, String format) {
137         BufferedImage argb = convertSnapshot();
138 
139         try {
140             ImageIO.write(argb, format, new File(path));
141         } catch (IOException e) {
142             return false;
143         }
144         return true;
145     }
146 
147     @Override
sameAs(IChimpImage other, double percent)148     public boolean sameAs(IChimpImage other, double percent) {
149         BufferedImage otherImage = other.getBufferedImage();
150         BufferedImage myImage = getBufferedImage();
151 
152         // Easy size check
153         if (otherImage.getWidth() != myImage.getWidth()) {
154             return false;
155         }
156         if (otherImage.getHeight() != myImage.getHeight()) {
157             return false;
158         }
159 
160         int[] otherPixel = new int[1];
161         int[] myPixel = new int[1];
162 
163         int width = myImage.getWidth();
164         int height = myImage.getHeight();
165 
166         int numDiffPixels = 0;
167         // Now, go through pixel-by-pixel and check that the images are the same;
168         for (int y = 0; y < height; y++) {
169             for (int x = 0; x < width; x++) {
170                 if (myImage.getRGB(x, y) != otherImage.getRGB(x, y)) {
171                     numDiffPixels++;
172                 }
173             }
174         }
175         double numberPixels = (height * width);
176         double diffPercent = numDiffPixels / numberPixels;
177         return percent <= 1.0 - diffPercent;
178     }
179 
180     // TODO: figure out the location of this class and is superclasses
181     private static class BufferedImageChimpImage extends ChimpImageBase {
182         private final BufferedImage image;
183 
BufferedImageChimpImage(BufferedImage image)184         public BufferedImageChimpImage(BufferedImage image) {
185             this.image = image;
186         }
187 
188         @Override
createBufferedImage()189         public BufferedImage createBufferedImage() {
190             return image;
191         }
192     }
193 
loadImageFromFile(String path)194     public static IChimpImage loadImageFromFile(String path) {
195         File f = new File(path);
196         if (f.exists() && f.canRead()) {
197             try {
198                 BufferedImage bufferedImage = ImageIO.read(new File(path));
199                 if (bufferedImage == null) {
200                     LOG.log(Level.WARNING, "Cannot decode file %s", path);
201                     return null;
202                 }
203                 return new BufferedImageChimpImage(bufferedImage);
204             } catch (IOException e) {
205                 LOG.log(Level.WARNING, "Exception trying to decode image", e);
206                 return null;
207             }
208         } else {
209             LOG.log(Level.WARNING, "Cannot read file %s", path);
210             return null;
211         }
212     }
213 
214     @Override
getSubImage(int x, int y, int w, int h)215     public IChimpImage getSubImage(int x, int y, int w, int h) {
216         BufferedImage image = getBufferedImage();
217         return new BufferedImageChimpImage(image.getSubimage(x, y, w, h));
218     }
219 }
220