Skip to content

Add implementation note about calculation of region and size for tiles#250

Merged
jpstroop merged 1 commit intoIIIF:masterfrom
zimeon:tiles_region_size
Jun 28, 2014
Merged

Add implementation note about calculation of region and size for tiles#250
jpstroop merged 1 commit intoIIIF:masterfrom
zimeon:tiles_region_size

Conversation

@zimeon
Copy link
Copy Markdown
Member

@zimeon zimeon commented Jun 28, 2014

Implementation note I promised for #225

I don't recall whether we'd thought of doing this in the same document or as a separate one, I have done it inline and I think it is OK.

There are choices to be made in implementation (e.g. what size image do you return for a 11x11 image at scale 2? Is it 5x5 or 6x6? Seems that "tradition" might dictate 6x6 but that is just one possible choice) so this isn't the only way to do the calculation. In order to be clearcut I have an integer-only algorithm expressed as Python code which I've tested quite carefully. One could make this shorter using Python's ternary/one-line "if" but I think that is less clear, especially for non-Python folks:

    # Calculate region parameters /xr,yr,wr,hr/ 
    xr = n*tw*s 
    yr = m*th*s
    wr = (tw*s) if (xr + tw*s <= width) else (width - xr)
    hr = (th*s) if (yr + th*s <= height) else (height - yr)
    # Calculate size parameters /ws,hs/
    s2 = s/2 #use to implement rounding with integer arithmetic
    ws = tw if (xr + tw*s <= width) else (width - xr + s2) / s
    hs = th if (yr + th*s <= height) else (height - yr + s2) / s

The other issue is that where is image API is implemented following the SHOULD of truncating if a region goes over the edge, then one doesn't really need to calculate special region parameters. However, the numbers are needed for the size parameter calculation and by calculating region also one has something that should work with all implementations.

@jpstroop
Copy link
Copy Markdown
Member

I'm OK with this being inline. It integer arithmetic OK? I think I've been doing math.ceil() for everything in Loris.

@jpstroop
Copy link
Copy Markdown
Member

@zimeon
Copy link
Copy Markdown
Member Author

zimeon commented Jun 28, 2014

Hmmm, Math.ceil() is an interesting choice, you always round up -- will have to think about that a little, but at least I know why it didn't always match my static file calculation ;-) The beauty of integer arithmetic is that is not (well, less frequently) implementation dependent.

@jpstroop
Copy link
Copy Markdown
Member

If I recall correctly, I decided to do ceil based on this:

https://github.com/openzoom/deepzoom.py/blob/develop/deepzoom.py

which makes DZI tiles for OSd.

@zimeon
Copy link
Copy Markdown
Member Author

zimeon commented Jun 28, 2014

I've not been able to reason whether rounding up (ceil) or rounding to nearest (as I have) is really best. My gut says nearest but I do see where you got it from in deepzoom...

I can, however, replicate/verify the OSD algorithm using integer arithmetic. My conversion of the JavaScript to python is:

def tile_params_float_ceil(width,height,n,m,s,tw,th):
    # Calculate using the algorithm that OSD uses
    # https://github.com/openseadragon/openseadragon/blob/master/src/iiif1_1tilesource.js#L149-L190
    scale = 1.0/s
    levelWidth = ceil( width * scale )
    levelHeight = ceil( height * scale )
    iiifTileSizeWidth = ceil ( tw / scale )
    iiifTileSizeHeight = ceil( th / scale )
    #if ( levelWidth <  && levelHeight < this.tile_height ){
    #        iiifSize = levelWidth + ",";
    #        iiifRegion = 'full';
    #} else {
    iiifTileX = n * iiifTileSizeWidth
    iiifTileY = m * iiifTileSizeHeight
    iiifTileW = min( iiifTileSizeWidth, width - iiifTileX )
    iiifTileH = min( iiifTileSizeHeight, height - iiifTileY )
    iiifSizeX = ceil( iiifTileW * scale )
    iiifSizeY = ceil( iiifTileH * scale )
    return( iiifTileX, iiifTileY, iiifTileW, iiifTileH, iiifSizeX, iiifSizeY )

(For comparison I have calculated an iiifSizeX and iiifSizeY instead of using just iiifSize for /w,/ (which isn't canonical by our current spec BTW).)

And then for the integer version one just changes my previous code in the ws, hs lines (and remove the need for s2), giving:

def tile_params_int_ceil(width,height,n,m,s,tw,th):
    # Integer calculation but always round up rather than to nearest
    #
    # Calculate region parameters /xr,yr,wr,hr/ 
    xr = n*tw*s 
    yr = m*th*s
    wr = (tw*s) if (xr + tw*s <= width) else (width - xr)
    hr = (th*s) if (yr + th*s <= height) else (height - yr)
    # Calculate size parameters /ws,hs/
    ws = tw if (xr + tw*s <= width) else (width - xr + s - 1 ) / s
    hs = th if (yr + th*s <= height) else (height - yr + s - 1 ) / s
    return(xr,yr,wr,hr,ws,hs)

I've compared the resulting parameters for quite a range of tiles, image sizes etc.. and have 100% agreement.

@jpstroop
Copy link
Copy Markdown
Member

So the OSd/IIIF algorithm has gone from Python -> Javascript -> Python. 😄.

Happy to leave it as is.

jpstroop added a commit that referenced this pull request Jun 28, 2014
Add implementation note about calculation of region and size for tiles
@jpstroop jpstroop merged commit 5c5aecd into IIIF:master Jun 28, 2014
zimeon added a commit to zimeon/iiif.io that referenced this pull request Jun 30, 2014
@zimeon zimeon deleted the tiles_region_size branch June 30, 2014 02:36
zimeon added a commit to zimeon/iiif.io that referenced this pull request Jun 30, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants