| #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 |