blob: e8352e59b982bb4a1e64d6eb73b45e2de5a4f7af [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 "SkCityHash.h"
11#include "SkEndian.h"
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000012#include "SkImageEncoder.h"
13#include "SkStream.h"
epoger@google.com31114c62012-12-12 17:22:23 +000014
15/**
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000016 * Write an integer value to a stream in little-endian order.
epoger@google.com31114c62012-12-12 17:22:23 +000017 */
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000018static void write_int_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
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000026/*static*/ bool SkBitmapHasher::ComputeDigestInternal(const SkBitmap& bitmap,
27 SkHashDigest *result) {
28 size_t pixelBufferSize = bitmap.width() * bitmap.height() * 4;
29 size_t totalBufferSize = pixelBufferSize + 2 * sizeof(uint32_t);
epoger@google.com31114c62012-12-12 17:22:23 +000030
31 SkAutoMalloc bufferManager(totalBufferSize);
32 char *bufferStart = static_cast<char *>(bufferManager.get());
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000033 SkMemoryWStream out(bufferStart, totalBufferSize);
34
epoger@google.com31114c62012-12-12 17:22:23 +000035 // start with the x/y dimensions
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000036 write_int_to_buffer(SkToU32(bitmap.width()), &out);
37 write_int_to_buffer(SkToU32(bitmap.height()), &out);
epoger@google.com31114c62012-12-12 17:22:23 +000038
39 // add all the pixel data
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000040 SkAutoTDelete<SkImageEncoder> enc(CreateARGBImageEncoder());
41 if (!enc->encodeStream(&out, bitmap, SkImageEncoder::kDefaultQuality)) {
epoger@google.com908f5832013-04-12 02:23:55 +000042 return false;
epoger@google.com31114c62012-12-12 17:22:23 +000043 }
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000044
epoger@google.com908f5832013-04-12 02:23:55 +000045 *result = SkCityHash::Compute64(bufferStart, totalBufferSize);
46 return true;
epoger@google.com31114c62012-12-12 17:22:23 +000047}
48
epoger@google.com908f5832013-04-12 02:23:55 +000049/*static*/ bool SkBitmapHasher::ComputeDigest(const SkBitmap& bitmap, SkHashDigest *result) {
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000050 if (ComputeDigestInternal(bitmap, result)) {
51 return true;
epoger@google.com31114c62012-12-12 17:22:23 +000052 }
53
54 // Hmm, that didn't work. Maybe if we create a new
55 // kARGB_8888_Config version of the bitmap it will work better?
56 SkBitmap copyBitmap;
bungeman@google.com8c6a4f22013-04-23 18:06:23 +000057 if (!bitmap.copyTo(&copyBitmap, SkBitmap::kARGB_8888_Config)) {
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 return ComputeDigestInternal(copyBitmap, result);
epoger@google.com31114c62012-12-12 17:22:23 +000061}