Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEV-974: support different GIF sizes #26

Merged
merged 23 commits into from
Mar 8, 2022
Merged

Conversation

torbensky
Copy link
Collaborator

@torbensky torbensky commented Mar 1, 2022

This PR updates the rendering to support any GIF size. Previously the GIF size was determined by the board size.

Now, GIF size parameters can be passed and the renderer will centre the board within the GIF. It will maximise the size of the board such that the board squares fill up as much of the width/height as they can without being clipped. This logic is able to handle non-square boards.

Three new API methods have been added:

  • GET /games/<GAME_ID>/<SIZE>.gif
  • GET /games/<GAME_ID>/frames/<FRAME>/SIZE>.gif
  • GET /games/<GAME_ID>/frames/<FRAME>.txt

Where <SIZE> is a path parameter expecting the format <WIDTH>x<HEIGHT>.

In order to maintain backwards-compatibility with the legacy GIF API methods, the old calculations are preserved for when a GIF size is not specified. That logic is GIF width = <board width> * 20 + <board border> * 2 and GIF height = <board height> * 20 + <board border> * 2. For example, a 11x11 board would default to creating a 224x224 GIF, and a 19x19 board defaults to creating a 384x384 GIF.

While the underlying logic is able to support any size, for practical reasons the API will only allow a discrete set of GIF sizes. This is because:

  • An upper bound is important to prevent massively large GIFs (the file size of GIFs grows quickly with resolution and so does the processing time required to generate them).
  • A lower bound prevents GIFs which are not visually useful (below a certain point there is not enough resolution to distinguish important game features).
  • Discrete size options ensures caching is effective and reduces unnecessary computations for resolutions which are not meaningfully different

Because boards can be of varying dimensions, the allowed options will be based on the board dimensions. Those dimensions are currently:

  • 10 pixels per square (+ 4 pixels for border)
  • 20 pixels per square (+ 4 pixels for border)
  • 30 pixels per square (+ 4 pixels for border)
  • 40 pixels per square (+ 4 pixels for border)

Examples:

  • sizes allowed for 11x11 board are: 114x114, 224x224, 334x334 and 444x444
  • sizes allowed for 19x19 board are: 194x194, 384x384, 574x574 and 764x764
    • 574x574 and 764x764 would be disallowed by the 504x504 upper-limit for max resolution
  • etc...

Importantly, if use cases requiring other sizes are surfaced, these options can quickly be changed by simply changing the validation logic, since the underlying rendering handles any size.

Summary

  • Added new API methods which include parameters for GIF dimensions
  • Only a restricted subset of dimensions are allowed by the API
  • Board is centered when GIF size does not perfectly fit board dimensions
  • Within the core rendering logic, any GIF dimensions are supported, not just square ones

@torbensky torbensky added the enhancement New feature or request label Mar 1, 2022
@torbensky torbensky changed the title Dev 974 variable gif size 3 DEV-974: support different GIF sizes Mar 1, 2022
func drawWatermark(dc *gg.Context) {
watermarkImage, err := media.GetWatermarkPNG(dc.Width()*2/3, dc.Height()*2/3)
func drawWatermark(dc *boardContext) {

Copy link
Collaborator Author

@torbensky torbensky Mar 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was updated so it properly sizes the watermark according to the rendered board size, not just the size of the entire image (GIF). This ensures that the watermark stays within the board and that it doesn't get stretched in weird aspect ratios.

const maxGIFResolution = 504 * 504

// allowedPixelsPerSquare is a list of resolutions that the API will allow.
var allowedPixelsPerSquare = []int{10, 20, 30, 40}
Copy link
Collaborator Author

@torbensky torbensky Mar 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is what I came up with for restricting the GIF resolutions to limited options. Size 20 is the same as what we used to have hard-coded.

I realised that custom games can have any board size, so the restrictions would need to adapt to the board. This way every board size can have a few options that fit it well.

In addition to these options, there is the upper-limit of 504x504, which supersedes these options.

So larger boards won't have all these options because they'd exceed the max resolution limit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A 19x19 board would only have the options of 194x194 and 384x384.

@torbensky torbensky marked this pull request as ready for review March 3, 2022 00:32
Copy link
Contributor

@robbles robbles left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, and I tested the new and old endpoints locally with no problems.
Only "regression" is the slight change in size of the food pellets on the legacy GIF endpoints, which seems to be captured in the image test in the PR.

go.mod Outdated
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
goji.io v2.0.2+incompatible
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to avoid the newer v3.0.0 version of Goji? Development on the project looks paused for a few years, are you thinking to use the latest stable version because of that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually didn't notice this to be honest. This was the version that Go selected when I ran go get github.com/goji/goji

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated to v3 - nice job noticing that :D

- **574x574** (30 pixels per board square) (**Disallowed** because it exceeds `504x504`)
- **764x764** (40 pixels per board square) (**Disallowed** because it exceeds `504x504`)
- etc...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there's no common allowed board size, is the idea here that Play will need to do a calculation to generate the URL for a preset size in order to link the GIF for a game? e.g. we'd decide we want the "View GIF" button to link to the "30 pixels per board square" resolution, and generate the URL accordingly on the fly?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Do you think it would be better to have the parameters be the resolution per-square instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Do you think it would be better to have the dimension parameters be the resolution per-square instead? I feel like that would be better so Play wouldn't have to do those calculations.

I originally started with allowing any size. Then after some discussion, it seemed that limited options were a good idea, but there wasn't a good way to do this with static sizes, so I came up with this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure which is better, TBH. There's something about having the actual image size reflected in the URL that seems convenient. I don't think it's a big deal for play to include that calculation. Might be worth asking in #dev in case there's a use case I've missed here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I brought this up with the team this morning, and the consensus was that we haven't fully worked out the use cases for different GIF sizes, so we can just ship as-is for now. We may end up revisiting the endpoint design with something like small/medium/large mapping to fixed pixels-per-square values, which I think won't be incompatible with the routing approach used here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good Rob. Yeah I think the routing is quite flexible. It should be easy enough to adapt this to other parameters in the future.

@torbensky
Copy link
Collaborator Author

torbensky commented Mar 8, 2022

Looks good, and I tested the new and old endpoints locally with no problems.
Only "regression" is the slight change in size of the food pellets on the legacy GIF endpoints, which seems to be captured in the image test in the PR.

@robbles I changed the food size in this PR because I thought it didn't match with the Play UI. But maybe I got that wrong.

update: actually, it looks like it might be smaller than the Play board by just a wee bit. I think that might be due to rounding errors. Previously the Exporter code used integer math and divided the square size by 3 to get the food radius. Now it's using floating point math, so the circles are more exactly 1/3 the size of the square.

Does the Play board do integer rounding?

If so, I'm not sure which way should be considered correct, but I would normally assume the float math is better because we will have consistently sized food. The integer rounding will result in inconsistent food to square sizing.

@torbensky torbensky closed this Mar 8, 2022
@torbensky torbensky reopened this Mar 8, 2022
@robbles
Copy link
Contributor

robbles commented Mar 8, 2022

I think the new food size is good - didn't mean to imply it was worse, just the only difference I was able to spot.

@torbensky torbensky merged commit 093f9f6 into main Mar 8, 2022
@torbensky torbensky deleted the dev-974-variable-gif-size-3 branch March 8, 2022 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants