33bool g_color_enabled =
true;
34bool g_color_checked =
false;
43 if (!isatty(fileno(stdout))) {
49 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
50 if (hOut == INVALID_HANDLE_VALUE) {
55 if (!GetConsoleMode(hOut, &dwMode)) {
59 dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
60 if (!SetConsoleMode(hOut, dwMode)) {
62 const char* term = std::getenv(
"TERM");
63 return term !=
nullptr;
68 const char* term = std::getenv(
"TERM");
69 if (term ==
nullptr) {
74 if (std::string_view{term} ==
"dumb") {
79 if (std::getenv(
"NO_COLOR") !=
nullptr) {
88 g_color_enabled = enabled;
89 g_color_checked =
true;
93 if (!g_color_checked) {
95 g_color_checked =
true;
97 return g_color_enabled;
106auto color(
const char*
code) ->
const char* {
110constexpr int kDefaultWidth = 78;
121 std::cout << std::string(kDefaultWidth,
'=') <<
"\n";
122 std::cout <<
center_text(title, kDefaultWidth) <<
"\n";
123 std::cout << std::string(kDefaultWidth,
'=') <<
"\n";
128 std::string line =
"--- " + std::string(title) +
" ";
129 line += std::string(kDefaultWidth - line.length(),
'-');
165 using namespace core::tags;
167 std::vector<std::pair<std::string, std::string>> patient_rows = {
168 {
"Patient Name", ds.
get_string(patient_name)},
170 {
"Birth Date", ds.
get_string(patient_birth_date)},
175 std::vector<std::pair<std::string, std::string>> study_rows = {
178 {
"Accession #", ds.
get_string(accession_number)},
179 {
"Description", ds.
get_string(study_description)},
183 std::vector<std::pair<std::string, std::string>> series_rows = {
187 {
"Description", ds.
get_string(series_description)},
191 std::vector<std::pair<std::string, std::string>> image_rows = {
195 {
"Bits Allocated", ds.
get_string(bits_allocated)},
196 {
"Photometric", ds.
get_string(photometric_interpretation)},
202 size_t max_value_length) {
204 << std::left << std::setw(14) <<
"Tag"
205 << std::setw(6) <<
"VR"
208 std::cout << std::string(kDefaultWidth,
'-') <<
"\n";
210 for (
const auto& [tag, element] : ds) {
218 auto value_result = element.as_string();
219 std::string value = value_result.is_ok() ? value_result.value() :
"<binary>";
220 std::cout <<
truncate(value, max_value_length) <<
"\n";
235 for (
const auto& line : lines) {
236 max_len = std::max(max_len, line.length());
238 max_len = std::min(max_len,
static_cast<size_t>(kDefaultWidth - 4));
241 std::cout <<
"+" << std::string(max_len + 2,
'-') <<
"+\n";
242 for (
const auto& line : lines) {
243 std::cout <<
"| " << std::left << std::setw(static_cast<int>(max_len))
244 <<
truncate(line, max_len) <<
" |\n";
246 std::cout <<
"+" << std::string(max_len + 2,
'-') <<
"+\n";
251 const std::vector<std::pair<std::string, std::string>>& rows) {
257 size_t max_key_len = 0;
258 for (
const auto& [key, _] : rows) {
259 max_key_len = std::max(max_key_len, key.length());
265 for (
const auto& [key, value] : rows) {
267 << std::right << std::setw(static_cast<int>(max_key_len)) << key
279 std::string_view label) {
284 double progress =
static_cast<double>(current) /
static_cast<double>(total);
285 int filled =
static_cast<int>(progress * width);
286 int percent =
static_cast<int>(progress * 100.0);
288 std::cout <<
"\r" << label <<
": [";
290 for (
int i = 0; i < filled; ++i) {
294 for (
int i = filled; i < width; ++i) {
298 std::cout <<
"] " << std::setw(3) << percent <<
"% ("
299 << current <<
"/" << total <<
")" << std::flush;
303 std::cout <<
"\r" << std::string(kDefaultWidth,
' ') <<
"\r" << std::flush;
311 constexpr uint64_t KB = 1024;
312 constexpr uint64_t MB = KB * 1024;
313 constexpr uint64_t GB = MB * 1024;
315 std::ostringstream oss;
316 oss << std::fixed << std::setprecision(1);
319 oss << static_cast<double>(bytes) /
static_cast<double>(GB) <<
" GB";
320 }
else if (bytes >= MB) {
321 oss << static_cast<double>(bytes) /
static_cast<double>(MB) <<
" MB";
322 }
else if (bytes >= KB) {
323 oss << static_cast<double>(bytes) /
static_cast<double>(KB) <<
" KB";
325 oss << bytes <<
" B";
332 std::ostringstream oss;
333 oss << std::fixed << std::setprecision(1);
335 if (milliseconds >= 60000) {
336 oss << static_cast<double>(milliseconds) / 60000.0 <<
" min";
337 }
else if (milliseconds >= 1000) {
338 oss << static_cast<double>(milliseconds) / 1000.0 <<
" s";
340 oss << milliseconds <<
" ms";
346auto center_text(std::string_view text,
size_t width) -> std::string {
347 if (text.length() >= width) {
348 return std::string{text.substr(0, width)};
351 size_t padding = (width - text.length()) / 2;
352 return std::string(padding,
' ') + std::string{text} +
353 std::string(width - padding - text.length(),
' ');
356auto truncate(std::string_view text,
size_t max_length,
357 std::string_view suffix) -> std::string {
358 if (text.length() <= max_length) {
359 return std::string{text};
362 if (max_length <= suffix.length()) {
363 return std::string{suffix.substr(0, max_length)};
366 return std::string{text.substr(0, max_length - suffix.length())} +
Represents a DICOM Dataset (ordered collection of Data Elements)
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.
Console output utilities for developer samples.
Compile-time constants for commonly used DICOM tags.
constexpr std::string_view to_string(vr_type vr) noexcept
Converts a vr_type to its two-character string representation.
constexpr const char * reset
Reset all formatting.
constexpr const char * red
constexpr const char * bold
Bold text.
constexpr const char * blue
constexpr const char * dim
Dim/faint text.
constexpr const char * yellow
constexpr const char * magenta
constexpr const char * green
constexpr const char * cyan
void print_dataset_summary(const core::dicom_dataset &ds)
Print a summary of a DICOM dataset.
void set_color_enabled(bool enabled)
Enable or disable color output globally.
void print_error(std::string_view message)
Print an error message.
void print_table(std::string_view title, const std::vector< std::pair< std::string, std::string > > &rows)
Print a key-value table.
auto truncate(std::string_view text, size_t max_length, std::string_view suffix) -> std::string
Truncate a string to a maximum length.
void print_debug(std::string_view message)
Print a debug message.
auto supports_color() noexcept -> bool
Check if the terminal supports ANSI colors.
void print_progress(size_t current, size_t total, int width, std::string_view label)
Print a progress bar.
void print_header(std::string_view title)
Print a header/title with decorative border.
auto center_text(std::string_view text, size_t width) -> std::string
Center a string within a given width.
auto format_duration(uint64_t milliseconds) -> std::string
Format a duration in milliseconds.
auto format_bytes(uint64_t bytes) -> std::string
Format a byte size for human-readable display.
void print_info(std::string_view message)
Print an informational message.
void clear_line()
Clear the current line (for updating progress)
void print_success(std::string_view message)
Print a success message.
auto is_color_enabled() noexcept -> bool
Check if colors are currently enabled.
void print_dataset_elements(const core::dicom_dataset &ds, size_t max_value_length)
Print all elements in a DICOM dataset.
void print_section(std::string_view title)
Print a section header.
void print_box(const std::vector< std::string > &lines)
Print text in a decorative box.
void print_warning(std::string_view message)
Print a warning message.