|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.favicons.decoders; |
|
6 |
|
7 import android.graphics.Bitmap; |
|
8 import android.util.Log; |
|
9 |
|
10 import java.io.ByteArrayOutputStream; |
|
11 import java.util.Iterator; |
|
12 |
|
13 /** |
|
14 * Class representing the result of loading a favicon. |
|
15 * This operation will produce either a collection of favicons, a single favicon, or no favicon. |
|
16 * It is necessary to model single favicons differently to a collection of one favicon (An entity |
|
17 * that may not exist with this scheme) since the in-database representation of these things differ. |
|
18 * (In particular, collections of favicons are stored in encoded ICO format, whereas single icons are |
|
19 * stored as decoded bitmap blobs.) |
|
20 */ |
|
21 public class LoadFaviconResult { |
|
22 private static final String LOGTAG = "LoadFaviconResult"; |
|
23 |
|
24 byte[] faviconBytes; |
|
25 int offset; |
|
26 int length; |
|
27 |
|
28 boolean isICO; |
|
29 Iterator<Bitmap> bitmapsDecoded; |
|
30 |
|
31 public Iterator<Bitmap> getBitmaps() { |
|
32 return bitmapsDecoded; |
|
33 } |
|
34 |
|
35 /** |
|
36 * Return a representation of this result suitable for storing in the database. |
|
37 * |
|
38 * @return A byte array containing the bytes from which this result was decoded, |
|
39 * or null if re-encoding failed. |
|
40 */ |
|
41 public byte[] getBytesForDatabaseStorage() { |
|
42 // Begin by normalising the buffer. |
|
43 if (offset != 0 || length != faviconBytes.length) { |
|
44 final byte[] normalised = new byte[length]; |
|
45 System.arraycopy(faviconBytes, offset, normalised, 0, length); |
|
46 offset = 0; |
|
47 faviconBytes = normalised; |
|
48 } |
|
49 |
|
50 // For results containing multiple images, we store the result verbatim. (But cutting the |
|
51 // buffer to size first). |
|
52 // We may instead want to consider re-encoding the entire ICO as a collection of efficiently |
|
53 // encoded PNGs. This may not be worth the CPU time (Indeed, the encoding of single-image |
|
54 // favicons may also not be worth the time/space tradeoff.). |
|
55 if (isICO) { |
|
56 return faviconBytes; |
|
57 } |
|
58 |
|
59 // For results containing a single image, we re-encode the |
|
60 // result as a PNG in an effort to save space. |
|
61 final Bitmap favicon = ((FaviconDecoder.SingleBitmapIterator) bitmapsDecoded).peek(); |
|
62 final ByteArrayOutputStream stream = new ByteArrayOutputStream(); |
|
63 |
|
64 try { |
|
65 if (favicon.compress(Bitmap.CompressFormat.PNG, 100, stream)) { |
|
66 return stream.toByteArray(); |
|
67 } |
|
68 } catch (OutOfMemoryError e) { |
|
69 Log.w(LOGTAG, "Out of memory re-compressing favicon."); |
|
70 } |
|
71 |
|
72 Log.w(LOGTAG, "Favicon re-compression failed."); |
|
73 return null; |
|
74 } |
|
75 |
|
76 } |