* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* 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.
*/
#include "pixel_map_util.h"
#include "image_packer.h"
#include "hilog_wrapper.h"
#include "image_source.h"
#include "file_utils.h"
namespace OHOS {
namespace Contacts {
namespace PixelMapUtil {
using namespace Media;
constexpr uint8_t DEFAULT_IMAGE_QUALITY = 90;
constexpr uint32_t IMAGE_NUMBER_HINT = 1;
constexpr int32_t SHORT_SIDE_THRESHOLD = 512;
constexpr int32_t LONG_SIDE_THRESHOLD = 1920;
constexpr int32_t MAXIMUM_LONG_SIDE = 4096;
constexpr int32_t PHOTO_TYPE_BIG = 3;
constexpr int32_t PHOTO_TYPE_SMALL = 1;
constexpr int32_t MIN_RESOLUTION = 409600;
constexpr int32_t MIN_TUMBNAIL_FILE_SIZE = 1024 * 1024;
constexpr float SMALL_AVATAR_SIZE = 280;
const std::string IMAGE_FORMAT = "image/jpeg";
uint32_t SavePixelMapToFile(const std::unique_ptr<PixelMap>& pixelMap, const int fileDescriptor)
{
PackOption option = {
.format = IMAGE_FORMAT,
.quality = DEFAULT_IMAGE_QUALITY,
.numberHint = IMAGE_NUMBER_HINT,
.desiredDynamicRange = EncodeDynamicRange::AUTO,
};
ImagePacker imagePacker;
uint32_t err = imagePacker.StartPacking(fileDescriptor, option);
if (err != 0) {
HILOG_ERROR("PixelMapUtil SavePixelMapToFile Failed to StartPacking %{public}d", err);
return err;
}
err = imagePacker.AddImage(*pixelMap);
if (err != 0) {
HILOG_ERROR("PixelMapUtil SavePixelMapToFile Failed to AddPicture %{public}d", err);
return err;
}
err = imagePacker.FinalizePacking();
if (err != 0) {
HILOG_ERROR("PixelMapUtil SavePixelMapToFile Failed to FinalizePacking %{public}d", err);
return err;
}
HILOG_DEBUG("PixelMapUtil SavePixelMapToFile SavePixelMapToFile success");
return 0;
}
std::unique_ptr<PixelMap> GetPixelMapFromFile(const std::string &filePath)
{
uint32_t errorCode = 0;
SourceOptions opts;
std::unique_ptr<ImageSource> imageSource =
ImageSource::CreateImageSource(filePath, opts, errorCode);
if (imageSource == nullptr) {
HILOG_ERROR("PixelMapUtil GetPixelMapFromFile CreateImageSource Failed %{public}u", errorCode);
return nullptr;
}
int32_t value = 0;
imageSource->GetImagePropertyInt(0, "Orientation", value);
const DecodeOptions decodeOpts;
std::unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode);
if (pixelMap == nullptr) {
HILOG_ERROR("PixelMapUtil GetPixelMapFromFile CreatePixelMap Failed %{public}u", errorCode);
return nullptr;
}
HILOG_DEBUG("PixelMapUtil GetPixelMapFromFile success");
pixelMap->rotate(value);
return pixelMap;
}
uint32_t GetArrayBufferFromPixelMap(const std::unique_ptr<PixelMap> &pixelMap, std::vector<uint8_t> &data)
{
CropPixelMap(pixelMap);
ImageInfo info;
pixelMap->GetImageInfo(info);
int32_t height = (info.size.height != 0) ? info.size.height : 100;
int32_t width = (info.size.width != 0) ? info.size.width : 100;
HILOG_INFO("GetArrayBufferFromPixelMap height %{public}d width %{public}d", height, width);
data.resize(pixelMap->GetByteCount());
ImagePacker imagePacker;
PackOption option = {
.format = IMAGE_FORMAT,
.quality = DEFAULT_IMAGE_QUALITY,
.numberHint = IMAGE_NUMBER_HINT,
.desiredDynamicRange = EncodeDynamicRange::AUTO,
};
uint32_t err = imagePacker.StartPacking(data.data(), data.size(), option);
if (err != 0) {
HILOG_ERROR("GetArrayBufferFromPixelMap Failed to StartPacking %{public}d", err);
return err;
}
err = imagePacker.AddImage(*pixelMap);
if (err != 0) {
HILOG_ERROR("GetArrayBufferFromPixelMap Failed to AddPicture %{public}d", err);
return err;
}
int64_t packedSize = 0;
imagePacker.FinalizePacking(packedSize);
HILOG_DEBUG("PixelMapUtil GetArrayBufferFromPixelMap success");
return 0;
}
void CropPixelMap(const std::unique_ptr<PixelMap> &pixelMap)
{
ImageInfo info;
pixelMap->GetImageInfo(info);
int32_t height = (info.size.height != 0) ? info.size.height : 100;
int32_t width = (info.size.width != 0) ? info.size.width : 100;
int32_t shortSide = height > width ? width : height;
int32_t cropY = (height - width) / 2;
cropY = cropY < 0 ? 0 : cropY;
Rect rect { 0, cropY, shortSide, shortSide };
pixelMap->crop(rect);
float scale = 0.5;
if (shortSide > 0) {
scale = SMALL_AVATAR_SIZE / shortSide;
}
HILOG_INFO("CropPixelMap scale %{public}f height %{public}d width %{public}d ", scale, height, width);
pixelMap->scale(scale, scale);
}
void GetThumbnailPixelMap(const std::unique_ptr<Media::PixelMap>& pixelMap, const int fileDescriptor)
{
FileUtils fileUtils;
int32_t fileSize = 0;
if (!fileUtils.GetFileSize(fileDescriptor, fileSize) || fileSize <= MIN_TUMBNAIL_FILE_SIZE) {
return;
}
Media::ImageInfo info;
pixelMap->GetImageInfo(info);
int32_t height = (info.size.height != 0) ? info.size.height : 100;
int32_t width = (info.size.width != 0) ? info.size.width : 100;
auto scale = GetThumbnailScale(height, width);
pixelMap->scale(scale, scale);
HILOG_INFO("GetThumbnailPixelMap height %{public}d width %{public}d sacle %{public}f", height, width, scale);
}
float GetThumbnailScale(int32_t height, int32_t width)
{
int32_t longSide = height > width ? height : width;
int32_t shortSide = height > width ? width : height;
int32_t srcShortSide = shortSide;
double ratio = static_cast<double>(longSide) / shortSide;
if (longSide > LONG_SIDE_THRESHOLD) {
longSide = LONG_SIDE_THRESHOLD;
shortSide = static_cast<int>(SHORT_SIDE_THRESHOLD / ratio);
}
if (shortSide < SHORT_SIDE_THRESHOLD && srcShortSide >= SHORT_SIDE_THRESHOLD) {
shortSide = SHORT_SIDE_THRESHOLD;
longSide = static_cast<int>(SHORT_SIDE_THRESHOLD * ratio);
}
if (longSide > MAXIMUM_LONG_SIDE) {
longSide = MAXIMUM_LONG_SIDE;
shortSide = static_cast<int>(MAXIMUM_LONG_SIDE / ratio);
}
return static_cast<double>(shortSide) / srcShortSide;
}
int GetBlobSourceFromPixelMap(const std::unique_ptr<PixelMap> &pixelMap)
{
Media::ImageInfo info;
pixelMap->GetImageInfo(info);
int32_t height = info.size.height;
int32_t width = info.size.width;
return (static_cast<int64_t>(height) * width) <= MIN_RESOLUTION ? PHOTO_TYPE_SMALL : PHOTO_TYPE_BIG;
}
}
}
}