|
1 /* |
|
2 * Copyright 2012 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 #include "SkBitmap.h" |
|
9 #include "SkBitmapHasher.h" |
|
10 #include "SkEndian.h" |
|
11 #include "SkImageEncoder.h" |
|
12 |
|
13 #include "SkMD5.h" |
|
14 |
|
15 /** |
|
16 * Write an int32 value to a stream in little-endian order. |
|
17 */ |
|
18 static void write_int32_to_buffer(uint32_t val, SkWStream* out) { |
|
19 val = SkEndian_SwapLE32(val); |
|
20 for (size_t byte = 0; byte < 4; ++byte) { |
|
21 out->write8((uint8_t)(val & 0xff)); |
|
22 val = val >> 8; |
|
23 } |
|
24 } |
|
25 |
|
26 /** |
|
27 * Return the first 8 bytes of a bytearray, encoded as a little-endian uint64. |
|
28 */ |
|
29 static inline uint64_t first_8_bytes_as_uint64(const uint8_t *bytearray) { |
|
30 return SkEndian_SwapLE64(*(reinterpret_cast<const uint64_t *>(bytearray))); |
|
31 } |
|
32 |
|
33 /*static*/ bool SkBitmapHasher::ComputeDigestInternal(const SkBitmap& bitmap, uint64_t *result) { |
|
34 SkMD5 out; |
|
35 |
|
36 // start with the x/y dimensions |
|
37 write_int32_to_buffer(SkToU32(bitmap.width()), &out); |
|
38 write_int32_to_buffer(SkToU32(bitmap.height()), &out); |
|
39 |
|
40 // add all the pixel data |
|
41 SkAutoTDelete<SkImageEncoder> enc(CreateARGBImageEncoder()); |
|
42 if (!enc->encodeStream(&out, bitmap, SkImageEncoder::kDefaultQuality)) { |
|
43 return false; |
|
44 } |
|
45 |
|
46 SkMD5::Digest digest; |
|
47 out.finish(digest); |
|
48 *result = first_8_bytes_as_uint64(digest.data); |
|
49 return true; |
|
50 } |
|
51 |
|
52 /*static*/ bool SkBitmapHasher::ComputeDigest(const SkBitmap& bitmap, uint64_t *result) { |
|
53 if (ComputeDigestInternal(bitmap, result)) { |
|
54 return true; |
|
55 } |
|
56 |
|
57 // Hmm, that didn't work. Maybe if we create a new |
|
58 // kARGB_8888_Config version of the bitmap it will work better? |
|
59 SkBitmap copyBitmap; |
|
60 if (!bitmap.copyTo(©Bitmap, kPMColor_SkColorType)) { |
|
61 return false; |
|
62 } |
|
63 return ComputeDigestInternal(copyBitmap, result); |
|
64 } |