blob: 5342d18d1007d592e5a9674358f530fc5fcda5ce [file] [log] [blame]
epoger@google.com31114c62012-12-12 17:22:23 +00001/*
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"
epoger@google.com908f5832013-04-12 02:23:55 +00009#include "SkBitmapHasher.h"
epoger@google.com31114c62012-12-12 17:22:23 +000010#include "SkEndian.h"
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000011#include "SkImageEncoder.h"
epoger@google.comb4ca46d2013-05-03 17:35:39 +000012
epoger@google.comb4ca46d2013-05-03 17:35:39 +000013#include "SkMD5.h"
epoger@google.com31114c62012-12-12 17:22:23 +000014
15/**
epoger@google.comb4ca46d2013-05-03 17:35:39 +000016 * Write an int32 value to a stream in little-endian order.
epoger@google.com31114c62012-12-12 17:22:23 +000017 */
epoger@google.comb4ca46d2013-05-03 17:35:39 +000018static void write_int32_to_buffer(uint32_t val, SkWStream* out) {
epoger@google.com31114c62012-12-12 17:22:23 +000019 val = SkEndian_SwapLE32(val);
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000020 for (size_t byte = 0; byte < 4; ++byte) {
21 out->write8((uint8_t)(val & 0xff));
epoger@google.com31114c62012-12-12 17:22:23 +000022 val = val >> 8;
23 }
24}
25
epoger@google.comb4ca46d2013-05-03 17:35:39 +000026/**
27 * Return the first 8 bytes of a bytearray, encoded as a little-endian uint64.
28 */
29static inline uint64_t first_8_bytes_as_uint64(const uint8_t *bytearray) {
30 return SkEndian_SwapLE64(*(reinterpret_cast<const uint64_t *>(bytearray)));
31}
32
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000033/*static*/ bool SkBitmapHasher::ComputeDigestInternal(const SkBitmap& bitmap,
34 SkHashDigest *result) {
epoger@google.comb4ca46d2013-05-03 17:35:39 +000035 SkMD5 out;
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000036
epoger@google.com31114c62012-12-12 17:22:23 +000037 // start with the x/y dimensions
epoger@google.comb4ca46d2013-05-03 17:35:39 +000038 write_int32_to_buffer(SkToU32(bitmap.width()), &out);
39 write_int32_to_buffer(SkToU32(bitmap.height()), &out);
epoger@google.com31114c62012-12-12 17:22:23 +000040
41 // add all the pixel data
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000042 SkAutoTDelete<SkImageEncoder> enc(CreateARGBImageEncoder());
43 if (!enc->encodeStream(&out, bitmap, SkImageEncoder::kDefaultQuality)) {
epoger@google.com908f5832013-04-12 02:23:55 +000044 return false;
epoger@google.com31114c62012-12-12 17:22:23 +000045 }
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000046
epoger@google.comb4ca46d2013-05-03 17:35:39 +000047 SkMD5::Digest digest;
48 out.finish(digest);
49 *result = first_8_bytes_as_uint64(digest.data);
epoger@google.com908f5832013-04-12 02:23:55 +000050 return true;
epoger@google.com31114c62012-12-12 17:22:23 +000051}
52
epoger@google.com908f5832013-04-12 02:23:55 +000053/*static*/ bool SkBitmapHasher::ComputeDigest(const SkBitmap& bitmap, SkHashDigest *result) {
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000054 if (ComputeDigestInternal(bitmap, result)) {
55 return true;
epoger@google.com31114c62012-12-12 17:22:23 +000056 }
57
58 // Hmm, that didn't work. Maybe if we create a new
59 // kARGB_8888_Config version of the bitmap it will work better?
60 SkBitmap copyBitmap;
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000061 if (!bitmap.copyTo(&copyBitmap, SkBitmap::kARGB_8888_Config)) {
epoger@google.com908f5832013-04-12 02:23:55 +000062 return false;
epoger@google.com31114c62012-12-12 17:22:23 +000063 }
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000064 return ComputeDigestInternal(copyBitmap, result);
epoger@google.com31114c62012-12-12 17:22:23 +000065}