1 /* Copyright © 2009-2019 Jakub Wilk <jwilk@jwilk.net>
2 *
3 * This file is part of pdf2djvu.
4 *
5 * pdf2djvu is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * pdf2djvu is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 */
14
15 #include "pdf-dpi.hh"
16
17 #include <algorithm>
18 #include <cmath>
19 #include <limits>
20
21 #include "pdf-backend.hh"
22
23 class DpiGuessDevice : public pdf::OutputDevice
24 {
25 protected:
26 double min_;
27 double max_;
28 void process_image(pdf::gfx::State *state, int width, int height);
29
drawImageMask(pdf::gfx::State * state,pdf::Object * object,pdf::Stream * stream,int width,int height,bool invert,bool interpolate,bool inline_image)30 virtual void drawImageMask(pdf::gfx::State *state, pdf::Object *object, pdf::Stream *stream, int width, int height,
31 bool invert, bool interpolate, bool inline_image)
32 {
33 this->process_image(state, width, height);
34 }
35
36 #if POPPLER_VERSION >= 8200
drawImage(pdf::gfx::State * state,pdf::Object * object,pdf::Stream * stream,int width,int height,pdf::gfx::ImageColorMap * color_map,bool interpolate,const int * mask_colors,bool inline_image)37 virtual void drawImage(pdf::gfx::State *state, pdf::Object *object, pdf::Stream *stream, int width, int height,
38 pdf::gfx::ImageColorMap *color_map, bool interpolate, const int *mask_colors, bool inline_image)
39 #else
40 virtual void drawImage(pdf::gfx::State *state, pdf::Object *object, pdf::Stream *stream, int width, int height,
41 pdf::gfx::ImageColorMap *color_map, bool interpolate, int *mask_colors, bool inline_image)
42 #endif
43 {
44 this->process_image(state, width, height);
45 }
46
drawMaskedImage(pdf::gfx::State * state,pdf::Object * object,pdf::Stream * stream,int width,int height,pdf::gfx::ImageColorMap * color_map,bool interpolate,pdf::Stream * mask_stream,int mask_width,int mask_height,bool mask_invert,bool mask_interpolate)47 virtual void drawMaskedImage(pdf::gfx::State *state, pdf::Object *object, pdf::Stream *stream, int width, int height,
48 pdf::gfx::ImageColorMap *color_map, bool interpolate,
49 pdf::Stream *mask_stream, int mask_width, int mask_height, bool mask_invert, bool mask_interpolate)
50 {
51 this->process_image(state, width, height);
52 this->process_image(state, mask_width, mask_height);
53 }
54
drawSoftMaskedImage(pdf::gfx::State * state,pdf::Object * object,pdf::Stream * stream,int width,int height,pdf::gfx::ImageColorMap * color_map,bool interpolate,pdf::Stream * mask_stream,int mask_width,int mask_height,pdf::gfx::ImageColorMap * mask_color_map,bool mask_interpolate)55 virtual void drawSoftMaskedImage(pdf::gfx::State *state, pdf::Object *object, pdf::Stream *stream,
56 int width, int height, pdf::gfx::ImageColorMap *color_map, bool interpolate,
57 pdf::Stream *mask_stream, int mask_width, int mask_height,
58 pdf::gfx::ImageColorMap *mask_color_map, bool mask_interpolate)
59 {
60 this->process_image(state, width, height);
61 this->process_image(state, mask_width, mask_height);
62 }
63
interpretType3Chars()64 virtual bool interpretType3Chars()
65 {
66 return false;
67 }
upsideDown()68 virtual bool upsideDown()
69 {
70 return false;
71 }
useDrawChar()72 virtual bool useDrawChar()
73 {
74 return false;
75 }
76 public:
DpiGuessDevice()77 DpiGuessDevice()
78 {
79 this->reset();
80 }
reset()81 void reset()
82 {
83 this->max_ = 0.0;
84 this->min_ = std::numeric_limits<double>::infinity();
85 }
min() const86 double min() const { return this->min_; }
max() const87 double max() const { return this->max_; }
~DpiGuessDevice()88 virtual ~DpiGuessDevice()
89 { }
90 };
91
process_image(pdf::gfx::State * state,int width,int height)92 void DpiGuessDevice::process_image(pdf::gfx::State *state, int width, int height)
93 {
94 const double *ctm = state->getCTM();
95 double h_dpi = 72.0 * width / hypot(ctm[0], ctm[1]);
96 double v_dpi = 72.0 * height / hypot(ctm[2], ctm[3]);
97 this->min_ = std::min(this->min_, std::min(h_dpi, v_dpi));
98 this->max_ = std::max(this->max_, std::max(h_dpi, v_dpi));
99 }
100
Guesser(pdf::Document & document)101 pdf::dpi::Guesser::Guesser(pdf::Document &document)
102 : document(document)
103 {
104 DpiGuessDevice *guess_device = new DpiGuessDevice();
105 this->magic = guess_device;
106 }
107
~Guesser()108 pdf::dpi::Guesser::~Guesser()
109 {
110 DpiGuessDevice *guess_device = static_cast<DpiGuessDevice*>(this->magic);
111 delete guess_device;
112 }
113
operator [](int n)114 pdf::dpi::Guess pdf::dpi::Guesser::operator[](int n)
115 {
116 DpiGuessDevice *guess_device = static_cast<DpiGuessDevice*>(this->magic);
117 guess_device->reset();
118 this->document.displayPages(guess_device, n, n, 72, 72, 0, true, false, false);
119 double min = guess_device->min();
120 double max = guess_device->max();
121 if (max == 0.0)
122 throw pdf::dpi::NoGuess();
123 return pdf::dpi::Guess(min, max);
124 }
125
126 // vim:ts=2 sts=2 sw=2 et
127