draw_histogram.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /* Copyright 2016 Google Inc. All Rights Reserved.
  2. Author: zip753@gmail.com (Ivan Nikulin)
  3. Distributed under MIT license.
  4. See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
  5. */
  6. /* Backward reference visualization tool. Accepts file with backward references
  7. as an input and produces PGM image with histogram of those references. */
  8. #include <algorithm> /* min */
  9. #include <cassert>
  10. #include <cstring> /* memset */
  11. #include <cmath> /* log, round */
  12. #include <cstdio> /* fscanf, fprintf */
  13. #include <cstdint>
  14. #include <gflags/gflags.h>
  15. using gflags::ParseCommandLineFlags;
  16. #include "third_party/absl/flags/flag.h"
  17. #include "read_dist.h"
  18. DEFINE_int32(height, 1000, "Height of the resulting histogam.");
  19. DEFINE_int32(width, 8000, "Width of the resulting histogam.");
  20. DEFINE_int32(size, 1e8, "Size of the compressed file.");
  21. DEFINE_int32(brotli_window, -1, "Size of brotli window in bits.");
  22. DEFINE_uint64(min_distance, 0, "Minimum distance.");
  23. DEFINE_uint64(max_distance, 1 << 30, "Maximum distance.");
  24. DEFINE_bool(with_copies, false, "True if input contains copy length.");
  25. DEFINE_bool(simple, false, "True if using only black and white pixels.");
  26. DEFINE_bool(linear, false, "True if using linear distance mapping.");
  27. DEFINE_uint64(skip, 0, "Number of bytes to skip.");
  28. inline double DistanceTransform(double x) {
  29. static bool linear = absl::GetFlag(FLAGS_linear);
  30. if (linear) {
  31. return x;
  32. } else {
  33. /* Using log^2 scale because log scale produces big white gap at the bottom
  34. of image. */
  35. return log(x) * log(x);
  36. }
  37. }
  38. /* Mapping pixel density on arc function to increase contrast. */
  39. inline double DensityTransform(double x) {
  40. double z = 255 - x;
  41. return sqrt(255 * 255 - z * z);
  42. }
  43. inline int GetMaxDistance() { return absl::GetFlag(FLAGS_max_distance); }
  44. void AdjustPosition(int* pos) {
  45. static uint32_t offset = 0;
  46. static int last = 0;
  47. static uint32_t window_size = (1 << absl::GetFlag(FLAGS_brotli_window));
  48. assert(*pos >= 0 && *pos < window_size);
  49. if (*pos < last) {
  50. offset += window_size;
  51. }
  52. last = *pos;
  53. *pos += offset;
  54. }
  55. void BuildHistogram(FILE* fin, int** histo) {
  56. int height = absl::GetFlag(FLAGS_height);
  57. int width = absl::GetFlag(FLAGS_width);
  58. int skip = absl::GetFlag(FLAGS_skip);
  59. size_t min_distance = absl::GetFlag(FLAGS_min_distance);
  60. printf("height = %d, width = %d\n", height, width);
  61. for (int i = 0; i < height; i++) {
  62. for (int j = 0; j < width; j++) {
  63. histo[i][j] = 0;
  64. }
  65. }
  66. int max_pos = absl::GetFlag(FLAGS_size) - skip;
  67. double min_dist = min_distance > 0 ? DistanceTransform(min_distance) : 0;
  68. double max_dist = DistanceTransform(GetMaxDistance()) - min_dist;
  69. int copy, pos, distance, x, y;
  70. double dist;
  71. while (ReadBackwardReference(fin, &copy, &pos, &distance)) {
  72. if (pos == -1) continue; // In case when only insert is present.
  73. if (distance < min_distance || distance >= GetMaxDistance()) continue;
  74. if (absl::GetFlag(FLAGS_brotli_window) != -1) {
  75. AdjustPosition(&pos);
  76. }
  77. if (pos >= skip && distance <= pos) {
  78. pos -= skip;
  79. if (pos >= max_pos) break;
  80. dist = DistanceTransform(static_cast<double>(distance)) - min_dist;
  81. x = std::min(static_cast<int>(round(dist / max_dist * height)),
  82. height - 1);
  83. y = 1ul * pos * width / max_pos;
  84. if (!(y >= 0 && y < width)) {
  85. printf("pos = %d, max_pos = %d, y = %d\n", pos, max_pos, y);
  86. assert(y >= 0 && y < width);
  87. }
  88. if (absl::GetFlag(FLAGS_with_copies)) {
  89. int right = 1ul * (pos + copy - 1) * width / max_pos;
  90. if (right < 0) {
  91. printf("pos = %d, distance = %d, copy = %d, y = %d, right = %d\n",
  92. pos, distance, copy, y, right);
  93. assert(right >= 0);
  94. }
  95. if (y == right) {
  96. histo[x][y] += copy;
  97. } else {
  98. int pos2 = static_cast<int>(ceil(1.0 * (y + 1) * max_pos / width));
  99. histo[x][y] += pos2 - pos;
  100. for (int i = y + 1; i < right && i < width; ++i) {
  101. histo[x][i] += max_pos / width; // Sometimes 1 more, but who cares.
  102. }
  103. // Make sure the match doesn't go beyond the image.
  104. if (right < width) {
  105. pos2 = static_cast<int>(ceil(1.0 * right * max_pos / width));
  106. histo[x][right] += pos + copy - 1 - pos2 + 1;
  107. }
  108. }
  109. } else {
  110. histo[x][y]++;
  111. }
  112. }
  113. }
  114. }
  115. void ConvertToPixels(int** histo, uint8_t** pixel) {
  116. int height = absl::GetFlag(FLAGS_height);
  117. int width = absl::GetFlag(FLAGS_width);
  118. int maxs = 0;
  119. for (int i = 0; i < height; i++) {
  120. for (int j = 0; j < width; j++) {
  121. if (maxs < histo[i][j]) maxs = histo[i][j];
  122. }
  123. }
  124. bool simple = absl::GetFlag(FLAGS_simple);
  125. double max_histo = static_cast<double>(maxs);
  126. for (int i = 0; i < height; i++) {
  127. for (int j = 0; j < width; j++) {
  128. if (simple) {
  129. pixel[i][j] = histo[i][j] > 0 ? 0 : 255;
  130. } else {
  131. pixel[i][j] = static_cast<uint8_t>(
  132. 255 - DensityTransform(histo[i][j] / max_histo * 255));
  133. }
  134. }
  135. }
  136. }
  137. void DrawPixels(uint8_t** pixel, FILE* fout) {
  138. int height = absl::GetFlag(FLAGS_height);
  139. int width = absl::GetFlag(FLAGS_width);
  140. fprintf(fout, "P5\n%d %d\n255\n", width, height);
  141. for (int i = height - 1; i >= 0; i--) {
  142. fwrite(pixel[i], 1, width, fout);
  143. }
  144. }
  145. int main(int argc, char* argv[]) {
  146. base::ParseCommandLine(&argc, &argv);
  147. if (argc != 3) {
  148. printf("usage: draw_histogram.cc data output_file\n");
  149. return 1;
  150. }
  151. int height = absl::GetFlag(FLAGS_height);
  152. int width = absl::GetFlag(FLAGS_width);
  153. FILE* fin = fopen(argv[1], "r");
  154. FILE* fout = fopen(argv[2], "wb");
  155. if (fin != nullptr && fout != nullptr) {
  156. uint8_t** pixel = new uint8_t*[height];
  157. int** histo = new int*[height];
  158. for (int i = 0; i < height; i++) {
  159. pixel[i] = new uint8_t[width];
  160. histo[i] = new int[width];
  161. }
  162. BuildHistogram(fin, histo);
  163. ConvertToPixels(histo, pixel);
  164. DrawPixels(pixel, fout);
  165. }
  166. if (fin) fclose(fin);
  167. if (fout) fclose(fout);
  168. return 0;
  169. }