• 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     constexpr int32_t EMPTY_FILE_SIZE = 0;
54     constexpr double FILE_SIZE_ERR = -1.0;
55 }
IsPathValid(const std::string & srcPath)56 bool ImageCompress::IsPathValid(const std::string &srcPath)
57 {
58     if (srcPath.find(BUNDLE_PATH) != std::string::npos) {
59         return access(srcPath.c_str(), R_OK) == 0;
60     } else {
61         return false;
62     }
63 }
64 
IsImageNeedCompressBySize(size_t fileSize)65 bool ImageCompress::IsImageNeedCompressBySize(size_t fileSize)
66 {
67     return fileSize > FILE_MAX_SIZE;
68 }
69 
CalculateRatio(size_t fileSize,const std::string & imageType)70 double ImageCompress::CalculateRatio(size_t fileSize, const std::string &imageType)
71 {
72     if (fileSize == EMPTY_FILE_SIZE) {
73         return FILE_SIZE_ERR;
74     }
75     if (imageType == WEBP_FORMAT) {
76         return sqrt(static_cast<double>(WEBP_COMPRESS_SIZE) / fileSize);
77     }
78     return sqrt(static_cast<double>(FILE_COMPRESS_SIZE) / fileSize);
79 }
80 
GetImageType(const std::unique_ptr<uint8_t[]> & fileData,size_t fileLength)81 ImageType ImageCompress::GetImageType(const std::unique_ptr<uint8_t[]> &fileData, size_t fileLength)
82 {
83     if (fileLength < FORMAT_LENGTH) {
84         return ImageType::WORNG_TYPE;
85     }
86     const uint8_t* data = fileData.get();
87     if (data[INDEX_ZERO] == JPEG_DATA_ZERO && data[INDEX_ONE] == JPEG_DATA_ONE
88         && data[INDEX_TWO] == JPEG_DATA_TWO) {
89         return ImageType::JPEG;
90     } else if (data[INDEX_ZERO] == PNG_DATA_ZERO && data[INDEX_ONE] == PNG_DATA_ONE &&
91         data[INDEX_TWO] == PNG_DATA_TWO && data[INDEX_THREE] == PNG_DATA_THREE) {
92         return ImageType::PNG;
93     } else {
94         return ImageType::WORNG_TYPE;
95     }
96 }
97 
GetImageTypeString(const std::unique_ptr<uint8_t[]> & fileData,size_t fileLength,std::string & imageType)98 bool ImageCompress::GetImageTypeString(const std::unique_ptr<uint8_t[]> &fileData,
99     size_t fileLength, std::string &imageType)
100 {
101     ImageType type = GetImageType(fileData, fileLength);
102     if (type == ImageType::WORNG_TYPE) {
103         APP_LOGE("input wrong type image!");
104         return false;
105     }
106     imageType = type == ImageType::JPEG ? JPEG_FORMAT : PNG_FORMAT;
107     return true;
108 }
109 
GetImageFileInfo(const std::string & srcFile,std::unique_ptr<uint8_t[]> & fileContent,int64_t & fileLength)110 bool ImageCompress::GetImageFileInfo(const std::string &srcFile,
111     std::unique_ptr<uint8_t[]> &fileContent, int64_t &fileLength)
112 {
113     if (!IsPathValid(srcFile)) {
114         APP_LOGE("%{public}s is unavailable", srcFile.c_str());
115         return false;
116     }
117     FILE* file = fopen(srcFile.c_str(), "rb");
118     if (!file) {
119         APP_LOGE("ImageCompress: GetImageTypeByFile %{public}s is unavailable", srcFile.c_str());
120         return false;
121     }
122     if (fseek(file, 0L, SEEK_END) != 0) {
123         fclose(file);
124         return false;
125     }
126     fileLength = ftell(file);
127     rewind(file);
128     fileContent = std::make_unique<uint8_t[]>(fileLength);
129     if (!fread(fileContent.get(), sizeof(uint8_t), fileLength, file)) {
130         APP_LOGE("read file failed!");
131         fclose(file);
132         return false;
133     }
134     if (fclose(file) != 0) {
135         APP_LOGE("close file failed!");
136         return false;
137     }
138     return true;
139 }
140 
CompressImageByContent(const std::unique_ptr<uint8_t[]> & fileData,size_t fileSize,std::unique_ptr<uint8_t[]> & compressedData,int64_t & compressedSize,std::string & imageType)141 bool ImageCompress::CompressImageByContent(const std::unique_ptr<uint8_t[]> &fileData, size_t fileSize,
142     std::unique_ptr<uint8_t[]> &compressedData, int64_t &compressedSize, std::string &imageType)
143 {
144     ImageType type = GetImageType(fileData, fileSize);
145     if (type == ImageType::WORNG_TYPE) {
146         APP_LOGE("input wrong image!");
147         return false;
148     }
149     imageType = type == ImageType::JPEG ? JPEG_FORMAT : WEBP_FORMAT;
150     uint32_t errorCode = 0;
151     Media::SourceOptions options;
152     std::unique_ptr<Media::ImageSource> imageSourcePtr =
153         Media::ImageSource::CreateImageSource(fileData.get(), fileSize, options, errorCode);
154     // do compress
155     Media::DecodeOptions decodeOptions;
156     uint32_t pixMapError = 0;
157     std::unique_ptr<Media::PixelMap> pixMap = imageSourcePtr->CreatePixelMap(decodeOptions, pixMapError);
158     if (pixMap == nullptr || pixMapError != Media::SUCCESS) {
159         APP_LOGE("CreatePixelMap failed!");
160         return false;
161     }
162     double ratio = CalculateRatio(fileSize, imageType);
163     if (ratio == FILE_SIZE_ERR) {
164         APP_LOGE("CalculateRatio failed: ratio is %{public}f", ratio);
165         return false;
166     }
167     APP_LOGD("ratio is %{public}f", ratio);
168     pixMap->scale(ratio, ratio);
169     Media::ImagePacker imagePacker;
170     Media::PackOption packOption;
171     packOption.format = imageType;
172     packOption.quality = QUALITY;
173     packOption.numberHint = MUNBER_ONE;
174     uint8_t *resultBuffer = reinterpret_cast<uint8_t *>(malloc(BUFFER_SIZE));
175     if (resultBuffer == nullptr) {
176         APP_LOGE("image packer malloc buffer failed.");
177         return 0;
178     }
179     imagePacker.StartPacking(resultBuffer, BUFFER_SIZE, packOption);
180     imagePacker.AddImage(*pixMap);
181     imagePacker.FinalizePacking(compressedSize);
182     compressedData = std::make_unique<uint8_t[]>(compressedSize);
183     APP_LOGD("compressedSize is %{public}d", static_cast<int32_t>(compressedSize));
184     uint8_t *result = compressedData.get();
185     if (memcpy_s(result, compressedSize, resultBuffer, compressedSize) != EOK) {
186         free(resultBuffer);
187         APP_LOGE("memcpy_s to compressedData failed!");
188         return false;
189     }
190     free(resultBuffer);
191     return true;
192 }
193 }
194 }