обновление build.sh
This commit is contained in:
@@ -7,10 +7,12 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdio>
|
||||||
#include <opencv2/opencv.hpp>
|
#include <opencv2/opencv.hpp>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libs/argparse.h>
|
#include "libs/argparse.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
@@ -25,21 +27,27 @@ double getColorDistance(const ColorInfo& c1, const ColorInfo& c2) {
|
|||||||
return std::sqrt(std::pow(c1.r - c2.r, 2) + std::pow(c1.g - c2.g, 2) + std::pow(c1.b - c2.b, 2));
|
return std::sqrt(std::pow(c1.r - c2.r, 2) + std::pow(c1.g - c2.g, 2) + std::pow(c1.b - c2.b, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void extract_color_palette(const std::string& image_path, int num_colors = 6) {
|
void extract_color_palette(const std::string& image_path, int num_colors, const std::string& output_path) {
|
||||||
cv::Mat image = cv::imread(image_path);
|
if (num_colors < 3) {
|
||||||
|
std::cerr << "ошибка: для генерации палитры нужно минимум 3 цвета" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat image = cv::imread(image_path);
|
||||||
if (image.empty()) {
|
if (image.empty()) {
|
||||||
std::cerr << "ошибка: невозможно прочитать картинку" << std::endl;
|
std::cerr << "ошибка: невозможно прочитать картинку по пути " << image_path << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Mat data;
|
cv::Mat data;
|
||||||
image.convertTo(data, CV_32F);
|
image.convertTo(data, CV_32F);
|
||||||
data = data.reshape(1, data.total());
|
|
||||||
|
data = data.reshape(3, data.total());
|
||||||
|
|
||||||
cv::Mat labels;
|
cv::Mat labels;
|
||||||
cv::Mat centers;
|
cv::Mat centers;
|
||||||
cv::TermCriteria criteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 10, 1.0);
|
cv::TermCriteria criteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 100, 1.0);
|
||||||
|
|
||||||
cv::kmeans(data, num_colors, labels, criteria, 3, cv::KMEANS_PP_CENTERS, centers);
|
cv::kmeans(data, num_colors, labels, criteria, 3, cv::KMEANS_PP_CENTERS, centers);
|
||||||
|
|
||||||
std::vector<ColorInfo> colors;
|
std::vector<ColorInfo> colors;
|
||||||
@@ -52,11 +60,9 @@ void extract_color_palette(const std::string& image_path, int num_colors = 6) {
|
|||||||
c.r = static_cast<int>(centers.at<float>(i, 2));
|
c.r = static_cast<int>(centers.at<float>(i, 2));
|
||||||
c.brightness = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
|
c.brightness = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
|
||||||
|
|
||||||
std::stringstream ss;
|
char hex_str[8];
|
||||||
ss << "#" << std::setfill('0') << std::setw(2) << std::hex << c.r
|
snprintf(hex_str, sizeof(hex_str), "#%02x%02x%02x", c.r, c.g, c.b);
|
||||||
<< std::setfill('0') << std::setw(2) << std::hex << c.g
|
c.hex = hex_str;
|
||||||
<< std::setfill('0') << std::setw(2) << std::hex << c.b;
|
|
||||||
c.hex = ss.str();
|
|
||||||
colors.push_back(c);
|
colors.push_back(c);
|
||||||
|
|
||||||
cv::Mat bgr_pixel(1, 1, CV_8UC3, cv::Scalar(c.b, c.g, c.r));
|
cv::Mat bgr_pixel(1, 1, CV_8UC3, cv::Scalar(c.b, c.g, c.r));
|
||||||
@@ -67,7 +73,6 @@ void extract_color_palette(const std::string& image_path, int num_colors = 6) {
|
|||||||
|
|
||||||
hsv[1] = std::min(static_cast<int>(hsv[1]), 60);
|
hsv[1] = std::min(static_cast<int>(hsv[1]), 60);
|
||||||
if (hsv[1] < 30) hsv[1] = 40;
|
if (hsv[1] < 30) hsv[1] = 40;
|
||||||
|
|
||||||
hsv[2] = std::max(static_cast<int>(hsv[2]), 230);
|
hsv[2] = std::max(static_cast<int>(hsv[2]), 230);
|
||||||
|
|
||||||
cv::Mat pastel_bgr;
|
cv::Mat pastel_bgr;
|
||||||
@@ -78,11 +83,9 @@ void extract_color_palette(const std::string& image_path, int num_colors = 6) {
|
|||||||
pc.b = pbgr[0]; pc.g = pbgr[1]; pc.r = pbgr[2];
|
pc.b = pbgr[0]; pc.g = pbgr[1]; pc.r = pbgr[2];
|
||||||
pc.brightness = 0.299 * pc.r + 0.587 * pc.g + 0.114 * pc.b;
|
pc.brightness = 0.299 * pc.r + 0.587 * pc.g + 0.114 * pc.b;
|
||||||
|
|
||||||
std::stringstream ss_pastel;
|
char hex_str_pas[8];
|
||||||
ss_pastel << "#" << std::setfill('0') << std::setw(2) << std::hex << pc.r
|
snprintf(hex_str_pas, sizeof(hex_str_pas), "#%02x%02x%02x", pc.r, pc.g, pc.b);
|
||||||
<< std::setfill('0') << std::setw(2) << std::hex << pc.g
|
pc.hex = hex_str_pas;
|
||||||
<< std::setfill('0') << std::setw(2) << std::hex << pc.b;
|
|
||||||
pc.hex = ss_pastel.str();
|
|
||||||
pastel_colors.push_back(pc);
|
pastel_colors.push_back(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,53 +140,28 @@ void extract_color_palette(const std::string& image_path, int num_colors = 6) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ofstream file_dark("palette_dark");
|
fs::path out_dir(output_path);
|
||||||
if (file_dark.is_open()) {
|
|
||||||
file_dark << bg_color.hex << "\n"
|
|
||||||
<< bg_sub.hex << "\n"
|
|
||||||
<< accent_color.hex << "\n"
|
|
||||||
<< fg_sub_color.hex << "\n"
|
|
||||||
<< fg_color.hex << "\n";
|
|
||||||
file_dark.close();
|
|
||||||
std::cout << "успешно сформирована темная палитра" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ofstream file_light("palette_light");
|
auto write_palette = [&](const std::string& filename, const std::vector<ColorInfo>& palette) {
|
||||||
if (file_light.is_open()) {
|
std::ofstream file(out_dir / filename);
|
||||||
file_light << fg_color.hex << "\n"
|
if (file.is_open()) {
|
||||||
<< fg_sub_color.hex << "\n"
|
for (const auto& color : palette) {
|
||||||
<< accent_color.hex << "\n"
|
file << color.hex << "\n";
|
||||||
<< bg_sub.hex << "\n"
|
}
|
||||||
<< bg_color.hex << "\n";
|
file.close();
|
||||||
file_light.close();
|
std::cout << "успешно сформирована палитра: " << filename << std::endl;
|
||||||
std::cout << "успешно сформирована светлая палитра" << std::endl;
|
} else {
|
||||||
}
|
std::cerr << "ошибка: не удалось создать файл " << filename << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::ofstream file_pastel_dark("palette_pastel_dark");
|
write_palette("palette_dark", {bg_color, bg_sub, accent_color, fg_sub_color, fg_color});
|
||||||
if (file_pastel_dark.is_open()) {
|
write_palette("palette_light", {fg_color, fg_sub_color, accent_color, bg_sub, bg_color});
|
||||||
file_pastel_dark << pas_bg_color.hex << "\n"
|
write_palette("palette_pastel_dark", {pas_bg_color, pas_bg_sub, pas_accent_color, pas_fg_sub_color, pas_fg_color});
|
||||||
<< pas_bg_sub.hex << "\n"
|
write_palette("palette_pastel_light", {pas_fg_color, pas_fg_sub_color, pas_accent_color, pas_bg_sub, pas_bg_color});
|
||||||
<< pas_accent_color.hex << "\n"
|
|
||||||
<< pas_fg_sub_color.hex << "\n"
|
|
||||||
<< pas_fg_color.hex << "\n";
|
|
||||||
file_pastel_dark.close();
|
|
||||||
std::cout << "успешно сформирована пастельная палитра" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ofstream file_pastel_link("palette_pastel_light");
|
|
||||||
if (file_pastel_link.is_open()) {
|
|
||||||
file_pastel_link << pas_fg_color.hex << "\n"
|
|
||||||
<< pas_fg_sub_color.hex << "\n"
|
|
||||||
<< pas_accent_color.hex << "\n"
|
|
||||||
<< pas_bg_sub.hex << "\n"
|
|
||||||
<< pas_bg_color.hex << "\n";
|
|
||||||
file_pastel_link.close();
|
|
||||||
std::cout << "успешно сформирована пастельная палитра" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int download_wall(const char* link, const char* path) {
|
||||||
int download_wall(const char* link, const char* path){
|
|
||||||
CURL* curl;
|
CURL* curl;
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
CURLcode res;
|
CURLcode res;
|
||||||
@@ -193,52 +171,50 @@ int download_wall(const char* link, const char* path){
|
|||||||
|
|
||||||
if(curl) {
|
if(curl) {
|
||||||
fp = fopen(path, "wb");
|
fp = fopen(path, "wb");
|
||||||
|
|
||||||
if(fp == NULL) {
|
if(fp == NULL) {
|
||||||
fprintf(stderr, \
|
fprintf(stderr, "ошибка: не удалось создать или открыть файл %s\n", path);
|
||||||
"ошибка: не удалось создать или открыть файл %s\n", path);
|
|
||||||
|
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, link);
|
curl_easy_setopt(curl, CURLOPT_URL, link);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) WallpaperPaletteBot/1.0");
|
||||||
|
|
||||||
res = curl_easy_perform(curl);
|
res = curl_easy_perform(curl);
|
||||||
|
|
||||||
if(res != CURLE_OK) {
|
|
||||||
fprintf(stderr, "ошибка скачивания: %s\n", \
|
|
||||||
curl_easy_strerror(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
if(res != CURLE_OK) {
|
||||||
|
fprintf(stderr, "ошибка скачивания: %s\n", curl_easy_strerror(res));
|
||||||
|
curl_global_cleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
curl_global_cleanup();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
int main(int argc, const char **argv) {
|
||||||
|
|
||||||
const char* link = nullptr;
|
const char* link = nullptr;
|
||||||
const char* raw_scheme_path = nullptr;
|
const char* raw_scheme_path = nullptr;
|
||||||
const char* raw_wall_path = nullptr;
|
const char* raw_wall_path = nullptr;
|
||||||
|
const char* raw_path_to_local = nullptr;
|
||||||
|
|
||||||
struct argparse_option options[] = {
|
struct argparse_option options[] = {
|
||||||
OPT_HELP(),
|
OPT_HELP(),
|
||||||
OPT_STRING(0,"link", &link, \
|
OPT_STRING(0, "link", &link, "ссылка на изображение с сайта wallhave.cc", NULL, 0, 0),
|
||||||
"ссылка на изображение с сайта wallhave.cc", NULL, 0, 0),
|
OPT_STRING(0, "local", &raw_path_to_local, "путь до локального файла с обоями", NULL, 0, 0),
|
||||||
OPT_STRING(0,"scheme-output", &raw_scheme_path,\
|
OPT_STRING(0, "scheme-output", &raw_scheme_path, "директория для сохранения палитр", NULL, 0, 0),
|
||||||
"директория для сохранения палитр", NULL, 0, 0),
|
OPT_STRING(0, "wall-output", &raw_wall_path, "директория для сохранения обоев", NULL, 0, 0),
|
||||||
OPT_STRING(0,"wall-output", &raw_wall_path, \
|
|
||||||
"директория для сохранения обоев", NULL, 0, 0),
|
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -246,27 +222,71 @@ int main(int argc, const char **argv) {
|
|||||||
argparse_init(&argparse, options, nullptr, 0);
|
argparse_init(&argparse, options, nullptr, 0);
|
||||||
argc = argparse_parse(&argparse, argc, argv);
|
argc = argparse_parse(&argparse, argc, argv);
|
||||||
|
|
||||||
fs::path target_dir;
|
if (link == nullptr && raw_path_to_local == nullptr) {
|
||||||
|
std::cerr << "ошибка: необходимо указать либо --link, либо --local" << std::endl;
|
||||||
if (raw_wall_path == nullptr || std::string(raw_wall_path).empty()){
|
return 1;
|
||||||
target_dir = fs::current_path();
|
|
||||||
}
|
}
|
||||||
else{
|
if (link != nullptr && raw_path_to_local != nullptr) {
|
||||||
std::string path_str(raw_wall_path);
|
std::cerr << "ошибка: нельзя указать одновременно --link и --local. Выберите что-то одно." << std::endl;
|
||||||
if (path_str[0] == '~'){
|
return 1;
|
||||||
const char* user_home = std::getenv("HOME");
|
}
|
||||||
if (user_home){
|
|
||||||
path_str.replace(0, 1, user_home);
|
auto resolve_dir = [](const char* raw_path) -> fs::path {
|
||||||
}
|
if (raw_path == nullptr || std::string(raw_path).empty()) {
|
||||||
|
return fs::current_path();
|
||||||
}
|
}
|
||||||
target_dir = fs::path(path_str);
|
std::string path_str(raw_path);
|
||||||
|
if (path_str[0] == '~') {
|
||||||
|
const char* user_home = std::getenv("HOME");
|
||||||
|
if (user_home) path_str.replace(0, 1, user_home);
|
||||||
|
}
|
||||||
|
return fs::path(path_str);
|
||||||
|
};
|
||||||
|
|
||||||
|
fs::path target_dir_wall = resolve_dir(raw_wall_path);
|
||||||
|
if (!fs::exists(target_dir_wall)) {
|
||||||
|
fs::create_directories(target_dir_wall);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string full_path_str(target_dir / "wallpaper.jpg");
|
fs::path target_dir_scheme = resolve_dir(raw_scheme_path);
|
||||||
const char* full_path = full_path_str.c_str();
|
if (!fs::exists(target_dir_scheme)) {
|
||||||
|
fs::create_directories(target_dir_scheme);
|
||||||
|
}
|
||||||
|
|
||||||
download_wall(link, full_path);
|
std::string final_image_path;
|
||||||
extract_color_palette(full_path, 6);
|
|
||||||
|
if (raw_path_to_local != nullptr) {
|
||||||
|
std::string local_str(raw_path_to_local);
|
||||||
|
|
||||||
|
if (local_str[0] == '~') {
|
||||||
|
const char* user_home = std::getenv("HOME");
|
||||||
|
if (user_home) local_str.replace(0, 1, user_home);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path local_file(local_str);
|
||||||
|
|
||||||
|
if (!fs::exists(local_file)) {
|
||||||
|
std::cerr << "ошибка: локальный файл не найден по пути " << local_file << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final_image_path = local_file.string();
|
||||||
|
std::cout << "используется локальный файл: " << final_image_path << std::endl;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
std::string full_wall_path = (target_dir_wall / "wallpaper.jpg").string();
|
||||||
|
|
||||||
|
std::cout << "скачивание изображения..." << std::endl;
|
||||||
|
if (download_wall(link, full_wall_path.c_str()) != 0) {
|
||||||
|
std::cerr << "не удалось скачать изображение. завершение работы." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final_image_path = full_wall_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "извлечение палитры..." << std::endl;
|
||||||
|
extract_color_palette(final_image_path, 6, target_dir_scheme.string());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user