1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "ImageHashManager"
18
19 #include "ImageHashManager.h"
20 #include <log/log_main.h>
21 #include "pHash/phash_config.h"
22 #include "pHash/phash_fingerprinter.h"
23
24 #include <errno.h>
25
26 namespace android {
27
generatePHash(const uint8_t * buffer,int32_t width,int32_t height,int32_t stride,std::array<uint8_t,8> * outImageHash)28 int32_t ImageHashManager::generatePHash(const uint8_t* buffer, int32_t width, int32_t height,
29 int32_t stride, std::array<uint8_t, 8>* outImageHash) {
30 if (width != kImageLength || height != kImageLength) {
31 ALOGE("Failed to generate phash algorithm. Incorrect buffer size=%dx%d where %d is "
32 "expected for width and height",
33 width, height, kImageLength);
34 return -EINVAL;
35 }
36
37 // Phash algorithm expects 1 byte per pixel instead of 4. Because the image is in grayscale,
38 // RGB should all be the same and alpha should be 0xFF. The code below is compressing the full
39 // buffer into a buffer that has 1 byte per pixel.
40 std::array<uint8_t, kImageSize> compressedBuffer;
41 size_t index = 0;
42
43 for (int32_t j = 0; j < height; j++) {
44 const uint8_t* src = buffer + (stride * j) * 4;
45 for (int32_t i = 0; i < width; i++) {
46 uint8_t r = *src;
47 uint8_t g = *(src + 1);
48 uint8_t b = *(src + 2);
49 if (r != g || r != b) {
50 ALOGE("Failed to generate phash algorithm. Buffer is not in grayscale. r=%02X "
51 "g=%02X b=%02X",
52 r, g, b);
53 return -EINVAL;
54 }
55
56 compressedBuffer[index] = *src;
57 src += 4;
58 index++;
59 }
60 }
61
62 PhashFingerprinter worker;
63 const int64_t result = worker.GenerateFingerprint(compressedBuffer.data());
64 *reinterpret_cast<int64_t*>(outImageHash->data()) = result;
65 return 0;
66 }
67
generateHash(std::string hashAlgorithm,const uint8_t * buf,AHardwareBuffer_Desc bufferDesc,std::array<uint8_t,8> * outImageHash)68 int32_t ImageHashManager::generateHash(std::string hashAlgorithm, const uint8_t* buf,
69 AHardwareBuffer_Desc bufferDesc,
70 std::array<uint8_t, 8>* outImageHash) {
71 if (hashAlgorithm == "phash") {
72 int32_t stride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
73 return generatePHash(buf, bufferDesc.width, bufferDesc.height, stride, outImageHash);
74 }
75
76 ALOGE("Failed to generate hash. Invalid hash algorithm sent %s", hashAlgorithm.c_str());
77 return -EINVAL;
78 }
79
80 } // namespace android
81