diff --git a/MandelbrotDiscovery/MandelbrotDiscovery.vcxproj b/MandelbrotDiscovery/MandelbrotDiscovery.vcxproj
index 7830386..9b1e7ae 100644
--- a/MandelbrotDiscovery/MandelbrotDiscovery.vcxproj
+++ b/MandelbrotDiscovery/MandelbrotDiscovery.vcxproj
@@ -106,6 +106,7 @@
+
diff --git a/MandelbrotDiscovery/MandelbrotDiscovery.vcxproj.filters b/MandelbrotDiscovery/MandelbrotDiscovery.vcxproj.filters
index a923851..00b4073 100644
--- a/MandelbrotDiscovery/MandelbrotDiscovery.vcxproj.filters
+++ b/MandelbrotDiscovery/MandelbrotDiscovery.vcxproj.filters
@@ -19,6 +19,9 @@
MandelbrotDiscovery
+
+ MandelbrotDiscovery
+
diff --git a/MandelbrotDiscovery/geometry.h b/MandelbrotDiscovery/geometry.h
index dfc141a..2a3bd56 100644
--- a/MandelbrotDiscovery/geometry.h
+++ b/MandelbrotDiscovery/geometry.h
@@ -32,9 +32,23 @@
value_type my_y { };
};
+ struct rectangle_base
+ {
+ public:
+ static constexpr auto default_pixels() noexcept -> int { return 768; }
+
+ virtual ~rectangle_base() = default;
+
+ protected:
+ rectangle_base() = default;
+ };
+
template
- struct rectangle_type
+ struct rectangle_type : public rectangle_base
{
+ private:
+ using base_class_type = rectangle_base;
+
public:
using point_type = PointType;
using value_type = typename point_type::value_type;
@@ -48,6 +62,8 @@
rectangle_type() = delete;
+ ~rectangle_type() override = default;
+
auto operator*=(const int n) -> rectangle_type&
{
static_cast(my_dx_half *= n);
@@ -91,8 +107,7 @@
auto dx_half() const noexcept -> value_type { return my_dx_half; }
auto dy_half() const noexcept -> value_type { return my_dy_half; }
- auto center() const noexcept -> const point_type& { return my_center; }
- auto center() noexcept -> point_type& { return my_center; }
+ auto center() const noexcept -> const point_type { return my_center; }
auto recenter(const point_type& new_center) noexcept -> void
{
diff --git a/MandelbrotDiscovery/mandelbrot_discovery.cpp b/MandelbrotDiscovery/mandelbrot_discovery.cpp
index 5ef83e0..2c2c7d3 100644
--- a/MandelbrotDiscovery/mandelbrot_discovery.cpp
+++ b/MandelbrotDiscovery/mandelbrot_discovery.cpp
@@ -37,10 +37,10 @@ template auto center_y() -> typename local::cfg_type
using rectangle_from_digits_type = geometry::rectangle_type::mandelbrot_coord_pnt_type>>;
-constexpr inline auto default_00_digits10() -> unsigned { return unsigned { UINT32_C( 44) }; } // For magnification <= 20
-constexpr inline auto default_01_digits10() -> unsigned { return unsigned { UINT32_C( 64) }; } // For magnification <= 40
-constexpr inline auto default_02_digits10() -> unsigned { return unsigned { UINT32_C( 104) }; } // For magnification <= 80
-constexpr inline auto default_03_digits10() -> unsigned { return unsigned { UINT32_C(1560) }; } // For magnification <= 1536 (which we consider unlimited)
+constexpr inline auto default_00_digits10() noexcept -> unsigned { return unsigned { UINT32_C( 44) }; } // For magnification <= 20
+constexpr inline auto default_01_digits10() noexcept -> unsigned { return unsigned { UINT32_C( 64) }; } // For magnification <= 40
+constexpr inline auto default_02_digits10() noexcept -> unsigned { return unsigned { UINT32_C( 104) }; } // For magnification <= 80
+constexpr inline auto default_03_digits10() noexcept -> unsigned { return unsigned { UINT32_C(1560) }; } // For magnification <= 1536 (which we consider unlimited)
using rectangle_00_type = rectangle_from_digits_type;
using rectangle_01_type = rectangle_from_digits_type;
@@ -74,9 +74,11 @@ auto rectangle_00() -> rectangle_00_type&
dy_half()
};
- static const bool result_pixel_assoc_is_ok { my_rect.set_pixel_assoc(768, 768) };
+ {
+ static const bool result_pixel_assoc_is_ok { my_rect.set_pixel_assoc(geometry::rectangle_base::default_pixels(), geometry::rectangle_base::default_pixels()) };
- static_cast(result_pixel_assoc_is_ok);
+ static_cast(result_pixel_assoc_is_ok);
+ }
return my_rect;
}
@@ -90,9 +92,11 @@ auto rectangle_01() -> rectangle_01_type&
dy_half()
};
- static const bool result_pixel_assoc_is_ok { my_rect.set_pixel_assoc(768, 768) };
+ {
+ static const bool result_pixel_assoc_is_ok { my_rect.set_pixel_assoc(geometry::rectangle_base::default_pixels(), geometry::rectangle_base::default_pixels()) };
- static_cast(result_pixel_assoc_is_ok);
+ static_cast(result_pixel_assoc_is_ok);
+ }
return my_rect;
}
@@ -106,9 +110,11 @@ auto rectangle_02() -> rectangle_02_type&
dy_half()
};
- static const bool result_pixel_assoc_is_ok { my_rect.set_pixel_assoc(768, 768) };
+ {
+ static const bool result_pixel_assoc_is_ok { my_rect.set_pixel_assoc(geometry::rectangle_base::default_pixels(), geometry::rectangle_base::default_pixels()) };
- static_cast(result_pixel_assoc_is_ok);
+ static_cast(result_pixel_assoc_is_ok);
+ }
return my_rect;
}
@@ -122,9 +128,11 @@ auto rectangle_03() -> rectangle_03_type&
dy_half()
};
- static const bool result_pixel_assoc_is_ok { my_rect.set_pixel_assoc(768, 768) };
+ {
+ static const bool result_pixel_assoc_is_ok { my_rect.set_pixel_assoc(geometry::rectangle_base::default_pixels(), geometry::rectangle_base::default_pixels()) };
- static_cast(result_pixel_assoc_is_ok);
+ static_cast(result_pixel_assoc_is_ok);
+ }
return my_rect;
}
diff --git a/MandelbrotDiscovery/mandelbrot_discovery.h b/MandelbrotDiscovery/mandelbrot_discovery.h
index 48042bd..f7fc3c2 100644
--- a/MandelbrotDiscovery/mandelbrot_discovery.h
+++ b/MandelbrotDiscovery/mandelbrot_discovery.h
@@ -32,13 +32,18 @@
#include
#include
#include
+ #include
#include
#include
#include
+ extern auto mandelbrot_discovery_rescale() -> void;
+
namespace mandelbrot_discovery_detail
{
constexpr char WindowTitleDefault[] = "Mandelbrot Discovery";
+
+ constexpr inline auto default_pixels() noexcept -> int { return geometry::rectangle_base::default_pixels(); }
}
template;
- using value_tuple_type = std::tuple;
+ using point_tuple_type = std::tuple;
+ using value_tuple_type = std::tuple;
static constexpr int screen_coordinate_x = static_cast(ScreenCoordinateX); // Screen coordinate X
static constexpr int screen_coordinate_y = static_cast(ScreenCoordinateY); // Screen coordinate Y
@@ -261,9 +266,6 @@
if(result_alloc_console_is_ok)
{
static_cast(::FreeConsole());
-
- static_cast(::CloseHandle(console_input()));
- static_cast(::CloseHandle(console_output()));
}
return static_cast(INT8_C(0));
@@ -278,6 +280,7 @@
::HWND my_handle_to_window { nullptr };
::HINSTANCE my_handle_to_instance { nullptr };
+ static point_tuple_type my_rectangle_centers;
static rectangle_tuple_ref_type my_ref_to_rectangle_tuple;
static std::thread my_thread;
@@ -286,6 +289,7 @@
static std::atomic my_thread_wait_for_new_set_click;
static value_tuple_type my_mandelbrot_zoom_factor_tuple;
static std::uint_fast32_t my_mandelbrot_iterations;
+ static unsigned my_mandelbrot_frac2_denominator;
static constexpr auto window_title() noexcept -> const char* { return WindowTitle; }
static constexpr auto icon_id () noexcept -> int { return IconId; }
@@ -335,12 +339,13 @@
stopwatch_type my_stopwatch { };
- // Generate the Mandelbrot image. Note: The filename suffix
- // will be provided by the interface.
+ // Generate the Mandelbrot image.
ckormanyos::mandelbrot::color::color_stretch_histogram_method local_color_stretches;
const ckormanyos::mandelbrot::color::color_functions_bw local_color_functions;
+ // Note: The filename suffix of the JPEG/PNG will be provided by the interface.
+
mandelbrot_generator.generate_mandelbrot_image("mandelbrot_zooming",
local_color_functions,
local_color_stretches,
@@ -361,16 +366,20 @@
}()
};
+ // Rescale the JPEG/PNG files.
+ ::mandelbrot_discovery_rescale();
+
write_string("mandelbrot_zoom: " + std::to_string(zoom_factor_p10()) + "\n");
write_string("mandelbrot_iter: " + std::to_string(my_mandelbrot_iterations) + "\n");
write_string("iteration_time : " + str_iteration_time + "s\n\n");
}
- template
+ template
static auto mandelbrot_iterate_engine() -> void
{
- constexpr auto MANDELBROT_CALCULATION_PIXELS_X = static_cast(768);
- constexpr auto MANDELBROT_CALCULATION_PIXELS_Y = static_cast(768);
+ constexpr auto MANDELBROT_CALCULATION_PIXELS_X = static_cast(unsigned { mandelbrot_discovery_detail::default_pixels() } / ResFrac2Denominator);
+ constexpr auto MANDELBROT_CALCULATION_PIXELS_Y = static_cast(unsigned { mandelbrot_discovery_detail::default_pixels() } / ResFrac2Denominator);
using local_value_type = std::tuple_element_t;
@@ -404,18 +413,6 @@
mandelbrot_iterate_engine_worker(gen);
}
- template
- static auto write_coords() -> bool
- {
- bool result_write_coords_is_ok { true };
-
- result_write_coords_is_ok = (write_number("x_val : ", std::get<0x00>(my_ref_to_rectangle_tuple.get()).center().get_x()) && result_write_coords_is_ok);
- result_write_coords_is_ok = (write_number("y_val : ", std::get<0x00>(my_ref_to_rectangle_tuple.get()).center().get_y()) && result_write_coords_is_ok);
- result_write_coords_is_ok = (write_number("dx_half: ", std::get<0x00>(my_ref_to_rectangle_tuple.get()).dx_half(), 3) && result_write_coords_is_ok);
-
- return result_write_coords_is_ok;
- }
-
static auto CALLBACK my_window_callback(::HWND handle_to_window,
::UINT message,
::WPARAM w_param,
@@ -435,7 +432,7 @@
load_jpeg_image
(
(std::get<0x00>(my_mandelbrot_zoom_factor_tuple) > 1) ? L"mandelbrot_zooming.jpg"
- : L"mandelbrot_MANDELBROT_01_FULL.jpg"
+ : L"mandelbrot_MANDELBROT_01_FULL.jpg"
)
};
@@ -508,19 +505,42 @@
bool result_is_ok { true };
- result_is_ok = { std::get<0x00>(my_ref_to_rectangle_tuple.get()).pixel_to_point(pixel_x, pixel_y, std::get<0x00>(my_ref_to_rectangle_tuple.get()).center()) && result_is_ok };
- result_is_ok = { std::get<0x01>(my_ref_to_rectangle_tuple.get()).pixel_to_point(pixel_x, pixel_y, std::get<0x01>(my_ref_to_rectangle_tuple.get()).center()) && result_is_ok };
- result_is_ok = { std::get<0x02>(my_ref_to_rectangle_tuple.get()).pixel_to_point(pixel_x, pixel_y, std::get<0x02>(my_ref_to_rectangle_tuple.get()).center()) && result_is_ok };
- result_is_ok = { std::get<0x03>(my_ref_to_rectangle_tuple.get()).pixel_to_point(pixel_x, pixel_y, std::get<0x03>(my_ref_to_rectangle_tuple.get()).center()) && result_is_ok };
+ result_is_ok = { std::get<0x00>(my_ref_to_rectangle_tuple.get()).pixel_to_point(pixel_x, pixel_y, std::get<0x00>(my_rectangle_centers)) && result_is_ok };
+ result_is_ok = { std::get<0x01>(my_ref_to_rectangle_tuple.get()).pixel_to_point(pixel_x, pixel_y, std::get<0x01>(my_rectangle_centers)) && result_is_ok };
+ result_is_ok = { std::get<0x02>(my_ref_to_rectangle_tuple.get()).pixel_to_point(pixel_x, pixel_y, std::get<0x02>(my_rectangle_centers)) && result_is_ok };
+ result_is_ok = { std::get<0x03>(my_ref_to_rectangle_tuple.get()).pixel_to_point(pixel_x, pixel_y, std::get<0x03>(my_rectangle_centers)) && result_is_ok };
if(result_is_ok)
{
const int tuple_index { rectangle_tuple_index() };
- if (tuple_index == 0) { result_is_ok = (write_coords<0x00>() && result_is_ok); }
- else if(tuple_index == 1) { result_is_ok = (write_coords<0x01>() && result_is_ok); }
- else if(tuple_index == 2) { result_is_ok = (write_coords<0x02>() && result_is_ok); }
- else { result_is_ok = (write_coords<0x03>() && result_is_ok); }
+ switch(tuple_index)
+ {
+ case 0x00:
+ result_is_ok = (write_number("x_val : ", std::get<0x00>(my_rectangle_centers).get_x()) && result_is_ok);
+ result_is_ok = (write_number("y_val : ", std::get<0x00>(my_rectangle_centers).get_y()) && result_is_ok);
+ result_is_ok = (write_number("dx_half: ", std::get<0x00>(my_ref_to_rectangle_tuple.get()).dx_half(), 3) && result_is_ok);
+ break;
+
+ case 0x01:
+ result_is_ok = (write_number("x_val : ", std::get<0x01>(my_rectangle_centers).get_x()) && result_is_ok);
+ result_is_ok = (write_number("y_val : ", std::get<0x01>(my_rectangle_centers).get_y()) && result_is_ok);
+ result_is_ok = (write_number("dx_half: ", std::get<0x01>(my_ref_to_rectangle_tuple.get()).dx_half(), 3) && result_is_ok);
+ break;
+
+ case 0x02:
+ result_is_ok = (write_number("x_val : ", std::get<0x02>(my_rectangle_centers).get_x()) && result_is_ok);
+ result_is_ok = (write_number("y_val : ", std::get<0x02>(my_rectangle_centers).get_y()) && result_is_ok);
+ result_is_ok = (write_number("dx_half: ", std::get<0x02>(my_ref_to_rectangle_tuple.get()).dx_half(), 3) && result_is_ok);
+ break;
+
+ case 0x03:
+ default:
+ result_is_ok = (write_number("x_val : ", std::get<0x03>(my_rectangle_centers).get_x()) && result_is_ok);
+ result_is_ok = (write_number("y_val : ", std::get<0x03>(my_rectangle_centers).get_y()) && result_is_ok);
+ result_is_ok = (write_number("dx_half: ", std::get<0x03>(my_ref_to_rectangle_tuple.get()).dx_half(), 3) && result_is_ok);
+ break;
+ }
result_is_ok = (write_string("\n") && result_is_ok);
}
@@ -620,6 +640,57 @@
write_string("new max. iterations: " + std::to_string(iter) + "\n");
}
}
+ else if( (str_cmd.find("res", static_cast(UINT8_C(0))) == static_cast(UINT8_C(0)))
+ && (str_cmd.length() > static_cast(UINT8_C(3))))
+ {
+ // TODO ckormanyos Parse strings of the form:
+ // res, res1, res1/2, res1/4, res1/8, res1/16, ...
+ // ... and use this resolution information accordingly.
+
+ // See also code at GodBolt at: https://godbolt.org/z/Wq5nran4o
+
+ if((str_cmd == "res") || (str_cmd == "res1"))
+ {
+ my_mandelbrot_frac2_denominator = 1;
+
+ write_string("new resolution having fraction: 1/1\n");
+ }
+ else
+ {
+ // Regex pattern to match the required strings.
+ std::string pattern_str = "res(1)?(/(2|4|8|16))?";
+ std::regex pattern(pattern_str);
+
+ std::smatch match;
+
+ if (std::regex_match(str_cmd, match, pattern))
+ {
+ if((match[1].matched) && (match[3].matched))
+ {
+ const std::string str_frac { match[3].str() };
+
+ int frac2 { };
+
+ const auto result_of_iter_from_chars =
+ std::from_chars
+ (
+ str_frac.data(),
+ str_frac.data() + str_frac.length(),
+ frac2
+ );
+
+ const auto err_code = result_of_iter_from_chars.ec;
+
+ if(err_code == std::errc())
+ {
+ my_mandelbrot_frac2_denominator = frac2;
+
+ write_string("new resolution having fraction: 1/" + std::to_string(frac2) + "\n");
+ }
+ }
+ }
+ }
+ }
else if(str_cmd == "calc")
{
// Rescale and re-center the rectangles.
@@ -642,10 +713,10 @@
}
);
- std::get<0x00>(my_ref_to_rectangle_tuple.get()).recenter(std::get<0x00>(my_ref_to_rectangle_tuple.get()).center());
- std::get<0x01>(my_ref_to_rectangle_tuple.get()).recenter(std::get<0x01>(my_ref_to_rectangle_tuple.get()).center());
- std::get<0x02>(my_ref_to_rectangle_tuple.get()).recenter(std::get<0x02>(my_ref_to_rectangle_tuple.get()).center());
- std::get<0x03>(my_ref_to_rectangle_tuple.get()).recenter(std::get<0x03>(my_ref_to_rectangle_tuple.get()).center());
+ std::get<0x00>(my_ref_to_rectangle_tuple.get()).recenter(std::get<0x00>(my_rectangle_centers));
+ std::get<0x01>(my_ref_to_rectangle_tuple.get()).recenter(std::get<0x01>(my_rectangle_centers));
+ std::get<0x02>(my_ref_to_rectangle_tuple.get()).recenter(std::get<0x02>(my_rectangle_centers));
+ std::get<0x03>(my_ref_to_rectangle_tuple.get()).recenter(std::get<0x03>(my_rectangle_centers));
// Set the flag to redraw the client window with the new JPEG.
// The redrawing will occur below.
@@ -707,10 +778,38 @@
const int local_rectangle_tuple_index { rectangle_tuple_index() };
- if (local_rectangle_tuple_index == 0x00) { mandelbrot_iterate_engine<0x00>(); }
- else if(local_rectangle_tuple_index == 0x01) { mandelbrot_iterate_engine<0x01>(); }
- else if(local_rectangle_tuple_index == 0x02) { mandelbrot_iterate_engine<0x02>(); }
- else { mandelbrot_iterate_engine<0x03>(); }
+ if(local_rectangle_tuple_index == 0x00)
+ {
+ if (my_mandelbrot_frac2_denominator == 16) { mandelbrot_iterate_engine<0x00, 16>(); }
+ else if(my_mandelbrot_frac2_denominator == 8) { mandelbrot_iterate_engine<0x00, 8>(); }
+ else if(my_mandelbrot_frac2_denominator == 4) { mandelbrot_iterate_engine<0x00, 4>(); }
+ else if(my_mandelbrot_frac2_denominator == 2) { mandelbrot_iterate_engine<0x00, 2>(); }
+ else { mandelbrot_iterate_engine<0x00, 1>(); }
+ }
+ else if(local_rectangle_tuple_index == 0x01)
+ {
+ if (my_mandelbrot_frac2_denominator == 16) { mandelbrot_iterate_engine<0x01, 16>(); }
+ else if(my_mandelbrot_frac2_denominator == 8) { mandelbrot_iterate_engine<0x01, 8>(); }
+ else if(my_mandelbrot_frac2_denominator == 4) { mandelbrot_iterate_engine<0x01, 4>(); }
+ else if(my_mandelbrot_frac2_denominator == 2) { mandelbrot_iterate_engine<0x01, 2>(); }
+ else { mandelbrot_iterate_engine<0x01, 1>(); }
+ }
+ else if(local_rectangle_tuple_index == 0x02)
+ {
+ if (my_mandelbrot_frac2_denominator == 16) { mandelbrot_iterate_engine<0x02, 16>(); }
+ else if(my_mandelbrot_frac2_denominator == 8) { mandelbrot_iterate_engine<0x02, 8>(); }
+ else if(my_mandelbrot_frac2_denominator == 4) { mandelbrot_iterate_engine<0x02, 4>(); }
+ else if(my_mandelbrot_frac2_denominator == 2) { mandelbrot_iterate_engine<0x02, 2>(); }
+ else { mandelbrot_iterate_engine<0x02, 1>(); }
+ }
+ else
+ {
+ if (my_mandelbrot_frac2_denominator == 16) { mandelbrot_iterate_engine<0x03, 16>(); }
+ else if(my_mandelbrot_frac2_denominator == 8) { mandelbrot_iterate_engine<0x03, 8>(); }
+ else if(my_mandelbrot_frac2_denominator == 4) { mandelbrot_iterate_engine<0x03, 4>(); }
+ else if(my_mandelbrot_frac2_denominator == 2) { mandelbrot_iterate_engine<0x03, 2>(); }
+ else { mandelbrot_iterate_engine<0x03, 1>(); }
+ }
// Redraw the client window with the new JPEG.
using local_window_type = mandelbrot_discovery;
@@ -847,10 +946,12 @@
write_string("MandelbrotDiscovery (C) 2024 Christopher Kormanyos.\n")
&& write_string(" help (or ?) - Print this text.\n")
&& write_string(" set - Select new coordinates with the mouse.\n")
- && write_string(" calc** - Iterate at the current coordinates and display.\n")
+ && write_string(" calc - Iterate at the current coordinates and display.\n")
&& write_string(" itrNNNN - Set max.-iterations, where NNNN is something like 1000\n")
+ && write_string(" res1/F - Set resultion, where F can be 1, 2, 4, 8 or 16\n")
&& write_string(" redo - Iterate at the current coordinates and scale.\n")
&& write_string(" out - Backstep one single order of magnification.\n")
+ && write_string(" exit - Exit the program.\n")
);
return result_write_is_ok;
@@ -1043,6 +1144,15 @@
const int ScreenCoordinateY>
std::atomic mandelbrot_discovery::my_thread_wait_for_new_set_click;
+ template
+ typename mandelbrot_discovery::point_tuple_type mandelbrot_discovery::my_rectangle_centers { };
+
template
std::uint_fast32_t mandelbrot_discovery::my_mandelbrot_iterations { static_cast(UINT32_C(400)) };
+ template
+ unsigned mandelbrot_discovery::my_mandelbrot_frac2_denominator { 1U };
+
#endif // MANDELBROT_DISCOVERY_2024_04_12_H
diff --git a/MandelbrotDiscovery/mandelbrot_discovery_rescale.cpp b/MandelbrotDiscovery/mandelbrot_discovery_rescale.cpp
new file mode 100644
index 0000000..0127845
--- /dev/null
+++ b/MandelbrotDiscovery/mandelbrot_discovery_rescale.cpp
@@ -0,0 +1,59 @@
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+auto mandelbrot_discovery_rescale() -> void
+{
+ // Rescale the JPEG/PNG files.
+
+ // Load the input image(s).
+ boost::gil::rgb8_image_t input_image_jpg;
+ boost::gil::rgb8_image_t input_image_png;
+
+ boost::gil::read_image("mandelbrot_zooming.jpg", input_image_jpg, boost::gil::jpeg_tag());
+ boost::gil::read_image("mandelbrot_zooming.png", input_image_png, boost::gil::png_tag ());
+
+ // Get the dimensions of the input image(s).
+ const auto input_dimensions_jpg = input_image_jpg.dimensions();
+ const auto input_dimensions_png = input_image_png.dimensions();
+
+ // Define the new desired size by scaling from potentially fewer pixels
+ // to the default of 768 * 768 pixels.
+
+ boost::gil::point_t
+ new_dimensions
+ {
+ geometry::rectangle_base::default_pixels(),
+ geometry::rectangle_base::default_pixels()
+ };
+
+ // Create the output image(s) with the new dimensions
+ boost::gil::rgb8_image_t output_image_jpg(new_dimensions.x, new_dimensions.y);
+ boost::gil::rgb8_image_t output_image_png(new_dimensions.x, new_dimensions.y);
+
+ // Resize the output image(s).
+ boost::gil::resize_view
+ (
+ boost::gil::view(input_image_jpg),
+ boost::gil::view(output_image_jpg),
+ boost::gil::bilinear_sampler()
+ );
+
+ boost::gil::resize_view
+ (
+ boost::gil::view(input_image_png),
+ boost::gil::view(output_image_png),
+ boost::gil::bilinear_sampler()
+ );
+
+ // Save the resized output image(s).
+ boost::gil::write_view("mandelbrot_zooming.jpg", boost::gil::view(output_image_jpg), boost::gil::jpeg_tag());
+ boost::gil::write_view("mandelbrot_zooming.png", boost::gil::view(output_image_png), boost::gil::png_tag ());
+}
diff --git a/MandelbrotDiscovery/readme.md b/MandelbrotDiscovery/readme.md
index 4b947c6..6a51425 100644
--- a/MandelbrotDiscovery/readme.md
+++ b/MandelbrotDiscovery/readme.md
@@ -29,9 +29,9 @@ coordinate points of the Mandelbrot set.
Build `MandelbrotDiscovery.exe` from the Microsoft(R) VisualStudio(R)
solution, `MandelbrotDiscovery.sln` located
[here](https://github.com/ckormanyos/mandelbrot/tree/main/MandelbrotDiscovery).
-The program written in classic Win32-API style. Aside from some
-geometrical and coordinate-related artifacts and setting up the
-main Window, the program is written in convenient, lightweight header-only.
+The program uses the classic Win32-API style. Aside from
+the JPEG and PNG libraries and image-rescaling, the program
+is written in a convenient, lightweight header-only fashion.
The program is mouse-and-command-driven.
Begin a search by starting `MandelbrotDiscovery.exe`.
@@ -46,7 +46,8 @@ The following commands are supported at the moment (with more planned for the fu
- set
- Enter the set
command prior to pointing and clicking to select now coordinates with the mouse.
- calc
- The calc
command calculated the Mandelbrot image at the currently set coordinate point. It subsequently displays the image after the calculation.
- itrNNNN
- Using itrNNNN
sets the maximum number of iterations to the appended number. The command itr2000
, for instance, sets the maximum number of iterations to $2,000$. Switch $2,000$ for another number like $40,000$ to obtain a maximum iteration count of $40,000$ and so on. The default iteration count at program start is modestly set to $400$. So don't be surprised if higher iteration counts are required for deeper and deeper dives.
- - redo
- The command redo
simply performs, yet again, the iteration at the coordinate point that is already set. This might be done if, for example, the image was not resolved and the iteration count needs to be increased. You can also exercise the set
command one or more times prior to exercising the redo
command.
+ - res1/F
- Using res1/F
sets the fractional resolution based on the default of $768{\times}768$ pixels. The command res1/2
, for example, sets the resolution to $384{\times}384$ pixels. The fractions $1/1$, $1/2$, $1/4$, $1/8$ and $1/16$ are supported. The command res
(or res1
) restores the default resolution.
+ - redo
- The command redo
simply performs, yet again, the iteration at the coordinate point that is already set. This might be done if, for example, the image was not resolved and the iteration count needs to be increased. You can also exercise the set
command one or more times prior to exercising the redo
command. Reduced resolution can decrease computation time when searching via deep diving.
- out
- With out
you can backstep one single order of magnification at the point that has been set and clicked. This can be done repeatedly if a different zoom pathway is desired even after zooming in to a point. So if you've taken a bit of a wrong turn, just zoom out
one or more times and refine your coordinate search.
- exit
- Quits the program and closes the image window.
diff --git a/MandelbrotDiscovery/resource.h b/MandelbrotDiscovery/resource.h
index 8524e67..d059ec1 100644
--- a/MandelbrotDiscovery/resource.h
+++ b/MandelbrotDiscovery/resource.h
@@ -2,5 +2,5 @@
// Microsoft Visual C++ generated include file.
// Used by MandelbrotDiscovery.rc
//
-#define IDI_MANDELBROT_DISCO 101
+#define IDI_MANDELBROT_DISCO 101
diff --git a/jpeg/Makefile b/jpeg/Makefile
index 85cf6e8..ca641c7 100644
--- a/jpeg/Makefile
+++ b/jpeg/Makefile
@@ -58,6 +58,7 @@ $(OBJ_DIR)/libjpeg-6b.a :
$(CC) $(CFLAGS) -c $(SRC_DIR)/jcsample.c -o $(OBJ_DIR)/jcsample.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jctrans.c -o $(OBJ_DIR)/jctrans.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdapimin.c -o $(OBJ_DIR)/jdapimin.o
+ $(CC) $(CFLAGS) -c $(SRC_DIR)/jdapistd.c -o $(OBJ_DIR)/jdapistd.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdatadst.c -o $(OBJ_DIR)/jdatadst.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdcoefct.c -o $(OBJ_DIR)/jdcoefct.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdcolor.c -o $(OBJ_DIR)/jdcolor.o
@@ -65,7 +66,9 @@ $(OBJ_DIR)/libjpeg-6b.a :
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdinput.c -o $(OBJ_DIR)/jdinput.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdmainct.c -o $(OBJ_DIR)/jdmainct.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdmarker.c -o $(OBJ_DIR)/jdmarker.o
+ $(CC) $(CFLAGS) -c $(SRC_DIR)/jdmaster.c -o $(OBJ_DIR)/jdmaster.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdmerge.c -o $(OBJ_DIR)/jdmerge.o
+ $(CC) $(CFLAGS) -c $(SRC_DIR)/jdphuff.c -o $(OBJ_DIR)/jdphuff.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdpostct.c -o $(OBJ_DIR)/jdpostct.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jdsample.c -o $(OBJ_DIR)/jdsample.o
$(CC) $(CFLAGS) -c $(SRC_DIR)/jerror.c -o $(OBJ_DIR)/jerror.o
diff --git a/jpeg/jpeg-6b-2022/jdapistd.c b/jpeg/jpeg-6b-2022/jdapistd.c
new file mode 100644
index 0000000..4abc8c7
--- /dev/null
+++ b/jpeg/jpeg-6b-2022/jdapistd.c
@@ -0,0 +1,275 @@
+/*
+ * jdapistd.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the decompression half
+ * of the JPEG library. These are the "standard" API routines that are
+ * used in the normal full-decompression case. They are not used by a
+ * transcoding-only application. Note that if an application links in
+ * jpeg_start_decompress, it will end up linking in the entire decompressor.
+ * We thus must separate this file from jdapimin.c to avoid linking the
+ * whole decompression library into a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Decompression initialization.
+ * jpeg_read_header must be completed before calling this.
+ *
+ * If a multipass operating mode was selected, this will do all but the
+ * last pass, and thus may take a great deal of time.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_start_decompress (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ /* First call: initialize master control, select active modules */
+ jinit_master_decompress(cinfo);
+ if (cinfo->buffered_image) {
+ /* No more work here; expecting jpeg_start_output next */
+ cinfo->global_state = DSTATE_BUFIMAGE;
+ return TRUE;
+ }
+ cinfo->global_state = DSTATE_PRELOAD;
+ }
+ if (cinfo->global_state == DSTATE_PRELOAD) {
+ /* If file has multiple scans, absorb them all into the coef buffer */
+ if (cinfo->inputctl->has_multiple_scans) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ for (;;) {
+ int retcode;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL)
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_SUSPENDED)
+ return FALSE;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ /* Advance progress counter if appropriate */
+ if (cinfo->progress != NULL &&
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+ /* jdmaster underestimated number of scans; ratchet up one scan */
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+ }
+ }
+ }
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+ }
+ cinfo->output_scan_number = cinfo->input_scan_number;
+ } else if (cinfo->global_state != DSTATE_PRESCAN)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Perform any dummy output passes, and set up for the final pass */
+ return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Set up for an output pass, and perform any dummy pass(es) needed.
+ * Common subroutine for jpeg_start_decompress and jpeg_start_output.
+ * Entry: global_state = DSTATE_PRESCAN only if previously suspended.
+ * Exit: If done, returns TRUE and sets global_state for proper output mode.
+ * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN.
+ */
+
+LOCAL(boolean)
+output_pass_setup (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state != DSTATE_PRESCAN) {
+ /* First call: do pass setup */
+ (*cinfo->master->prepare_for_output_pass) (cinfo);
+ cinfo->output_scanline = 0;
+ cinfo->global_state = DSTATE_PRESCAN;
+ }
+ /* Loop over any required dummy passes */
+ while (cinfo->master->is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+ /* Crank through the dummy pass */
+ while (cinfo->output_scanline < cinfo->output_height) {
+ JDIMENSION last_scanline;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+ /* Process some data */
+ last_scanline = cinfo->output_scanline;
+ (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL,
+ &cinfo->output_scanline, (JDIMENSION) 0);
+ if (cinfo->output_scanline == last_scanline)
+ return FALSE; /* No progress made, must suspend */
+ }
+ /* Finish up dummy pass, and set up for another one */
+ (*cinfo->master->finish_output_pass) (cinfo);
+ (*cinfo->master->prepare_for_output_pass) (cinfo);
+ cinfo->output_scanline = 0;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+ }
+ /* Ready for application to drive output pass through
+ * jpeg_read_scanlines or jpeg_read_raw_data.
+ */
+ cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
+ return TRUE;
+}
+
+
+/*
+ * Read some scanlines of data from the JPEG decompressor.
+ *
+ * The return value will be the number of lines actually read.
+ * This may be less than the number requested in several cases,
+ * including bottom of image, data source suspension, and operating
+ * modes that emit multiple scanlines at a time.
+ *
+ * Note: we warn about excess calls to jpeg_read_scanlines() since
+ * this likely signals an application programmer error. However,
+ * an oversize buffer (max_lines > scanlines remaining) is not an error.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
+ JDIMENSION max_lines)
+{
+ JDIMENSION row_ctr;
+
+ if (cinfo->global_state != DSTATE_SCANNING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->output_scanline >= cinfo->output_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Process some data */
+ row_ctr = 0;
+ (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);
+ cinfo->output_scanline += row_ctr;
+ return row_ctr;
+}
+
+
+/*
+ * Alternate entry point to read raw data.
+ * Processes exactly one iMCU row per call, unless suspended.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
+ JDIMENSION max_lines)
+{
+ JDIMENSION lines_per_iMCU_row;
+
+ if (cinfo->global_state != DSTATE_RAW_OK)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->output_scanline >= cinfo->output_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Verify that at least one iMCU row can be returned. */
+ lines_per_iMCU_row = (JDIMENSION) (cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size);
+ if (max_lines < lines_per_iMCU_row)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+ /* Decompress directly into user's buffer. */
+ if (! (*cinfo->coef->decompress_data) (cinfo, data))
+ return 0; /* suspension forced, can do nothing more */
+
+ /* OK, we processed one iMCU row. */
+ cinfo->output_scanline += lines_per_iMCU_row;
+ return lines_per_iMCU_row;
+}
+
+
+/* Additional entry points for buffered-image mode. */
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Initialize for an output pass in buffered-image mode.
+ */
+
+GLOBAL(boolean)
+jpeg_start_output (j_decompress_ptr cinfo, int scan_number)
+{
+ if (cinfo->global_state != DSTATE_BUFIMAGE &&
+ cinfo->global_state != DSTATE_PRESCAN)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Limit scan number to valid range */
+ if (scan_number <= 0)
+ scan_number = 1;
+ if (cinfo->inputctl->eoi_reached &&
+ scan_number > cinfo->input_scan_number)
+ scan_number = cinfo->input_scan_number;
+ cinfo->output_scan_number = scan_number;
+ /* Perform any dummy output passes, and set up for the real pass */
+ return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Finish up after an output pass in buffered-image mode.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_finish_output (j_decompress_ptr cinfo)
+{
+ if ((cinfo->global_state == DSTATE_SCANNING ||
+ cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) {
+ /* Terminate this pass. */
+ /* We do not require the whole pass to have been completed. */
+ (*cinfo->master->finish_output_pass) (cinfo);
+ cinfo->global_state = DSTATE_BUFPOST;
+ } else if (cinfo->global_state != DSTATE_BUFPOST) {
+ /* BUFPOST = repeat call after a suspension, anything else is error */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ /* Read markers looking for SOS or EOI */
+ while (cinfo->input_scan_number <= cinfo->output_scan_number &&
+ ! cinfo->inputctl->eoi_reached) {
+ if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+ return FALSE; /* Suspend, come back later */
+ }
+ cinfo->global_state = DSTATE_BUFIMAGE;
+ return TRUE;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
diff --git a/jpeg/jpeg-6b-2022/jdmaster.c b/jpeg/jpeg-6b-2022/jdmaster.c
new file mode 100644
index 0000000..2802c5b
--- /dev/null
+++ b/jpeg/jpeg-6b-2022/jdmaster.c
@@ -0,0 +1,557 @@
+/*
+ * jdmaster.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains master control logic for the JPEG decompressor.
+ * These routines are concerned with selecting the modules to be executed
+ * and with determining the number of passes and the work to be done in each
+ * pass.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_decomp_master pub; /* public fields */
+
+ int pass_number; /* # of passes completed */
+
+ boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
+
+ /* Saved references to initialized quantizer modules,
+ * in case we need to switch modes.
+ */
+ struct jpeg_color_quantizer * quantizer_1pass;
+ struct jpeg_color_quantizer * quantizer_2pass;
+} my_decomp_master;
+
+typedef my_decomp_master * my_master_ptr;
+
+
+/*
+ * Determine whether merged upsample/color conversion should be used.
+ * CRUCIAL: this must match the actual capabilities of jdmerge.c!
+ */
+
+LOCAL(boolean)
+use_merged_upsample (j_decompress_ptr cinfo)
+{
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ /* Merging is the equivalent of plain box-filter upsampling */
+ if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
+ return FALSE;
+ /* jdmerge.c only supports YCC=>RGB color conversion */
+ if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
+ cinfo->out_color_space != JCS_RGB ||
+ cinfo->out_color_components != RGB_PIXELSIZE)
+ return FALSE;
+ /* and it only handles 2h1v or 2h2v sampling ratios */
+ if (cinfo->comp_info[0].h_samp_factor != 2 ||
+ cinfo->comp_info[1].h_samp_factor != 1 ||
+ cinfo->comp_info[2].h_samp_factor != 1 ||
+ cinfo->comp_info[0].v_samp_factor > 2 ||
+ cinfo->comp_info[1].v_samp_factor != 1 ||
+ cinfo->comp_info[2].v_samp_factor != 1)
+ return FALSE;
+ /* furthermore, it doesn't work if we've scaled the IDCTs differently */
+ if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
+ cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
+ cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size)
+ return FALSE;
+ /* ??? also need to test for upsample-time rescaling, when & if supported */
+ return TRUE; /* by golly, it'll work... */
+#else
+ return FALSE;
+#endif
+}
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ * Also note that it may be called before the master module is initialized!
+ */
+
+GLOBAL(void)
+jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+ int ci;
+ jpeg_component_info *compptr;
+#endif
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_READY)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+ /* Compute actual output image dimensions and DCT scaling choices. */
+ if (cinfo->scale_num * 8 <= cinfo->scale_denom) {
+ /* Provide 1/8 scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width, 8L);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height, 8L);
+ cinfo->min_DCT_scaled_size = 1;
+ } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) {
+ /* Provide 1/4 scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width, 4L);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height, 4L);
+ cinfo->min_DCT_scaled_size = 2;
+ } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) {
+ /* Provide 1/2 scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width, 2L);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height, 2L);
+ cinfo->min_DCT_scaled_size = 4;
+ } else {
+ /* Provide 1/1 scaling */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ cinfo->min_DCT_scaled_size = DCTSIZE;
+ }
+ /* In selecting the actual DCT scaling for each component, we try to
+ * scale up the chroma components via IDCT scaling rather than upsampling.
+ * This saves time if the upsampler gets to use 1:1 scaling.
+ * Note this code assumes that the supported DCT scalings are powers of 2.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ int ssize = cinfo->min_DCT_scaled_size;
+ while (ssize < DCTSIZE &&
+ (compptr->h_samp_factor * ssize * 2 <=
+ cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) &&
+ (compptr->v_samp_factor * ssize * 2 <=
+ cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) {
+ ssize = ssize * 2;
+ }
+ compptr->DCT_scaled_size = ssize;
+ }
+
+ /* Recompute downsampled dimensions of components;
+ * application needs to know these if using raw downsampled data.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Size in samples, after IDCT scaling */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width *
+ (long) (compptr->h_samp_factor * compptr->DCT_scaled_size),
+ (long) (cinfo->max_h_samp_factor * DCTSIZE));
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height *
+ (long) (compptr->v_samp_factor * compptr->DCT_scaled_size),
+ (long) (cinfo->max_v_samp_factor * DCTSIZE));
+ }
+
+#else /* !IDCT_SCALING_SUPPORTED */
+
+ /* Hardwire it to "no scaling" */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
+ * and has computed unscaled downsampled_width and downsampled_height.
+ */
+
+#endif /* IDCT_SCALING_SUPPORTED */
+
+ /* Report number of components in selected colorspace. */
+ /* Probably this should be in the color conversion module... */
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo->out_color_components = 1;
+ break;
+ case JCS_RGB:
+#if RGB_PIXELSIZE != 3
+ cinfo->out_color_components = RGB_PIXELSIZE;
+ break;
+#endif /* else share code with YCbCr */
+ case JCS_YCbCr:
+ cinfo->out_color_components = 3;
+ break;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo->out_color_components = 4;
+ break;
+ default: /* else must be same colorspace as in file */
+ cinfo->out_color_components = cinfo->num_components;
+ break;
+ }
+ cinfo->output_components = (cinfo->quantize_colors ? 1 :
+ cinfo->out_color_components);
+
+ /* See if upsampler will want to emit more than one row at a time */
+ if (use_merged_upsample(cinfo))
+ cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;
+ else
+ cinfo->rec_outbuf_height = 1;
+}
+
+
+/*
+ * Several decompression processes need to range-limit values to the range
+ * 0..MAXJSAMPLE; the input value may fall somewhat outside this range
+ * due to noise introduced by quantization, roundoff error, etc. These
+ * processes are inner loops and need to be as fast as possible. On most
+ * machines, particularly CPUs with pipelines or instruction prefetch,
+ * a (subscript-check-less) C table lookup
+ * x = sample_range_limit[x];
+ * is faster than explicit tests
+ * if (x < 0) x = 0;
+ * else if (x > MAXJSAMPLE) x = MAXJSAMPLE;
+ * These processes all use a common table prepared by the routine below.
+ *
+ * For most steps we can mathematically guarantee that the initial value
+ * of x is within MAXJSAMPLE+1 of the legal range, so a table running from
+ * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial
+ * limiting step (just after the IDCT), a wildly out-of-range value is
+ * possible if the input data is corrupt. To avoid any chance of indexing
+ * off the end of memory and getting a bad-pointer trap, we perform the
+ * post-IDCT limiting thus:
+ * x = range_limit[x & MASK];
+ * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
+ * samples. Under normal circumstances this is more than enough range and
+ * a correct output will be generated; with bogus input data the mask will
+ * cause wraparound, and we will safely generate a bogus-but-in-range output.
+ * For the post-IDCT step, we want to convert the data from signed to unsigned
+ * representation by adding CENTERJSAMPLE at the same time that we limit it.
+ * So the post-IDCT limiting table ends up looking like this:
+ * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
+ * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0,1,...,CENTERJSAMPLE-1
+ * Negative inputs select values from the upper half of the table after
+ * masking.
+ *
+ * We can save some space by overlapping the start of the post-IDCT table
+ * with the simpler range limiting table. The post-IDCT table begins at
+ * sample_range_limit + CENTERJSAMPLE.
+ *
+ * Note that the table is allocated in near data space on PCs; it's small
+ * enough and used often enough to justify this.
+ */
+
+LOCAL(void)
+prepare_range_limit_table (j_decompress_ptr cinfo)
+/* Allocate and fill in the sample_range_limit table */
+{
+ JSAMPLE * table;
+ int i;
+
+ table = (JSAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+ table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */
+ cinfo->sample_range_limit = table;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJSAMPLE; i++)
+ table[i] = (JSAMPLE) i;
+ table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++)
+ table[i] = MAXJSAMPLE;
+ /* Second half of post-IDCT table */
+ MEMZERO(table + (2 * (MAXJSAMPLE+1)),
+ (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+ MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE),
+ cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE));
+}
+
+
+/*
+ * Master selection of decompression modules.
+ * This is done once at jpeg_start_decompress time. We determine
+ * which modules will be used and give them appropriate initialization calls.
+ * We also initialize the decompressor input side to begin consuming data.
+ *
+ * Since jpeg_read_header has finished, we know what is in the SOF
+ * and (first) SOS markers. We also have all the application parameter
+ * settings.
+ */
+
+LOCAL(void)
+master_selection (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+ boolean use_c_buffer;
+ long samplesperrow;
+ JDIMENSION jd_samplesperrow;
+
+ /* Initialize dimensions and other stuff */
+ jpeg_calc_output_dimensions(cinfo);
+ prepare_range_limit_table(cinfo);
+
+ /* Width of an output scanline must be representable as JDIMENSION. */
+ samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components;
+ jd_samplesperrow = (JDIMENSION) samplesperrow;
+ if ((long) jd_samplesperrow != samplesperrow)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+ /* Initialize my private state */
+ master->pass_number = 0;
+ master->using_merged_upsample = use_merged_upsample(cinfo);
+
+ /* Color quantizer selection */
+ master->quantizer_1pass = NULL;
+ master->quantizer_2pass = NULL;
+ /* No mode changes if not using buffered-image mode. */
+ if (! cinfo->quantize_colors || ! cinfo->buffered_image) {
+ cinfo->enable_1pass_quant = FALSE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ }
+ if (cinfo->quantize_colors) {
+ if (cinfo->raw_data_out)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+ /* 2-pass quantizer only works in 3-component color space. */
+ if (cinfo->out_color_components != 3) {
+ cinfo->enable_1pass_quant = TRUE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ cinfo->colormap = NULL;
+ } else if (cinfo->colormap != NULL) {
+ cinfo->enable_external_quant = TRUE;
+ } else if (cinfo->two_pass_quantize) {
+ cinfo->enable_2pass_quant = TRUE;
+ } else {
+ cinfo->enable_1pass_quant = TRUE;
+ }
+
+ if (cinfo->enable_1pass_quant) {
+#ifdef QUANT_1PASS_SUPPORTED
+ jinit_1pass_quantizer(cinfo);
+ master->quantizer_1pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+
+ /* We use the 2-pass code to map to external colormaps. */
+ if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
+#ifdef QUANT_2PASS_SUPPORTED
+ jinit_2pass_quantizer(cinfo);
+ master->quantizer_2pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+ /* If both quantizers are initialized, the 2-pass one is left active;
+ * this is necessary for starting with quantization to an external map.
+ */
+ }
+
+ /* Post-processing: in particular, color conversion first */
+ if (! cinfo->raw_data_out) {
+ if (master->using_merged_upsample) {
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ jinit_merged_upsampler(cinfo); /* does color conversion too */
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ jinit_color_deconverter(cinfo);
+ jinit_upsampler(cinfo);
+ }
+ jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+ }
+ /* Inverse DCT */
+ jinit_inverse_dct(cinfo);
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ if (cinfo->progressive_mode) {
+#ifdef D_PROGRESSIVE_SUPPORTED
+ jinit_phuff_decoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else
+ jinit_huff_decoder(cinfo);
+ }
+
+ /* Initialize principal buffer controllers. */
+ use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
+ jinit_d_coef_controller(cinfo, use_c_buffer);
+
+ if (! cinfo->raw_data_out)
+ jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Initialize input side of decompressor to consume first scan. */
+ (*cinfo->inputctl->start_input_pass) (cinfo);
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* If jpeg_start_decompress will read the whole file, initialize
+ * progress monitoring appropriately. The input step is counted
+ * as one pass.
+ */
+ if (cinfo->progress != NULL && ! cinfo->buffered_image &&
+ cinfo->inputctl->has_multiple_scans) {
+ int nscans;
+ /* Estimate number of scans to set pass_limit. */
+ if (cinfo->progressive_mode) {
+ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+ nscans = 2 + 3 * cinfo->num_components;
+ } else {
+ /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+ nscans = cinfo->num_components;
+ }
+ cinfo->progress->pass_counter = 0L;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
+ cinfo->progress->completed_passes = 0;
+ cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);
+ /* Count the input pass as done */
+ master->pass_number++;
+ }
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each output pass. We determine which
+ * modules will be active during this pass and give them appropriate
+ * start_pass calls. We also set is_dummy_pass to indicate whether this
+ * is a "real" output pass or a dummy pass for color quantization.
+ * (In the latter case, jdapistd.c will crank the pass to completion.)
+ */
+
+METHODDEF(void)
+prepare_for_output_pass (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ if (master->pub.is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+ /* Final pass of 2-pass quantization */
+ master->pub.is_dummy_pass = FALSE;
+ (*cinfo->cquantize->start_pass) (cinfo, FALSE);
+ (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);
+ (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+ } else {
+ if (cinfo->quantize_colors && cinfo->colormap == NULL) {
+ /* Select new quantization method */
+ if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
+ cinfo->cquantize = master->quantizer_2pass;
+ master->pub.is_dummy_pass = TRUE;
+ } else if (cinfo->enable_1pass_quant) {
+ cinfo->cquantize = master->quantizer_1pass;
+ } else {
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+ }
+ }
+ (*cinfo->idct->start_pass) (cinfo);
+ (*cinfo->coef->start_output_pass) (cinfo);
+ if (! cinfo->raw_data_out) {
+ if (! master->using_merged_upsample)
+ (*cinfo->cconvert->start_pass) (cinfo);
+ (*cinfo->upsample->start_pass) (cinfo);
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);
+ (*cinfo->post->start_pass) (cinfo,
+ (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+ (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+ }
+ }
+
+ /* Set up progress monitor's pass info if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->completed_passes = master->pass_number;
+ cinfo->progress->total_passes = master->pass_number +
+ (master->pub.is_dummy_pass ? 2 : 1);
+ /* In buffered-image mode, we assume one more output pass if EOI not
+ * yet reached, but no more passes if EOI has been reached.
+ */
+ if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) {
+ cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);
+ }
+ }
+}
+
+
+/*
+ * Finish up at end of an output pass.
+ */
+
+METHODDEF(void)
+finish_output_pass (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->finish_pass) (cinfo);
+ master->pass_number++;
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+GLOBAL(void)
+jpeg_new_colormap (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_BUFIMAGE)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (cinfo->quantize_colors && cinfo->enable_external_quant &&
+ cinfo->colormap != NULL) {
+ /* Select 2-pass quantizer for external colormap use */
+ cinfo->cquantize = master->quantizer_2pass;
+ /* Notify quantizer of colormap change */
+ (*cinfo->cquantize->new_color_map) (cinfo);
+ master->pub.is_dummy_pass = FALSE; /* just in case */
+ } else
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+/*
+ * Initialize master decompression control and select active modules.
+ * This is performed at the start of jpeg_start_decompress.
+ */
+
+GLOBAL(void)
+jinit_master_decompress (j_decompress_ptr cinfo)
+{
+ my_master_ptr master;
+
+ master = (my_master_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_decomp_master));
+ cinfo->master = (struct jpeg_decomp_master *) master;
+ master->pub.prepare_for_output_pass = prepare_for_output_pass;
+ master->pub.finish_output_pass = finish_output_pass;
+
+ master->pub.is_dummy_pass = FALSE;
+
+ master_selection(cinfo);
+}
diff --git a/jpeg/jpeg-6b-2022/jdphuff.c b/jpeg/jpeg-6b-2022/jdphuff.c
new file mode 100644
index 0000000..15d8ee0
--- /dev/null
+++ b/jpeg/jpeg-6b-2022/jdphuff.c
@@ -0,0 +1,686 @@
+/*
+ * jdphuff.c
+ *
+ * Copyright (C) 1995-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy decoding routines for progressive JPEG.
+ *
+ * Much of the complexity here has to do with supporting input suspension.
+ * If the data source module demands suspension, we want to be able to back
+ * up to the start of the current MCU. To do this, we copy state variables
+ * into local working storage, and update them back to the permanent
+ * storage only upon successful completion of an MCU.
+ */
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshift-negative-value"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsign-conversion"
+#endif
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdhuff.h" /* Declarations shared with jdhuff.c */
+
+
+#ifdef D_PROGRESSIVE_SUPPORTED
+
+/*
+ * Expanded entropy decoder object for progressive Huffman decoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ unsigned int EOBRUN; /* remaining EOBs in EOBRUN */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment. You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src) ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src) \
+ ((dest).EOBRUN = (src).EOBRUN, \
+ (dest).last_dc_val[0] = (src).last_dc_val[0], \
+ (dest).last_dc_val[1] = (src).last_dc_val[1], \
+ (dest).last_dc_val[2] = (src).last_dc_val[2], \
+ (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+ struct jpeg_entropy_decoder pub; /* public fields */
+
+ /* These fields are loaded into local variables at start of each MCU.
+ * In case of suspension, we exit WITHOUT updating them.
+ */
+ bitread_perm_state bitstate; /* Bit buffer at start of MCU */
+ savable_state saved; /* Other state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
+
+ d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */
+} phuff_entropy_decoder;
+
+typedef phuff_entropy_decoder * phuff_entropy_ptr;
+
+/* Forward declarations */
+METHODDEF(boolean) decode_mcu_DC_first JPP((j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(boolean) decode_mcu_AC_first JPP((j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass_phuff_decoder (j_decompress_ptr cinfo)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ boolean is_DC_band, bad;
+ int ci, coefi, tbl;
+ int *coef_bit_ptr;
+ jpeg_component_info * compptr;
+
+ is_DC_band = (cinfo->Ss == 0);
+
+ /* Validate scan parameters */
+ bad = FALSE;
+ if (is_DC_band) {
+ if (cinfo->Se != 0)
+ bad = TRUE;
+ } else {
+ /* need not check Ss/Se < 0 since they came from unsigned bytes */
+ if (cinfo->Ss > cinfo->Se || cinfo->Se >= DCTSIZE2)
+ bad = TRUE;
+ /* AC scans may have only one component */
+ if (cinfo->comps_in_scan != 1)
+ bad = TRUE;
+ }
+ if (cinfo->Ah != 0) {
+ /* Successive approximation refinement scan: must have Al = Ah-1. */
+ if (cinfo->Al != cinfo->Ah-1)
+ bad = TRUE;
+ }
+ if (cinfo->Al > 13) /* need not check for < 0 */
+ bad = TRUE;
+ /* Arguably the maximum Al value should be less than 13 for 8-bit precision,
+ * but the spec doesn't say so, and we try to be liberal about what we
+ * accept. Note: large Al values could result in out-of-range DC
+ * coefficients during early scans, leading to bizarre displays due to
+ * overflows in the IDCT math. But we won't crash.
+ */
+ if (bad)
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+ /* Update progression status, and verify that scan order is legal.
+ * Note that inter-scan inconsistencies are treated as warnings
+ * not fatal errors ... not clear if this is right way to behave.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ int cindex = cinfo->cur_comp_info[ci]->component_index;
+ coef_bit_ptr = & cinfo->coef_bits[cindex][0];
+ if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+ for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
+ int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+ if (cinfo->Ah != expected)
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+ coef_bit_ptr[coefi] = cinfo->Al;
+ }
+ }
+
+ /* Select MCU decoding routine */
+ if (cinfo->Ah == 0) {
+ if (is_DC_band)
+ entropy->pub.decode_mcu = decode_mcu_DC_first;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_first;
+ } else {
+ if (is_DC_band)
+ entropy->pub.decode_mcu = decode_mcu_DC_refine;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_refine;
+ }
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Make sure requested tables are present, and compute derived tables.
+ * We may build same derived table more than once, but it's not expensive.
+ */
+ if (is_DC_band) {
+ if (cinfo->Ah == 0) { /* DC refinement needs no table */
+ tbl = compptr->dc_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,
+ & entropy->derived_tbls[tbl]);
+ }
+ } else {
+ tbl = compptr->ac_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, FALSE, tbl,
+ & entropy->derived_tbls[tbl]);
+ /* remember the single active table */
+ entropy->ac_derived_tbl = entropy->derived_tbls[tbl];
+ }
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+
+ /* Initialize bitread state variables */
+ entropy->bitstate.bits_left = 0;
+ entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+ entropy->pub.insufficient_data = FALSE;
+
+ /* Initialize private state variables */
+ entropy->saved.EOBRUN = 0;
+
+ /* Initialize restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Figure F.12: extend sign bit.
+ * On some machines, a shift and add will be faster than a table lookup.
+ */
+
+#ifdef AVOID_TABLES
+
+#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
+
+#else
+
+#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
+
+static const int extend_test[16] = /* entry n is 2**(n-1) */
+ { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
+ 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
+
+static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
+ { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
+ ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
+ ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
+ ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
+
+#endif /* AVOID_TABLES */
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ * Returns FALSE if must suspend.
+ */
+
+LOCAL(boolean)
+process_restart (j_decompress_ptr cinfo)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int ci;
+
+ /* Throw away any unused bits remaining in bit buffer; */
+ /* include any full bytes in next_marker's count of discarded bytes */
+ cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
+ entropy->bitstate.bits_left = 0;
+
+ /* Advance past the RSTn marker */
+ if (! (*cinfo->marker->read_restart_marker) (cinfo))
+ return FALSE;
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+ /* Re-init EOB run count, too */
+ entropy->saved.EOBRUN = 0;
+
+ /* Reset restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+
+ /* Reset out-of-data flag, unless read_restart_marker left us smack up
+ * against a marker. In that case we will end up treating the next data
+ * segment as empty, and we can avoid producing bogus output pixels by
+ * leaving the flag set.
+ */
+ if (cinfo->unread_marker == 0)
+ entropy->pub.insufficient_data = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Huffman MCU decoding.
+ * Each of these routines decodes and returns one MCU's worth of
+ * Huffman-compressed coefficients.
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+ *
+ * We return FALSE if data source requested suspension. In that case no
+ * changes have been made to permanent state. (Exception: some output
+ * coefficients may already have been assigned. This is harmless for
+ * spectral selection, since we'll just re-assign them on the next call.
+ * Successive approximation AC refinement has to be more careful, however.)
+ */
+
+/*
+ * MCU decoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int Al = cinfo->Al;
+ register int s, r;
+ int blkn, ci;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+ savable_state state;
+ d_derived_tbl * tbl;
+ jpeg_component_info * compptr;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->pub.insufficient_data) {
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ tbl = entropy->derived_tbls[compptr->dc_tbl_no];
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ HUFF_DECODE(s, br_state, tbl, return FALSE, label1);
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+
+ /* Convert DC difference to actual value, update last_dc_val */
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */
+ (*block)[0] = (JCOEF) (s << Al);
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int Se = cinfo->Se;
+ int Al = cinfo->Al;
+ register int s, k, r;
+ unsigned int EOBRUN;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+ d_derived_tbl * tbl;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->pub.insufficient_data) {
+
+ /* Load up working state.
+ * We can avoid loading/saving bitread state if in an EOB run.
+ */
+ EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */
+
+ /* There is always only one block per MCU */
+
+ if (EOBRUN > 0) /* if it's a band of zeroes... */
+ EOBRUN--; /* ...process it now (we do nothing) */
+ else {
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ block = MCU_data[0];
+ tbl = entropy->ac_derived_tbl;
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, tbl, return FALSE, label2);
+ r = s >> 4;
+ s &= 15;
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ /* Scale and output coefficient in natural (dezigzagged) order */
+ (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al);
+ } else {
+ if (r == 15) { /* ZRL */
+ k += 15; /* skip 15 zeroes in band */
+ } else { /* EOBr, run length is 2^r + appended bits */
+ EOBRUN = 1 << r;
+ if (r) { /* EOBr, r > 0 */
+ CHECK_BIT_BUFFER(br_state, r, return FALSE);
+ r = GET_BITS(r);
+ EOBRUN += r;
+ }
+ EOBRUN--; /* this band is processed at this moment */
+ break; /* force end-of-band */
+ }
+ }
+ }
+
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ }
+
+ /* Completed MCU, so update state */
+ entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component, although the spec
+ * is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ int blkn;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* Not worth the cycles to check insufficient_data here,
+ * since we will not change the data anyway if we read zeroes.
+ */
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+
+ /* Encoded data is simply the next bit of the two's-complement DC value */
+ CHECK_BIT_BUFFER(br_state, 1, return FALSE);
+ if (GET_BITS(1))
+ (*block)[0] |= p1;
+ /* Note: since we use |=, repeating the assignment later is safe */
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
+ int Se = cinfo->Se;
+ int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */
+ register int s, k, r;
+ unsigned int EOBRUN;
+ JBLOCKROW block;
+ JCOEFPTR thiscoef;
+ BITREAD_STATE_VARS;
+ d_derived_tbl * tbl;
+ int num_newnz;
+ int newnz_pos[DCTSIZE2];
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, don't modify the MCU.
+ */
+ if (! entropy->pub.insufficient_data) {
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */
+
+ /* There is always only one block per MCU */
+ block = MCU_data[0];
+ tbl = entropy->ac_derived_tbl;
+
+ /* If we are forced to suspend, we must undo the assignments to any newly
+ * nonzero coefficients in the block, because otherwise we'd get confused
+ * next time about which coefficients were already nonzero.
+ * But we need not undo addition of bits to already-nonzero coefficients;
+ * instead, we can test the current bit to see if we already did it.
+ */
+ num_newnz = 0;
+
+ /* initialize coefficient loop counter to start of band */
+ k = cinfo->Ss;
+
+ if (EOBRUN == 0) {
+ for (; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, tbl, goto undoit, label3);
+ r = s >> 4;
+ s &= 15;
+ if (s) {
+ if (s != 1) /* size of new coef should always be 1 */
+ WARNMS(cinfo, JWRN_HUFF_BAD_CODE);
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1))
+ s = p1; /* newly nonzero coef is positive */
+ else
+ s = m1; /* newly nonzero coef is negative */
+ } else {
+ if (r != 15) {
+ EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */
+ if (r) {
+ CHECK_BIT_BUFFER(br_state, r, goto undoit);
+ r = GET_BITS(r);
+ EOBRUN += r;
+ }
+ break; /* rest of block is handled by EOB logic */
+ }
+ /* note s = 0 for processing ZRL */
+ }
+ /* Advance over already-nonzero coefs and r still-zero coefs,
+ * appending correction bits to the nonzeroes. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ do {
+ thiscoef = *block + jpeg_natural_order[k];
+ if (*thiscoef != 0) {
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1)) {
+ if ((*thiscoef & p1) == 0) { /* do nothing if already set it */
+ if (*thiscoef >= 0)
+ *thiscoef += p1;
+ else
+ *thiscoef += m1;
+ }
+ }
+ } else {
+ if (--r < 0)
+ break; /* reached target zero coefficient */
+ }
+ k++;
+ } while (k <= Se);
+ if (s) {
+ int pos = jpeg_natural_order[k];
+ /* Output newly nonzero coefficient */
+ (*block)[pos] = (JCOEF) s;
+ /* Remember its position in case we have to suspend */
+ newnz_pos[num_newnz++] = pos;
+ }
+ }
+ }
+
+ if (EOBRUN > 0) {
+ /* Scan any remaining coefficient positions after the end-of-band
+ * (the last newly nonzero coefficient, if any). Append a correction
+ * bit to each already-nonzero coefficient. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ for (; k <= Se; k++) {
+ thiscoef = *block + jpeg_natural_order[k];
+ if (*thiscoef != 0) {
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1)) {
+ if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */
+ if (*thiscoef >= 0)
+ *thiscoef += p1;
+ else
+ *thiscoef += m1;
+ }
+ }
+ }
+ }
+ /* Count one block completed in EOB run */
+ EOBRUN--;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+
+undoit:
+ /* Re-zero any output coefficients that we made newly nonzero */
+ while (num_newnz > 0)
+ (*block)[newnz_pos[--num_newnz]] = 0;
+
+ return FALSE;
+}
+
+
+/*
+ * Module initialization routine for progressive Huffman entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_phuff_decoder (j_decompress_ptr cinfo)
+{
+ phuff_entropy_ptr entropy;
+ int *coef_bit_ptr;
+ int ci, i;
+
+ entropy = (phuff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(phuff_entropy_decoder));
+ cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
+ entropy->pub.start_pass = start_pass_phuff_decoder;
+
+ /* Mark derived tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->derived_tbls[i] = NULL;
+ }
+
+ /* Create progression status table */
+ cinfo->coef_bits = (int (*)[DCTSIZE2])
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components*DCTSIZE2*SIZEOF(int));
+ coef_bit_ptr = & cinfo->coef_bits[0][0];
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ for (i = 0; i < DCTSIZE2; i++)
+ *coef_bit_ptr++ = -1;
+}
+
+#endif /* D_PROGRESSIVE_SUPPORTED */
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#pragma GCC diagnostic pop
+#pragma GCC diagnostic pop
+#pragma GCC diagnostic pop
+#endif
diff --git a/jpeg/jpeg_vs2022.vcxproj b/jpeg/jpeg_vs2022.vcxproj
index acb52b0..03b9366 100644
--- a/jpeg/jpeg_vs2022.vcxproj
+++ b/jpeg/jpeg_vs2022.vcxproj
@@ -28,6 +28,7 @@
+
@@ -36,7 +37,9 @@
+
+
diff --git a/jpeg/jpeg_vs2022.vcxproj.filters b/jpeg/jpeg_vs2022.vcxproj.filters
index 3f74438..1a11262 100644
--- a/jpeg/jpeg_vs2022.vcxproj.filters
+++ b/jpeg/jpeg_vs2022.vcxproj.filters
@@ -124,6 +124,15 @@
jpeg-6b-2022
+
+ jpeg-6b-2022
+
+
+ jpeg-6b-2022
+
+
+ jpeg-6b-2022
+