blob: ffdd3f24e14e33824eae79278a6e6b82bd0558e3 [file] [log] [blame]
#include "image_io/jpeg/jpeg_segment_lister.h"
#include <iomanip>
#include <sstream>
#include <string>
#include "image_io/jpeg/jpeg_marker.h"
#include "image_io/jpeg/jpeg_scanner.h"
#include "image_io/jpeg/jpeg_segment.h"
namespace photos_editing_formats {
namespace image_io {
/// The width of the type column.
constexpr size_t kTypeWidth = 5;
/// The width of the number columns.
constexpr size_t kNumWidth = 12;
/// The number of bytes to dump from each segment.
constexpr size_t kDumpCount = 16;
/// The width of the ascii dump column, including the surrounding [] brackets.
constexpr size_t kAscWidth = kDumpCount + 2;
/// The width of the hex dump column, including the surrounding [] brackets.
constexpr size_t kHexWidth = 2 * kDumpCount + 2;
using std::string;
using std::stringstream;
namespace {
/// @param value The value to convert to a string.
/// @return The value paraemter as a string of length kNumWidth.
string Size2String(size_t value) {
stringstream stream;
stream << std::setw(kNumWidth) << std::right << value;
return stream.str();
}
/// @param value The value to convert to a hex string.
/// @return The value paraemter as a hex string of length kNumWidth.
string Size2HexString(size_t value) {
stringstream stream;
stream << std::hex << std::uppercase << std::setw(kNumWidth) << std::right
<< value;
return stream.str();
}
/// @param str The string to add brackets to.
/// @return The str value enclosed by square brackets.
string BracketedString(const string& str) {
stringstream stream;
stream << '[' << str << ']';
return stream.str();
}
/// @param str The string to center.
/// @param width The width to center the string in.
/// @return A string with leading/trailing spaces added so that it is centered.
string CenteredString(const string& str, size_t width) {
if (str.length() >= width) {
return str;
}
size_t spacing = width - str.length();
size_t leading = spacing / 2;
size_t trailing = spacing - leading;
return string(leading, ' ') + str + string(trailing, ' ');
}
/// @param type The type value of the segment. If this value is empty, then a
/// divider line with dashes is created.
/// @param begin The begin value of the segment.
/// @param count The count (size) of the segment.
/// @param hex_string The hex dump string of the segment.
/// @param asc_string The ascii dump string of the segment.
/// @return A line with the various parameters properly spaced.
string SegmentLine(string type, string begin, string count, string hex_string,
string asc_string) {
if (type.empty()) {
type = string(kTypeWidth, '-');
begin = count = string(kNumWidth, '-');
hex_string = string(kHexWidth, '-');
asc_string = string(kAscWidth, '-');
}
stringstream line_stream;
line_stream << std::setw(kTypeWidth) << std::left << type << " "
<< std::setw(kNumWidth) << std::right << begin << " "
<< std::setw(kNumWidth) << std::right << count << " "
<< std::setw(kHexWidth) << std::right << hex_string << " "
<< std::setw(kAscWidth) << std::right << asc_string;
return line_stream.str();
}
/// @param type The type value of the summary. If this value is empty, then a
/// divider line with dashes is created.
/// @param count The number of the segments of the given type.
/// @return A line with the parameters properly spaced.
string SummaryLine(string type, string count) {
if (type.empty()) {
type = string(kTypeWidth, '-');
count = string(kNumWidth, '-');
}
stringstream line_stream;
line_stream << std::setw(kTypeWidth) << std::left << type << " "
<< std::setw(kNumWidth) << std::right << count;
return line_stream.str();
}
} // namespace
JpegSegmentLister::JpegSegmentLister()
: marker_type_counts_(kJpegMarkerArraySize, 0) {}
void JpegSegmentLister::Start(JpegScanner* scanner) {
scanner->UpdateInterestingMarkerFlags(JpegMarker::Flags().set());
string divider_line = SegmentLine("", "", "", "", "");
lines_.push_back(divider_line);
lines_.push_back(SegmentLine("Type", "Offset", "Payload Size",
CenteredString("Hex Payload", kHexWidth),
CenteredString("Ascii Payload", kAscWidth)));
lines_.push_back(divider_line);
}
void JpegSegmentLister::Process(JpegScanner* scanner,
const JpegSegment& segment) {
JpegMarker marker = segment.GetMarker();
string hex_payload, ascii_payload;
++marker_type_counts_[marker.GetType()];
segment.GetPayloadHexDumpStrings(kDumpCount, &hex_payload, &ascii_payload);
lines_.push_back(SegmentLine(
marker.GetName(), Size2HexString(segment.GetBegin()),
Size2HexString(segment.GetEnd() - segment.GetBegin() - 2),
BracketedString(hex_payload), BracketedString(ascii_payload)));
}
void JpegSegmentLister::Finish(JpegScanner* scanner) {
lines_.push_back("");
string divider_line = SummaryLine("", "");
lines_.push_back(divider_line);
lines_.push_back(SummaryLine("Type", "Count"));
lines_.push_back(divider_line);
int total_segments = 0;
for (int type = 0; type < kJpegMarkerArraySize; ++type) {
int count = marker_type_counts_[type];
if (count) {
total_segments += count;
lines_.push_back(
SummaryLine(JpegMarker(type).GetName(), Size2String(count)));
}
}
lines_.push_back(divider_line);
lines_.push_back(SummaryLine("TOTAL", Size2String(total_segments)));
}
} // namespace image_io
} // namespace photos_editing_formats