Skip to content

Commit ecf1fa8

Browse files
committed
Re-write of View::getResolution() to more robustly determine resolution level: handles images with levels either rounded up or down.
Update to IIIF.cc to more cleanly determine whether a request is for a tile or not and more accruately calculate normalized region sizes.
1 parent 38c919f commit ecf1fa8

File tree

4 files changed

+62
-54
lines changed

4 files changed

+62
-54
lines changed

ChangeLog

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
31/12/2015:
2+
- Re-write of View::getResolution() to more robustly determine resolution level: handles images with levels
3+
either rounded up or down.
4+
- Update to IIIF.cc to more cleanly determine whether a request is for a tile or not and more accruately
5+
calculate normalized region sizes.
6+
7+
18
28/12/2025:
29
- Eliminate warnings from GCC when using maximal compiler warning levels
310

src/IIIF.cc

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ void IIIF::run( Session* session, const string& src )
373373
int numOfTokens = 0;
374374

375375
// Our region parameters (always between 0 and 1)
376-
float region[4] = {0.0, 0.0, 1.0, 1.0};
376+
double region[4] = {0.0, 0.0, 1.0, 1.0};
377377

378378
// Region Parameter: { "full"; "square"; "x,y,w,h"; "pct:x,y,w,h" }
379379
if ( izer.hasMoreTokens() ){
@@ -420,8 +420,8 @@ void IIIF::run( Session* session, const string& src )
420420
}
421421

422422
// Define our denominators as our session view expects a ratio, not pixel values
423-
float wd = (float) width;
424-
float hd = (float) height;
423+
double wd = (double) width;
424+
double hd = (double) height;
425425

426426
if( isPCT ){
427427
wd = 100.0;
@@ -539,7 +539,7 @@ void IIIF::run( Session* session, const string& src )
539539
i.clear();
540540
i.str( sizeString.substr( pos + 1, string::npos ) );
541541
if ( !(i >> requested_height) ) throw invalid_argument( "invalid height" );
542-
}
542+
}
543543
}
544544

545545

@@ -738,15 +738,14 @@ void IIIF::run( Session* session, const string& src )
738738

739739

740740
// Determine whether this is a request for an individual tile which, therefore, coincides exactly with our tile boundaries
741-
if( ( session->view->maintain_aspect && (requested_res > 0) &&
742-
(view_left % tw == 0) && (view_top % th == 0) && // Left / top boundaries align with tile positions
743-
(requested_width == vtw) && (requested_height == vth) && // Request is for exact tile dimensions
744-
(session->view->getViewWidth() == vtw) && (session->view->getViewHeight() == vth) ) || // View size should also be identical to tile dimensions
745-
// For smallest resolution, image size can be given as equal or less than tile size or exactly equal to tile size
746-
( ( session->view->maintain_aspect && (requested_res == 0) ) &&
747-
( ( ((unsigned int) requested_width == im_width) && ((unsigned int) requested_height == im_height)) ||
748-
( ((unsigned int) requested_width == tw) && ((unsigned int) requested_height == th)) ) )
749-
){
741+
if(
742+
// Left / top boundaries align with tile positions
743+
(view_left % tw == 0) && (view_top % th == 0) &&
744+
// Request is for exact tile dimensions (taking into account edge tile sizes)
745+
(requested_width == vtw) && (requested_height == vth) &&
746+
// View size should also be identical to tile dimensions
747+
(session->view->getViewWidth() == vtw) && (session->view->getViewHeight() == vth)
748+
){
750749

751750
// Get the width and height for last row and column tiles
752751
unsigned int rem_x = im_width % tw;

src/View.cc

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,45 +23,47 @@
2323
using namespace std;
2424

2525

26-
/// Calculate optimal resolution for a given requested pixel dimension
27-
void View::calculateResolution( const std::vector<unsigned int>& dimensions,
28-
const unsigned int requested_size ){
29-
30-
int j;
31-
32-
// Make sure we have a minimum size
33-
unsigned int rs = (requested_size<min_size) ? min_size : requested_size;
34-
35-
// Find the resolution level closest but higher than the requested size
36-
for( j=0; j<(int)max_resolutions; j++ ){
37-
if( dimensions[j] < rs ) break;
38-
}
39-
40-
// Invert to convert to IIP resolutions (0=smallest) - note that we implicitly add 1 to get resolution higher than
41-
j = max_resolutions-j;
42-
43-
// Limit j to the maximum resolution
44-
if( j < 0 ) j = 0;
45-
if( j > (int)(max_resolutions-1) ) j = max_resolutions - 1;
46-
47-
// Only update value of resolution if our calculated resolution is greater than value that has already been set
48-
if( j > resolution ) resolution = j;
49-
}
50-
5126

5227
/// Calculate the optimal resolution and the size of this resolution for the requested view,
5328
/// taking into account any maximum size settings
5429
unsigned int View::getResolution( const std::vector<unsigned int>& widths, const std::vector<unsigned int>& heights ){
5530

56-
// Initialize our resolution to smallest available before calculating
57-
resolution = 0;
31+
int level;
5832

33+
// Get requested size - takes into account max size
5934
vector<unsigned int> requested_size = View::getRequestSize();
60-
View::calculateResolution( widths, round((float)requested_size[0]/(float)view_width) );
61-
View::calculateResolution( heights, round((float)requested_size[1]/(float)view_height) );
6235

63-
res_width = widths[max_resolutions-resolution-1];
64-
res_height = heights[max_resolutions-resolution-1];
36+
// Start from the smallest resolution size (last item in size array)
37+
for( level = (int) max_resolutions - 1; level >= 0; level-- ){
38+
39+
// Scaling factor (assume powers of 2)
40+
unsigned int factor = 1 << level;
41+
42+
// For some reason, this needs to be done in 2 steps with fw, fh first, otherwise rounding errors occur :-/
43+
float fw = (float) width * view_width;
44+
// For full width or height requests use the real level size.
45+
// Also add an epsilon to avoid floating-point rounding errors when using floor()
46+
unsigned int scaled_width = (view_width == 1.0) ? widths[level] : floor( (fw/factor) + numeric_limits<float>::epsilon() );
47+
float fh = (float) height * view_height;
48+
unsigned int scaled_height = (view_height == 1.0) ? heights[level] : floor( (fh/factor) + numeric_limits<float>::epsilon() );
49+
50+
// Note that we add 1px for the first checks to take into account differences between levels that have rounded up or down
51+
if( scaled_width <= (widths[level]+1) && scaled_height <= (heights[level]+1) &&
52+
// Skip check and avoid potential rounding errors if only a single dimension has been requested
53+
( requested_width == 0 ? true : scaled_width >= requested_size[0] ) &&
54+
( requested_height == 0 ? true : scaled_height >= requested_size[1] ) ){
55+
break; // Lowest resolution where conditions are met
56+
}
57+
}
58+
// Clamp to 0 if no matches
59+
if( level < 0 ) level = 0;
60+
61+
// Size of image at this level
62+
res_width = widths[level];
63+
res_height = heights[level];
64+
65+
// Store resolution as IIP resolution (0=smallest)
66+
resolution = max_resolutions - level - 1;
6567

6668
// Check if we need to limit to a smaller resolution due to our max size limit
6769
float scale = getScale();
@@ -119,29 +121,29 @@ float View::getScale(){
119121
}
120122

121123

122-
void View::setViewLeft( float x ) {
124+
void View::setViewLeft( double x ) {
123125
if( x > 1.0 ) view_left = 1.0;
124126
else if( x < 0.0 ) view_left = 0.0;
125127
else view_left = x;
126128
}
127129

128130

129-
void View::setViewTop( float y ) {
131+
void View::setViewTop( double y ) {
130132
if( y > 1.0 ) view_top = 1.0;
131133
else if( y < 0.0 ) view_top = 0.0;
132134
else view_top = y;
133135
}
134136

135137

136-
void View::setViewWidth( float w ) {
138+
void View::setViewWidth( double w ) {
137139
// Sanity check
138140
if( w > 1.0 ) view_width = 1.0;
139141
else if( w < 0.0 ) view_width = 0.0;
140142
else view_width = w;
141143
}
142144

143145

144-
void View::setViewHeight( float h ) {
146+
void View::setViewHeight( double h ) {
145147
// Sanity check
146148
if( h > 1.0 ) view_height = 1.0;
147149
else if( h < 0.0 ) view_height = 0.0;

src/View.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class View{
3939
private:
4040

4141
// Resolution independent x,y,w,h region viewport in range 0 -> 1.0
42-
float view_left, view_top, view_width, view_height; /// viewport
42+
double view_left, view_top, view_width, view_height; /// viewport
4343

4444
int resolution; ///< Requested resolution where 0 is smallest available
4545
unsigned int max_resolutions; ///< Total available resolutions
@@ -190,28 +190,28 @@ class View{
190190

191191
/// Set the left co-ordinate of the viewport
192192
/** @param x left resolution independent co-ordinate */
193-
void setViewLeft( float x );
193+
void setViewLeft( double x );
194194

195195

196196
/// Set the top co-ordinate of the viewport
197197
/** @param y top resolution independent co-ordinate */
198-
void setViewTop( float y );
198+
void setViewTop( double y );
199199

200200

201201
/// Set the width co-ordinate of the viewport
202202
/** @param w width resolution independent co-ordinate */
203-
void setViewWidth( float w );
203+
void setViewWidth( double w );
204204

205205

206206
/// Set the height co-ordinate of the viewport
207207
/** @param h height resolution independent co-ordinate */
208-
void setViewHeight( float h );
208+
void setViewHeight( double h );
209209

210210

211211
/// Return the view dimensions scaled to the full resolution of the image
212212
/** @return size view dimensions on the full resolution canvas packed into a vector */
213213
std::vector<float> getViewSize(){
214-
std::vector<float> size = { width*view_width, height*view_height };
214+
std::vector<float> size = { width*(float)view_width, height*(float)view_height };
215215
return size;
216216
};
217217

0 commit comments

Comments
 (0)