• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <cstdio>
16 #include <cmath>
17 #include <unistd.h>
18 
19 
20 #include "image_compress.h"
21 
22 #include "app_log_wrapper.h"
23 #include "securec.h"
24 #include "image_source.h"
25 #include "image_packer.h"
26 #include "media_errors.h"
27 
28 namespace OHOS {
29 namespace AppExecFwk {
30 namespace {
31     constexpr size_t FORMAT_LENGTH = 8;
32     const std::string JPEG_FORMAT = "image/jpeg";
33     const std::string PNG_FORMAT = "image/png";
34     const std::string WEBP_FORMAT = "image/webp";
35     const std::string BUNDLE_PATH = "/data/app/el1/bundle";
36     constexpr int32_t QUALITY = 20;
37     constexpr int32_t MUNBER_ONE = 1;
38     constexpr int64_t BUFFER_SIZE = 2 * 1024 * 1024;
39     constexpr int32_t FILE_MAX_SIZE = 10240;
40     constexpr int32_t FILE_COMPRESS_SIZE = 4096;
41     constexpr int32_t WEBP_COMPRESS_SIZE = 128;
42     constexpr uint8_t JPEG_DATA_ZERO = 0xFF;
43     constexpr uint8_t JPEG_DATA_ONE = 0xD8;
44     constexpr uint8_t JPEG_DATA_TWO = 0xFF;
45     constexpr uint8_t PNG_DATA_ZERO = 0x89;
46     constexpr uint8_t PNG_DATA_ONE = 0x50;
47     constexpr uint8_t PNG_DATA_TWO = 0x4E;
48     constexpr uint8_t PNG_DATA_THREE = 0x47;
49     constexpr int32_t INDEX_ZERO = 0;
50     constexpr int32_t INDEX_ONE = 1;
51     constexpr int32_t INDEX_TWO = 2;
52     constexpr int32_t INDEX_THREE = 3;
53 }
IsPathValid(const std::string & srcPath)54 bool ImageCompress::IsPathValid(const std::string &srcPath)
55 {
56     if (srcPath.find(BUNDLE_PATH) != std::string::npos) {
57         return access(srcPath.c_str(), R_OK) == 0;
58     } else {
59         return false;
60     }
61 }
62 
IsImageNeedCompressBySize(size_t fileSize)63 bool ImageCompress::IsImageNeedCompressBySize(size_t fileSize)
64 {
65     return fileSize > FILE_MAX_SIZE;
66 }
67 
CalculateRatio(size_t fileSize,const std::string & imageType)68 double ImageCompress::CalculateRatio(size_t fileSize, const std::string &imageType)
69 {
70     if (imageType == WEBP_FORMAT) {
71         return sqrt(static_cast<double>(WEBP_COMPRESS_SIZE) / fileSize);
72     }
73     return sqrt(static_cast<double>(FILE_COMPRESS_SIZE) / fileSize);
74 }
75 
GetImageType(const std::unique_ptr<uint8_t[]> & fileData,size_t fileLength)76 ImageType ImageCompress::GetImageType(const std::unique_ptr<uint8_t[]> &fileData, size_t fileLength)
77 {
78     if (fileLength < FORMAT_LENGTH) {
79         return ImageType::WORNG_TYPE;
80     }
81     const uint8_t* data = fileData.get();
82     if (data[INDEX_ZERO] == JPEG_DATA_ZERO && data[INDEX_ONE] == JPEG_DATA_ONE
83         && data[INDEX_TWO] == JPEG_DATA_TWO) {
84         return ImageType::JPEG;
85     } else if (data[INDEX_ZERO] == PNG_DATA_ZERO && data[INDEX_ONE] == PNG_DATA_ONE &&
86         data[INDEX_TWO] == PNG_DATA_TWO && data[INDEX_THREE] == PNG_DATA_THREE) {
87         return ImageType::PNG;
88     } else {
89         return ImageType::WORNG_TYPE;
90     }
91 }
92 
GetImageTypeString(const std::unique_ptr<uint8_t[]> & fileData,size_t fileLength,std::string & imageType)93 bool ImageCompress::GetImageTypeString(const std::unique_ptr<uint8_t[]> &fileData,
94     size_t fileLength, std::string &imageType)
95 {
96     ImageType type = GetImageType(fileData, fileLength);
97     if (type == ImageType::WORNG_TYPE) {
98         APP_LOGE("input wrong type image!");
99         return false;
100     }
101     imageType = type == ImageType::JPEG ? JPEG_FORMAT : PNG_FORMAT;
102     return true;
103 }
104 
GetImageFileInfo(const std::string & srcFile,std::unique_ptr<uint8_t[]> & fileContent,int64_t & fileLength)105 bool ImageCompress::GetImageFileInfo(const std::string &srcFile,
106     std::unique_ptr<uint8_t[]> &fileContent, int64_t &fileLength)
107 {
108     if (!IsPathValid(srcFile)) {
109         APP_LOGE("%{public}s is unavailable", srcFile.c_str());
110         return false;
111     }
112     FILE* file = fopen(srcFile.c_str(), "rb");
113     if (!file) {
114         APP_LOGE("ImageCompress: GetImageTypeByFile %{public}s is unavailable", srcFile.c_str());
115         return false;
116     }
117     if (fseek(file, 0L, SEEK_END) != 0) {
118         fclose(file);
119         return false;
120     }
121     fileLength = ftell(file);
122     rewind(file);
123     fileContent = std::make_unique<uint8_t[]>(fileLength);
124     if (!fread(fileContent.get(), sizeof(uint8_t), fileLength, file)) {
125         APP_LOGE("read file failed!");
126         fclose(file);
127         return false;
128     }
129     if (fclose(file) != 0) {
130         APP_LOGE("close file failed!");
131         return false;
132     }
133     return true;
134 }
135 
CompressImageByContent(const std::unique_ptr<uint8_t[]> & fileData,size_t fileSize,std::unique_ptr<uint8_t[]> & compressedData,int64_t & compressedSize,std::string & imageType)136 bool ImageCompress::CompressImageByContent(const std::unique_ptr<uint8_t[]> &fileData, size_t fileSize,
137     std::unique_ptr<uint8_t[]> &compressedData, int64_t &compressedSize, std::string &imageType)
138 {
139     ImageType type = GetImageType(fileData, fileSize);
140     if (type == ImageType::WORNG_TYPE) {
141         APP_LOGE("input wrong image!");
142         return false;
143     }
144     imageType = type == ImageType::JPEG ? JPEG_FORMAT : WEBP_FORMAT;
145     uint32_t errorCode = 0;
146     Media::SourceOptions options;
147     std::unique_ptr<Media::ImageSource> imageSourcePtr =
148         Media::ImageSource::CreateImageSource(fileData.get(), fileSize, options, errorCode);
149     // do compress
150     Media::DecodeOptions decodeOptions;
151     uint32_t pixMapError = 0;
152     std::unique_ptr<Media::PixelMap> pixMap = imageSourcePtr->CreatePixelMap(decodeOptions, pixMapError);
153     if (pixMap == nullptr || pixMapError != Media::SUCCESS) {
154         APP_LOGE("CreatePixelMap failed!");
155         return false;
156     }
157     double ratio = CalculateRatio(fileSize, imageType);
158     APP_LOGE("ratio is %{public}f", ratio);
159     pixMap->scale(ratio, ratio);
160     Media::ImagePacker imagePacker;
161     Media::PackOption packOption;
162     packOption.format = imageType;
163     packOption.quality = QUALITY;
164     packOption.numberHint = MUNBER_ONE;
165     uint8_t *resultBuffer = reinterpret_cast<uint8_t *>(malloc(BUFFER_SIZE));
166     if (resultBuffer == nullptr) {
167         APP_LOGE("image packer malloc buffer failed.");
168         return 0;
169     }
170     imagePacker.StartPacking(resultBuffer, BUFFER_SIZE, packOption);
171     imagePacker.AddImage(*pixMap);
172     imagePacker.FinalizePacking(compressedSize);
173     compressedData = std::make_unique<uint8_t[]>(compressedSize);
174     APP_LOGD("compressedSize is %{public}d", static_cast<int32_t>(compressedSize));
175     uint8_t *result = compressedData.get();
176     if (memcpy_s(result, compressedSize, resultBuffer, compressedSize) != EOK) {
177         free(resultBuffer);
178         APP_LOGE("memcpy_s to compressedData failed!");
179         return false;
180     }
181     free(resultBuffer);
182     return true;
183 }
184 }
185 }