/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "ImageHashManager" #include "ImageHashManager.h" #include #include "pHash/phash_config.h" #include "pHash/phash_fingerprinter.h" #include namespace android { int32_t ImageHashManager::generatePHash(const uint8_t* buffer, int32_t width, int32_t height, int32_t stride, std::array* outImageHash) { if (width != kImageLength || height != kImageLength) { ALOGE("Failed to generate phash algorithm. Incorrect buffer size=%dx%d where %d is " "expected for width and height", width, height, kImageLength); return -EINVAL; } // Phash algorithm expects 1 byte per pixel instead of 4. Because the image is in grayscale, // RGB should all be the same and alpha should be 0xFF. The code below is compressing the full // buffer into a buffer that has 1 byte per pixel. std::array compressedBuffer; size_t index = 0; for (int32_t j = 0; j < height; j++) { const uint8_t* src = buffer + (stride * j) * 4; for (int32_t i = 0; i < width; i++) { uint8_t r = *src; uint8_t g = *(src + 1); uint8_t b = *(src + 2); if (r != g || r != b) { ALOGE("Failed to generate phash algorithm. Buffer is not in grayscale. r=%02X " "g=%02X b=%02X", r, g, b); return -EINVAL; } compressedBuffer[index] = *src; src += 4; index++; } } PhashFingerprinter worker; const int64_t result = worker.GenerateFingerprint(compressedBuffer.data()); *reinterpret_cast(outImageHash->data()) = result; return 0; } int32_t ImageHashManager::generateHash(std::string hashAlgorithm, const uint8_t* buf, AHardwareBuffer_Desc bufferDesc, std::array* outImageHash) { if (hashAlgorithm == "phash") { int32_t stride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width; return generatePHash(buf, bufferDesc.width, bufferDesc.height, stride, outImageHash); } ALOGE("Failed to generate hash. Invalid hash algorithm sent %s", hashAlgorithm.c_str()); return -EINVAL; } } // namespace android