diff --git a/fix_colors.cpp b/fix_colors.cpp new file mode 100644 index 0000000..de54313 --- /dev/null +++ b/fix_colors.cpp @@ -0,0 +1,77 @@ +#include "fix_colors.hpp" + +#include +#include + +#define ALPHA_THRESHOLD 127 + +struct Coord { + int x, y; +}; + +static ColorRGB FindClosestOpaque(const Image& image, size_t x, size_t y, const std::vector& kernel) { + for (const Coord& c : kernel) { + int cx = x + c.x; + int cy = y + c.y; + + if (cx < 0 || cx >= image.GetWidth() || cy < 0 || cy >= image.GetHeight()) { + continue; + } + + const ColorRGBA& pixel = image.At(cx, cy); + + if (pixel.a >= ALPHA_THRESHOLD) { + return pixel.rgb; + } + } + + return { 255, 0, 0 }; +} + + +void FixColors::Fix(const Image& src, Image& dst, float max_dist) { + + std::vector kernel; + for (int y = -max_dist; y <= max_dist; y++) { + for (int x = -max_dist; x <= max_dist; x++) { + kernel.push_back({ x, y }); + } + } + + //kernel.erase(std::remove_if(kernel.begin(), kernel.end(), [max_dist](const Coord& c) { + // return c.x * c.x + c.y * c.y > max_dist * max_dist; + //}), kernel.end()); + + std::sort(kernel.begin(), kernel.end(), [](const Coord& a, const Coord& b) { + return a.x * a.x + a.y * a.y < b.x * b.x + b.y * b.y; + }); + + for (size_t y = 0; y < src.GetHeight(); y++) { + for (size_t x = 0; x < src.GetWidth(); x++) { + const ColorRGBA& pixel_src = src.At(x, y); + ColorRGBA& pixel_dst = dst.At(x, y); + + pixel_dst.a = pixel_src.a; + + if (pixel_src.a < ALPHA_THRESHOLD) { + pixel_dst.rgb = FindClosestOpaque(src, x, y, kernel); + } + else { + pixel_dst.rgb = pixel_src.rgb; + } + //pixel_dst.a = 255; + } + } + + //size_t i = 0; + //for (const Coord& c : kernel) { + // ColorRGBA& pixel = image.At(c.x + 40, c.y + 40); + // + // uint8_t intensity = i * 255 / kernel.size(); + // + // pixel.rgb = { intensity, 0, 0 }; + // pixel.a = 255; + + // i++; + //} +} diff --git a/fix_colors.hpp b/fix_colors.hpp new file mode 100644 index 0000000..97d92bc --- /dev/null +++ b/fix_colors.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "image.hpp" + +class FixColors { + +public: + static void Fix(const Image& src, Image& dst, float max_dist); +}; diff --git a/image.cpp b/image.cpp new file mode 100644 index 0000000..9b4e911 --- /dev/null +++ b/image.cpp @@ -0,0 +1,44 @@ +#include "image.hpp" + +#include +#include +#include + +Image::Image(const std::string& path) { + int width, height, channels; + stbi_uc* data = stbi_load(path.c_str(), &width, &height, &channels, 4); + + if (!data) { + throw std::runtime_error("Failed to load image: " + path); + } + + m_width = width; + m_height = height; + m_data = std::make_unique(m_width * m_height); + + for (size_t y = 0; y < m_height; y++) { + for (size_t x = 0; x < m_width; x++) { + size_t idx_dst = y * m_width + x; + size_t idx_src = idx_dst * 4; + + ColorRGBA& pixel = m_data[idx_dst]; + + pixel.rgb.r = data[idx_src + 0]; + pixel.rgb.g = data[idx_src + 1]; + pixel.rgb.b = data[idx_src + 2]; + pixel.a = data[idx_src + 3]; + } + } + + stbi_image_free(data); +} + +Image::Image(size_t width, size_t height) { + m_width = width; + m_height = height; + m_data = std::make_unique(m_width * m_height); +} + +void Image::Save(const std::string& path) const { + stbi_write_png(path.c_str(), m_width, m_height, 4, m_data.get(), m_width * 4); +} diff --git a/image.hpp b/image.hpp new file mode 100644 index 0000000..d6e8885 --- /dev/null +++ b/image.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include + +struct ColorRGB { + uint8_t r; + uint8_t g; + uint8_t b; +}; + +struct ColorRGBA { + ColorRGB rgb; + uint8_t a; +}; + +class Image { + size_t m_width; + size_t m_height; + + std::unique_ptr m_data; + +public: + Image(const std::string& path); + Image(size_t width, size_t height); + + size_t GetWidth() const { return m_width; } + size_t GetHeight() const { return m_height; } + + ColorRGBA& At(size_t x, size_t y) { + return m_data[y * m_width + x]; + } + + const ColorRGBA& At(size_t x, size_t y) const { + return m_data[y * m_width + x]; + } + + void Save(const std::string& path) const; + +}; \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..aa5fd08 --- /dev/null +++ b/main.cpp @@ -0,0 +1,30 @@ +// proctex.cpp : This file contains the 'main' function. Program execution begins and ends there. +// + +#include + +#include + +#include "image.hpp" +#include "fix_colors.hpp" + +int main() { + + Image input_img("image.png"); + Image output_img(input_img.GetWidth(), input_img.GetHeight()); + + FixColors::Fix(input_img, output_img, std::max(input_img.GetWidth(), input_img.GetHeight())); + + output_img.Save("fixed_image.png"); +} + +// Run program: Ctrl + F5 or Debug > Start Without Debugging menu +// Debug program: F5 or Debug > Start Debugging menu + +// Tips for Getting Started: +// 1. Use the Solution Explorer window to add/manage files +// 2. Use the Team Explorer window to connect to source control +// 3. Use the Output window to see build output and other messages +// 4. Use the Error List window to view errors +// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project +// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file diff --git a/texproc.sln b/texproc.sln new file mode 100644 index 0000000..c3ff95f --- /dev/null +++ b/texproc.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "texproc", "texproc.vcxproj", "{ED18FA33-5CF7-40FC-9C21-1B8D5C08C78E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ED18FA33-5CF7-40FC-9C21-1B8D5C08C78E}.Debug|x64.ActiveCfg = Debug|x64 + {ED18FA33-5CF7-40FC-9C21-1B8D5C08C78E}.Debug|x64.Build.0 = Debug|x64 + {ED18FA33-5CF7-40FC-9C21-1B8D5C08C78E}.Debug|x86.ActiveCfg = Debug|Win32 + {ED18FA33-5CF7-40FC-9C21-1B8D5C08C78E}.Debug|x86.Build.0 = Debug|Win32 + {ED18FA33-5CF7-40FC-9C21-1B8D5C08C78E}.Release|x64.ActiveCfg = Release|x64 + {ED18FA33-5CF7-40FC-9C21-1B8D5C08C78E}.Release|x64.Build.0 = Release|x64 + {ED18FA33-5CF7-40FC-9C21-1B8D5C08C78E}.Release|x86.ActiveCfg = Release|Win32 + {ED18FA33-5CF7-40FC-9C21-1B8D5C08C78E}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6D1C48F6-3834-4AAE-A82F-83CD137E839A} + EndGlobalSection +EndGlobal diff --git a/texproc.vcxproj b/texproc.vcxproj new file mode 100644 index 0000000..a5006aa --- /dev/null +++ b/texproc.vcxproj @@ -0,0 +1,144 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + 17.0 + Win32Proj + {ed18fa33-5cf7-40fc-9c21-1b8d5c08c78e} + texproc + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/texproc.vcxproj.filters b/texproc.vcxproj.filters new file mode 100644 index 0000000..5f77cd1 --- /dev/null +++ b/texproc.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file