blob: 82cbe9fa7e1be0b1f0d48f0f470fe1bdd7e51b36 [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
13#ifdef BITMAPHASHER_USES_TRUNCATED_MD5
14#include "SkMD5.h"
15#else
16#include "SkCityHash.h"
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000017#include "SkStream.h"
epoger@google.comb4ca46d2013-05-03 17:35:39 +000018#endif
epoger@google.com31114c62012-12-12 17:22:23 +000019
20/**
epoger@google.comb4ca46d2013-05-03 17:35:39 +000021 * Write an int32 value to a stream in little-endian order.
epoger@google.com31114c62012-12-12 17:22:23 +000022 */
epoger@google.comb4ca46d2013-05-03 17:35:39 +000023static void write_int32_to_buffer(uint32_t val, SkWStream* out) {
epoger@google.com31114c62012-12-12 17:22:23 +000024 val = SkEndian_SwapLE32(val);
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000025 for (size_t byte = 0; byte < 4; ++byte) {
26 out->write8((uint8_t)(val & 0xff));
epoger@google.com31114c62012-12-12 17:22:23 +000027 val = val >> 8;
28 }
29}
30
epoger@google.comb4ca46d2013-05-03 17:35:39 +000031/**
32 * Return the first 8 bytes of a bytearray, encoded as a little-endian uint64.
33 */
34static inline uint64_t first_8_bytes_as_uint64(const uint8_t *bytearray) {
35 return SkEndian_SwapLE64(*(reinterpret_cast<const uint64_t *>(bytearray)));
36}
37
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000038/*static*/ bool SkBitmapHasher::ComputeDigestInternal(const SkBitmap& bitmap,
39 SkHashDigest *result) {
epoger@google.comb4ca46d2013-05-03 17:35:39 +000040#ifdef BITMAPHASHER_USES_TRUNCATED_MD5
41 SkMD5 out;
42#else
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000043 size_t pixelBufferSize = bitmap.width() * bitmap.height() * 4;
44 size_t totalBufferSize = pixelBufferSize + 2 * sizeof(uint32_t);
epoger@google.com31114c62012-12-12 17:22:23 +000045
46 SkAutoMalloc bufferManager(totalBufferSize);
47 char *bufferStart = static_cast<char *>(bufferManager.get());
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000048 SkMemoryWStream out(bufferStart, totalBufferSize);
epoger@google.comb4ca46d2013-05-03 17:35:39 +000049#endif
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000050
epoger@google.com31114c62012-12-12 17:22:23 +000051 // start with the x/y dimensions
epoger@google.comb4ca46d2013-05-03 17:35:39 +000052 write_int32_to_buffer(SkToU32(bitmap.width()), &out);
53 write_int32_to_buffer(SkToU32(bitmap.height()), &out);
epoger@google.com31114c62012-12-12 17:22:23 +000054
55 // add all the pixel data
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000056 SkAutoTDelete<SkImageEncoder> enc(CreateARGBImageEncoder());
57 if (!enc->encodeStream(&out, bitmap, SkImageEncoder::kDefaultQuality)) {
epoger@google.com908f5832013-04-12 02:23:55 +000058 return false;
epoger@google.com31114c62012-12-12 17:22:23 +000059 }
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000060
epoger@google.comb4ca46d2013-05-03 17:35:39 +000061#ifdef BITMAPHASHER_USES_TRUNCATED_MD5
62 SkMD5::Digest digest;
63 out.finish(digest);
64 *result = first_8_bytes_as_uint64(digest.data);
65#else
epoger@google.com908f5832013-04-12 02:23:55 +000066 *result = SkCityHash::Compute64(bufferStart, totalBufferSize);
epoger@google.comb4ca46d2013-05-03 17:35:39 +000067#endif
epoger@google.com908f5832013-04-12 02:23:55 +000068 return true;
epoger@google.com31114c62012-12-12 17:22:23 +000069}
70
epoger@google.com908f5832013-04-12 02:23:55 +000071/*static*/ bool SkBitmapHasher::ComputeDigest(const SkBitmap& bitmap, SkHashDigest *result) {
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000072 if (ComputeDigestInternal(bitmap, result)) {
73 return true;
epoger@google.com31114c62012-12-12 17:22:23 +000074 }
75
76 // Hmm, that didn't work. Maybe if we create a new
77 // kARGB_8888_Config version of the bitmap it will work better?
78 SkBitmap copyBitmap;
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000079 if (!bitmap.copyTo(&copyBitmap, SkBitmap::kARGB_8888_Config)) {
epoger@google.com908f5832013-04-12 02:23:55 +000080 return false;
epoger@google.com31114c62012-12-12 17:22:23 +000081 }
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000082 return ComputeDigestInternal(copyBitmap, result);
epoger@google.com31114c62012-12-12 17:22:23 +000083}