| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- /* Copyright 2016 Google Inc. All Rights Reserved.
- Author: zip753@gmail.com (Ivan Nikulin)
- Distributed under MIT license.
- See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
- */
- /* Backward reference visualization tool. Accepts file with backward references
- as an input and produces PGM image with histogram of those references. */
- #include <algorithm> /* min */
- #include <cassert>
- #include <cstring> /* memset */
- #include <cmath> /* log, round */
- #include <cstdio> /* fscanf, fprintf */
- #include <cstdint>
- #include <gflags/gflags.h>
- using gflags::ParseCommandLineFlags;
- #include "third_party/absl/flags/flag.h"
- #include "read_dist.h"
- DEFINE_int32(height, 1000, "Height of the resulting histogam.");
- DEFINE_int32(width, 8000, "Width of the resulting histogam.");
- DEFINE_int32(size, 1e8, "Size of the compressed file.");
- DEFINE_int32(brotli_window, -1, "Size of brotli window in bits.");
- DEFINE_uint64(min_distance, 0, "Minimum distance.");
- DEFINE_uint64(max_distance, 1 << 30, "Maximum distance.");
- DEFINE_bool(with_copies, false, "True if input contains copy length.");
- DEFINE_bool(simple, false, "True if using only black and white pixels.");
- DEFINE_bool(linear, false, "True if using linear distance mapping.");
- DEFINE_uint64(skip, 0, "Number of bytes to skip.");
- inline double DistanceTransform(double x) {
- static bool linear = absl::GetFlag(FLAGS_linear);
- if (linear) {
- return x;
- } else {
- /* Using log^2 scale because log scale produces big white gap at the bottom
- of image. */
- return log(x) * log(x);
- }
- }
- /* Mapping pixel density on arc function to increase contrast. */
- inline double DensityTransform(double x) {
- double z = 255 - x;
- return sqrt(255 * 255 - z * z);
- }
- inline int GetMaxDistance() { return absl::GetFlag(FLAGS_max_distance); }
- void AdjustPosition(int* pos) {
- static uint32_t offset = 0;
- static int last = 0;
- static uint32_t window_size = (1 << absl::GetFlag(FLAGS_brotli_window));
- assert(*pos >= 0 && *pos < window_size);
- if (*pos < last) {
- offset += window_size;
- }
- last = *pos;
- *pos += offset;
- }
- void BuildHistogram(FILE* fin, int** histo) {
- int height = absl::GetFlag(FLAGS_height);
- int width = absl::GetFlag(FLAGS_width);
- int skip = absl::GetFlag(FLAGS_skip);
- size_t min_distance = absl::GetFlag(FLAGS_min_distance);
- printf("height = %d, width = %d\n", height, width);
- for (int i = 0; i < height; i++) {
- for (int j = 0; j < width; j++) {
- histo[i][j] = 0;
- }
- }
- int max_pos = absl::GetFlag(FLAGS_size) - skip;
- double min_dist = min_distance > 0 ? DistanceTransform(min_distance) : 0;
- double max_dist = DistanceTransform(GetMaxDistance()) - min_dist;
- int copy, pos, distance, x, y;
- double dist;
- while (ReadBackwardReference(fin, ©, &pos, &distance)) {
- if (pos == -1) continue; // In case when only insert is present.
- if (distance < min_distance || distance >= GetMaxDistance()) continue;
- if (absl::GetFlag(FLAGS_brotli_window) != -1) {
- AdjustPosition(&pos);
- }
- if (pos >= skip && distance <= pos) {
- pos -= skip;
- if (pos >= max_pos) break;
- dist = DistanceTransform(static_cast<double>(distance)) - min_dist;
- x = std::min(static_cast<int>(round(dist / max_dist * height)),
- height - 1);
- y = 1ul * pos * width / max_pos;
- if (!(y >= 0 && y < width)) {
- printf("pos = %d, max_pos = %d, y = %d\n", pos, max_pos, y);
- assert(y >= 0 && y < width);
- }
- if (absl::GetFlag(FLAGS_with_copies)) {
- int right = 1ul * (pos + copy - 1) * width / max_pos;
- if (right < 0) {
- printf("pos = %d, distance = %d, copy = %d, y = %d, right = %d\n",
- pos, distance, copy, y, right);
- assert(right >= 0);
- }
- if (y == right) {
- histo[x][y] += copy;
- } else {
- int pos2 = static_cast<int>(ceil(1.0 * (y + 1) * max_pos / width));
- histo[x][y] += pos2 - pos;
- for (int i = y + 1; i < right && i < width; ++i) {
- histo[x][i] += max_pos / width; // Sometimes 1 more, but who cares.
- }
- // Make sure the match doesn't go beyond the image.
- if (right < width) {
- pos2 = static_cast<int>(ceil(1.0 * right * max_pos / width));
- histo[x][right] += pos + copy - 1 - pos2 + 1;
- }
- }
- } else {
- histo[x][y]++;
- }
- }
- }
- }
- void ConvertToPixels(int** histo, uint8_t** pixel) {
- int height = absl::GetFlag(FLAGS_height);
- int width = absl::GetFlag(FLAGS_width);
- int maxs = 0;
- for (int i = 0; i < height; i++) {
- for (int j = 0; j < width; j++) {
- if (maxs < histo[i][j]) maxs = histo[i][j];
- }
- }
- bool simple = absl::GetFlag(FLAGS_simple);
- double max_histo = static_cast<double>(maxs);
- for (int i = 0; i < height; i++) {
- for (int j = 0; j < width; j++) {
- if (simple) {
- pixel[i][j] = histo[i][j] > 0 ? 0 : 255;
- } else {
- pixel[i][j] = static_cast<uint8_t>(
- 255 - DensityTransform(histo[i][j] / max_histo * 255));
- }
- }
- }
- }
- void DrawPixels(uint8_t** pixel, FILE* fout) {
- int height = absl::GetFlag(FLAGS_height);
- int width = absl::GetFlag(FLAGS_width);
- fprintf(fout, "P5\n%d %d\n255\n", width, height);
- for (int i = height - 1; i >= 0; i--) {
- fwrite(pixel[i], 1, width, fout);
- }
- }
- int main(int argc, char* argv[]) {
- base::ParseCommandLine(&argc, &argv);
- if (argc != 3) {
- printf("usage: draw_histogram.cc data output_file\n");
- return 1;
- }
- int height = absl::GetFlag(FLAGS_height);
- int width = absl::GetFlag(FLAGS_width);
- FILE* fin = fopen(argv[1], "r");
- FILE* fout = fopen(argv[2], "wb");
- if (fin != nullptr && fout != nullptr) {
- uint8_t** pixel = new uint8_t*[height];
- int** histo = new int*[height];
- for (int i = 0; i < height; i++) {
- pixel[i] = new uint8_t[width];
- histo[i] = new int[width];
- }
- BuildHistogram(fin, histo);
- ConvertToPixels(histo, pixel);
- DrawPixels(pixel, fout);
- }
- if (fin) fclose(fin);
- if (fout) fclose(fout);
- return 0;
- }
|