scale icon

Signed-off-by: liduo <liduo29@huawei.com>
This commit is contained in:
liduo
2024-09-07 15:59:42 +08:00
parent 993da69412
commit 06d27e66ee
13 changed files with 235 additions and 18 deletions
+9
View File
@@ -52,9 +52,15 @@ struct TranscodeResult {
int32_t height;
};
struct ImageSize {
size_t width;
size_t height;
};
typedef TranscodeError (*ITranscodeImages) (const std::string &imagePath, const bool extAppend,
std::string &outputPath, TranscodeResult &result);
typedef bool (*ISetTranscodeOptions) (const std::string &optionJson, const std::string &optionJsonExclude);
typedef TranscodeError (*IScaleImage) (const std::string &imagePath, std::string &outputPath, ImageSize size);
class CompressionParser {
public:
@@ -69,6 +75,8 @@ public:
std::string PrintTransMessage();
bool GetDefaultCompress();
void SetOutPath(const std::string &path);
bool ScaleIconEnable();
bool CheckAndScaleIcon(const std::string &src, const std::string &originDst, std::string &scaleDst);
private:
bool ParseContext(const cJSON *contextNode);
bool ParseCompression(const cJSON *compressionNode);
@@ -77,6 +85,7 @@ private:
bool SetTranscodeOptions(const std::string &optionJson, const std::string &optionJsonExclude);
TranscodeError TranscodeImages(const std::string &imagePath, const bool extAppend,
std::string &outputPath, TranscodeResult &result);
TranscodeError ScaleImage(const std::string &imagePath, std::string &outputPath);
std::vector<std::string> ParsePath(const cJSON *pathNode);
std::string ParseRules(const cJSON *rulesNode);
std::string ParseJsonStr(const cJSON *node);
+1
View File
@@ -53,6 +53,7 @@ public:
const FilePath &GetFilePath() const;
static bool Exist(const std::string &path);
static bool RemoveAllDir(const std::string &path);
static bool RemoveFile(const std::string &path);
static bool CreateDirs(const std::string &path);
static bool CopyFileInner(const std::string &src, const std::string &dst);
static bool IsDirectory(const std::string &path);
+2
View File
@@ -36,11 +36,13 @@ public:
moduleName_ = moduleName;
};
uint32_t MergeResourceItem(const std::map<int64_t, std::vector<ResourceItem>> &resourceInfos);
bool ScaleIcons(const std::string &output, const std::map<std::string, std::set<uint32_t>> &iconMap);
private:
uint32_t ScanModule(const std::string &input, const std::string &output);
uint32_t ParseReference(const std::string &output);
void CheckAllItems(std::vector<std::pair<ResType, std::string>> &noBaseResource);
bool ScaleIcon(const std::string &output, ResourceItem &item);
// id, resource items
std::map<int64_t, std::vector<ResourceItem>> items_;
+5
View File
@@ -18,6 +18,7 @@
#include <cJSON.h>
#include "id_worker.h"
#include "resource_data.h"
#include "resource_item.h"
namespace OHOS {
@@ -31,6 +32,7 @@ public:
uint32_t ParseRefInResourceItem(ResourceItem &resourceItem) const;
uint32_t ParseRefInJsonFile(ResourceItem &resourceItem, const std::string &output, const bool isIncrement = false);
uint32_t ParseRefInString(std::string &value, bool &update) const;
static std::map<int64_t, std::set<int64_t>> &GetLayerIconIds();
private:
bool ParseRefJson(const std::string &from, const std::string &to);
bool ParseRefResourceItemData(const ResourceItem &resourceItem, std::string &data, bool &update) const;
@@ -46,7 +48,10 @@ private:
const IdWorker &idWorker_;
static const std::map<std::string, ResType> ID_REFS;
static const std::map<std::string, ResType> ID_OHOS_REFS;
static std::map<int64_t, std::set<int64_t>> layerIconIds_;
cJSON *root_;
bool isParsingMediaJson_;
int64_t mediaJsonId_{ INVALID_ID };
};
}
}
+2 -1
View File
@@ -49,10 +49,11 @@ const static std::string SOLUTIONS_ARROW = "> ";
const static std::string LONG_PATH_HEAD = "\\\\?\\";
const static int32_t VERSION_MAX_LEN = 128;
const static int32_t INT_TO_BYTES = sizeof(uint32_t);
static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 5.011" };
static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 5.012" };
const static int32_t TAG_LEN = 4;
static std::set<std::string> g_resourceSet;
const static int8_t THREAD_POOL_SIZE = 2;
const static int8_t INVALID_ID = -1;
enum class KeyType {
LANGUAGE = 0,
+7
View File
@@ -56,6 +56,13 @@ public:
*/
static bool RmoveAllDir(const std::string &path);
/**
* @brief remove file.
* @param path: input file.
* @return true if remove success, other false.
*/
static bool RmoveFile(const std::string &path);
/**
* @brief open json file.
* @param path: json file path.
+77 -10
View File
@@ -95,6 +95,14 @@ uint32_t CompressionParser::Init()
cerr << "Error: JSON file parsing failed, please check the JSON file." << NEW_LINE_PATH << filePath_ << endl;
return RESTOOL_ERROR;
}
cJSON *contextNode = cJSON_GetObjectItem(root_, "context");
if (!ParseContext(contextNode)) {
cerr << NEW_LINE_PATH << filePath_ << endl;
return RESTOOL_ERROR;
}
if (!LoadImageTranscoder()) {
return RESTOOL_ERROR;
}
cJSON *compressionNode = cJSON_GetObjectItem(root_, "compression");
if (!ParseCompression(compressionNode)) {
return RESTOOL_ERROR;
@@ -102,15 +110,11 @@ uint32_t CompressionParser::Init()
if (!mediaSwitch_) {
return RESTOOL_SUCCESS;
}
cJSON *contextNode = cJSON_GetObjectItem(root_, "context");
cJSON *filtersNode = cJSON_GetObjectItem(compressionNode, "filters");
if (!ParseContext(contextNode) || !ParseFilters(filtersNode)) {
if (!ParseFilters(filtersNode)) {
cerr << NEW_LINE_PATH << filePath_ << endl;
return RESTOOL_ERROR;
}
if (!LoadImageTranscoder()) {
return RESTOOL_ERROR;
}
string caches = outPath_;
caches.append(SEPARATOR_FILE).append(CACHES_DIR);
if (!ResourceUtil::CreateDirs(caches)) {
@@ -375,6 +379,35 @@ TranscodeError CompressionParser::TranscodeImages(const string &imagePath, const
return TranscodeError::SUCCESS;
}
TranscodeError CompressionParser::ScaleImage(const std::string &imagePath, std::string &outputPath)
{
if (!handle_) {
cout << "Warning: ScaleImage handle_ is nullptr." << endl;
return TranscodeError::LOAD_COMPRESS_FAILED;
}
#ifdef __WIN32
IScaleImage iScaleImage = (IScaleImage)GetProcAddress(handle_, "TranscodeSLR");
#else
IScaleImage iScaleImage = (IScaleImage)dlsym(handle_, "TranscodeSLR");
#endif
if (!iScaleImage) {
cout << "Warning: Failed to get the 'TranscodeSLR'." << endl;
return TranscodeError::LOAD_COMPRESS_FAILED;
}
TranscodeError ret = (*iScaleImage)(imagePath, outputPath, { 512, 512 });
if (ret != TranscodeError::SUCCESS) {
auto iter = ERRORCODEMAP.find(ret);
if (iter != ERRORCODEMAP.end()) {
cout << "Warning: ScaleImage failed, error message: " << iter->second << ", file path = " << imagePath
<< endl;
} else {
cout << "Warning: ScaleImage failed" << ", file path = " << imagePath << endl;
}
return ret;
}
return TranscodeError::SUCCESS;
}
bool CompressionParser::CheckPath(const string &src, const vector<string> &paths)
{
if (paths.size() == 1 && paths[0] == "true") {
@@ -519,14 +552,14 @@ bool CompressionParser::CheckAndTranscode(const string &src, string &dst, string
bool CompressionParser::CopyForTrans(const string &src, const string &originDst, const string &dst)
{
string srcSuffix;
string dstSuffix;
auto srcIndex = src.find_last_of(".");
auto dstIndex = dst.find_last_of(".");
if (srcIndex == string::npos || dstIndex == string::npos) {
cerr << "Error: invalid copy path." << endl;
return false;
if (srcIndex != string::npos && dstIndex != string::npos) {
srcSuffix = src.substr(srcIndex + 1);
dstSuffix = dst.substr(dstIndex + 1);
}
string srcSuffix = src.substr(srcIndex + 1);
string dstSuffix = dst.substr(dstIndex + 1);
auto ret = false;
if (srcSuffix == dstSuffix) {
ret = ResourceUtil::CopyFileInner(src, dst);
@@ -571,6 +604,40 @@ bool CompressionParser::CopyAndTranscode(const string &src, string &dst, const b
CollectTime(totalCounts_, totalTime_, t2);
return ret;
}
bool CompressionParser::CheckAndScaleIcon(const std::string &src, const std::string &originDst, std::string &scaleDst)
{
scaleDst = src;
if (filePath_.empty() || outPath_.empty()) {
cout << "Info: compression path or out path is empty, unable to scale icon." << endl;
return true;
}
auto index = originDst.find_last_of(SEPARATOR_FILE);
if (index == string::npos) {
cerr << "Error: invalid output path." << NEW_LINE_PATH << originDst << endl;
return false;
}
uint32_t startIndex = outPath_.size() + RESOURCES_DIR.size() + 1;
string qualifierDir = originDst.substr(startIndex, index - startIndex);
string outputCache = outPath_ + SEPARATOR_FILE + CACHES_DIR + qualifierDir;
if (!ResourceUtil::CreateDirs(outputCache)) {
cerr << "Error: scale icon create output dir failed. dir = " << outputCache << endl;
return false;
}
string fileName = originDst.substr(index + 1);
string outputFile = outputCache + SEPARATOR_FILE + fileName;
auto ret = ScaleImage(src, outputFile);
if (ret == TranscodeError::SUCCESS) {
// if scale success, change src file to scale image
scaleDst = outputFile;
}
return true;
}
bool CompressionParser::ScaleIconEnable()
{
return !filePath_.empty() && !outPath_.empty() && handle_ != nullptr;
}
}
}
}
+5
View File
@@ -424,6 +424,11 @@ void ConfigParser::AddCheckNode(const string &key, uint32_t id)
} else {
result->second.emplace(id);
}
auto layerIconIds = ReferenceParser::GetLayerIconIds();
if (layerIconIds.find(id) != layerIconIds.end()) {
auto ids = layerIconIds[id];
jsonCheckIds_[key].insert(ids.begin(), ids.end());
}
}
}
+9
View File
@@ -137,6 +137,15 @@ bool FileEntry::RemoveAllDir(const string &path)
return RemoveAllDirInner(f);
}
bool FileEntry::RemoveFile(const string &path)
{
FileEntry f(path);
if (!f.Init()) {
return false;
}
return RemoveAllDirInner(f);
}
bool FileEntry::CreateDirs(const string &path)
{
return CreateDirsInner(path, 0);
+80
View File
@@ -15,6 +15,7 @@
#include "file_manager.h"
#include <algorithm>
#include "compression_parser.h"
#include <iostream>
#include "factory_resource_compiler.h"
#include "file_entry.h"
@@ -87,6 +88,85 @@ void FileManager::CheckAllItems(vector<pair<ResType, string>> &noBaseResource)
}
}
}
bool FileManager::ScaleIcons(const string &output, const std::map<std::string, std::set<uint32_t>> &iconMap)
{
if (!CompressionParser::GetCompressionParser()->ScaleIconEnable()) {
cout << "Info: scale icon is not enable." << endl;
return true;
}
std::set<int64_t> allIconIds;
for (auto &it : iconMap) {
if (it.first != "icon") {
continue;
}
allIconIds.insert(it.second.begin(), it.second.end());
}
if (allIconIds.size() == 0) {
cout << "Info: no icons need to scale, icon ids size is 0." << endl;
return true;
}
for (auto &id : allIconIds) {
std::map<int64_t, std::vector<ResourceItem>>::iterator iter = items_.find(id);
if (iter == items_.end()) {
continue;
}
for (auto &item : iter->second) {
if (!ScaleIcon(output, item)) {
return false;
}
}
}
return true;
}
bool FileManager::ScaleIcon(const string &output, ResourceItem &item)
{
std::string media = "media";
// item's data is short path for icon file, such as "entry/resources/base/media/app_icon.png"
const string currentData(reinterpret_cast<const char *>(item.GetData()), item.GetDataLength());
auto outIndex = currentData.find_last_of(SEPARATOR);
if (outIndex == string::npos) {
cerr << "Error: ScaleIcon invalid output name: " << currentData << endl;
return false;
}
// get current output file name and full path
string fileName = currentData.substr(outIndex + 1);
FileEntry::FilePath fullFilePath = FileEntry::FilePath(output).Append(RESOURCES_DIR).Append(item.GetLimitKey())
.Append(media).Append(fileName);
if (fullFilePath.GetExtension() == JSON_EXTENSION) {
cout << "Info: can't scale media json file." << endl;
return true;
}
const string fullOutPath = fullFilePath.GetPath();
// delete current output file
if (!ResourceUtil::RmoveFile(fullOutPath)) {
cout << "Error: ScaleIcon RmoveFile failed: " << fullOutPath << endl;
return false;
}
// get origin icon output full path with the origin icon file name in src
std::string dst = FileEntry::FilePath(output).Append(RESOURCES_DIR).Append(item.GetLimitKey()).Append(media)
.Append(item.GetName()).GetPath();
// the origin full file in src
std::string scaleDst = item.GetFilePath();
// scale icon
if (!CompressionParser::GetCompressionParser()->CheckAndScaleIcon(item.GetFilePath(), dst, scaleDst)) {
return false;
}
// compress scaled icon
if (!CompressionParser::GetCompressionParser()->CopyAndTranscode(scaleDst, dst)) {
return false;
}
string newFileName = FileEntry::FilePath(dst).GetFilename();
std::string newData = moduleName_ + SEPARATOR + RESOURCES_DIR + SEPARATOR + item.GetLimitKey() + SEPARATOR + media
+ SEPARATOR + newFileName;
if (!item.SetData(reinterpret_cast<const int8_t *>(newData.c_str()), newData.length())) {
cerr << "Error: ScaleIcon resource item set data fail, data: " << newData << NEW_LINE_PATH
<< item.GetFilePath() << endl;
return false;
}
return true;
}
}
}
}
+29 -7
View File
@@ -53,7 +53,9 @@ const map<string, ResType> ReferenceParser::ID_OHOS_REFS = {
{ "^\\$ohos:symbol:", ResType::SYMBOL }
};
ReferenceParser::ReferenceParser() : idWorker_(IdWorker::GetInstance()), root_(nullptr)
std::map<int64_t, std::set<int64_t>> ReferenceParser::layerIconIds_;
ReferenceParser::ReferenceParser() : idWorker_(IdWorker::GetInstance()), root_(nullptr), isParsingMediaJson_(false)
{
}
@@ -113,14 +115,25 @@ uint32_t ReferenceParser::ParseRefInResourceItem(ResourceItem &resourceItem) con
uint32_t ReferenceParser::ParseRefInJsonFile(ResourceItem &resourceItem, const string &output, const bool isIncrement)
{
string jsonPath;
if (resourceItem.GetResType() == ResType::MEDIA) {
jsonPath = FileEntry::FilePath(output).Append(RESOURCES_DIR)
.Append(resourceItem.GetLimitKey()).Append("media").Append(resourceItem.GetName()).GetPath();
ResType resType = resourceItem.GetResType();
string resName = resourceItem.GetName();
if (resType == ResType::MEDIA) {
jsonPath = FileEntry::FilePath(output).Append(RESOURCES_DIR).Append(resourceItem.GetLimitKey()).Append("media")
.Append(resName).GetPath();
isParsingMediaJson_ = true;
mediaJsonId_ = idWorker_.GetId(resType, ResourceUtil::GetIdName(resName, resType));
if (mediaJsonId_ != INVALID_ID) {
set<int64_t> set;
layerIconIds_[mediaJsonId_] = set;
}
} else {
jsonPath = FileEntry::FilePath(output).Append(RESOURCES_DIR)
.Append("base").Append("profile").Append(resourceItem.GetName()).GetPath();
jsonPath = FileEntry::FilePath(output).Append(RESOURCES_DIR).Append("base").Append("profile").Append(resName)
.GetPath();
}
if (!ParseRefJson(resourceItem.GetFilePath(), jsonPath)) {
bool parseJsonRet = ParseRefJson(resourceItem.GetFilePath(), jsonPath);
isParsingMediaJson_ = false;
mediaJsonId_ = INVALID_ID;
if (!parseJsonRet) {
return RESTOOL_ERROR;
}
@@ -274,6 +287,10 @@ bool ReferenceParser::ParseRefImpl(string &key, const map<string, ResType> &refs
if (regex_search(key, result, regex(ref.first))) {
string name = key.substr(result[0].str().length());
int64_t id = idWorker_.GetId(ref.second, name);
if (!isSystem && ref.second == ResType::MEDIA && mediaJsonId_ != 0
&& layerIconIds_.find(mediaJsonId_) != layerIconIds_.end()) {
layerIconIds_[mediaJsonId_].insert(id);
}
if (isSystem) {
id = idWorker_.GetSystemId(ref.second, name);
}
@@ -314,6 +331,11 @@ bool ReferenceParser::ParseRefJsonImpl(cJSON *node, bool &needSave) const
}
return true;
}
std::map<int64_t, std::set<int64_t>> &ReferenceParser::GetLayerIconIds()
{
return layerIconIds_;
}
}
}
}
+4
View File
@@ -308,6 +308,10 @@ uint32_t ResourcePack::PackNormal()
return RESTOOL_ERROR;
}
if (!FileManager::GetInstance().ScaleIcons(packageParser_.GetOutput(), configJson_.GetCheckNode())) {
return RESTOOL_ERROR;
}
if (packageParser_.GetIconCheck()) {
CheckConfigJson();
}
+5
View File
@@ -73,6 +73,11 @@ bool ResourceUtil::RmoveAllDir(const string &path)
return FileEntry::RemoveAllDir(path);
}
bool ResourceUtil::RmoveFile(const string &path)
{
return FileEntry::RemoveFile(path);
}
bool ResourceUtil::OpenJsonFile(const string &path, cJSON **root)
{
ifstream ifs(FileEntry::AdaptLongPath(path), ios::binary);