Commit b0465300 authored by twanvl's avatar twanvl

Fixed some corner cases in the rotation code (rotation + scaling + stretching)

parent fb42f335
...@@ -45,11 +45,11 @@ void sharp_resample_and_clip(const Image& img_in, Image& img_out, wxRect rect, i ...@@ -45,11 +45,11 @@ void sharp_resample_and_clip(const Image& img_in, Image& img_out, wxRect rect, i
/// Draw text by first drawing it using a larger font and then downsampling it /// Draw text by first drawing it using a larger font and then downsampling it
/** optionally rotated by an angle. /** optionally rotated by an angle.
* rect = rectangle to draw in * rect = rectangle to draw in
* stretch_x = amount to stretch horizontally after drawing * stretch = amount to stretch in the direction of the text after drawing
* (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right * (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right
*/ */
void draw_resampled_text(DC& dc, const RealRect& rect, double stretch_x, int wc, int hc, int angle, const String& text, int blur_radius = 0, int repeat = 1); void draw_resampled_text(DC& dc, const RealRect& rect, double stretch, int wc, int hc, int angle, const String& text, int blur_radius = 0, int repeat = 1);
// scaling factor to use when drawing resampled text // scaling factor to use when drawing resampled text
extern const int text_scaling; extern const int text_scaling;
......
...@@ -20,8 +20,6 @@ const int text_scaling = 4; ...@@ -20,8 +20,6 @@ const int text_scaling = 4;
// Downsamples the red channel of the input image to the alpha channel of the output image // Downsamples the red channel of the input image to the alpha channel of the output image
// img_in must be text_scaling times as large as img_out // img_in must be text_scaling times as large as img_out
void downsample_to_alpha(Image& img_in, Image& img_out) { void downsample_to_alpha(Image& img_in, Image& img_out) {
assert(img_in.GetHeight() == img_out.GetHeight() * text_scaling);
Byte* temp = nullptr; Byte* temp = nullptr;
Byte* in = img_in.GetData(); Byte* in = img_in.GetData();
Byte* out = img_in.GetData(); Byte* out = img_in.GetData();
...@@ -74,13 +72,46 @@ void downsample_to_alpha(Image& img_in, Image& img_out) { ...@@ -74,13 +72,46 @@ void downsample_to_alpha(Image& img_in, Image& img_out) {
img_out.InitAlpha(); img_out.InitAlpha();
out = img_out.GetAlpha(); out = img_out.GetAlpha();
int line_size = img_out.GetWidth(); int line_size = img_out.GetWidth();
for (int y = 0 ; y < img_out.GetHeight() ; ++y) { int h = img_out.GetHeight();
for (int x = 0 ; x < line_size ; ++x) { if (img_in.GetHeight() == h * text_scaling) {
int total = 0; // no stretching
for (int j = 0 ; j < text_scaling ; ++j) { for (int y = 0 ; y < h ; ++y) {
total += in[x + line_size * (j + text_scaling * y)]; for (int x = 0 ; x < line_size ; ++x) {
int total = 0;
for (int j = 0 ; j < text_scaling ; ++j) {
total += in[x + line_size * (j + text_scaling * y)];
}
out[x + line_size * y] = total / text_scaling;
}
}
} else {
const int shift = 32-12-8; // => max size = 4096, max alpha = 255
int h1 = img_in.GetHeight(), w = img_out.GetWidth();
int out_fact = (h << shift) / h1; // how much to output for 256 input = 1 pixel
int out_rest = (h << shift) % h1;
for (int x = 0 ; x < w ; ++x) {
int in_rem = out_fact + out_rest;
for (int y = 0 ; y < h ; ++y) {
int out_rem = 1 << shift;
int tot = 0;
while (out_rem >= in_rem) {
// eat a whole input pixel
tot += *in * in_rem;
out_rem -= in_rem;
in_rem = out_fact;
in += line_size;
}
if (out_rem > 0) {
// eat a partial input pixel
tot += *in * out_rem;
in_rem -= out_rem;
}
// store
*out = tot >> shift;
out += line_size;
} }
out[x + line_size * y] = total / text_scaling; in = in - h1 * line_size + 1;
out = out - h * line_size + 1;
} }
} }
...@@ -113,7 +144,7 @@ void blur_image_alpha(Image& img) { ...@@ -113,7 +144,7 @@ void blur_image_alpha(Image& img) {
// optionally rotated by an angle // optionally rotated by an angle
// (w2,h2) = size of text // (w2,h2) = size of text
// (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right // (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right
void draw_resampled_text(DC& dc, const RealRect& rect, double stretch_x, int wc, int hc, int angle, const String& text, int blur_radius, int repeat) { void draw_resampled_text(DC& dc, const RealRect& rect, double stretch, int wc, int hc, int angle, const String& text, int blur_radius, int repeat) {
// enlarge slightly; some fonts are larger then the GetTextExtent tells us (especially italic fonts) // enlarge slightly; some fonts are larger then the GetTextExtent tells us (especially italic fonts)
int w = static_cast<int>(rect.width) + 3 + 2 * blur_radius, h = static_cast<int>(rect.height) + 1 + 2 * blur_radius; int w = static_cast<int>(rect.width) + 3 + 2 * blur_radius, h = static_cast<int>(rect.height) + 1 + 2 * blur_radius;
// determine sub-pixel position // determine sub-pixel position
...@@ -132,7 +163,9 @@ void draw_resampled_text(DC& dc, const RealRect& rect, double stretch_x, int wc, ...@@ -132,7 +163,9 @@ void draw_resampled_text(DC& dc, const RealRect& rect, double stretch_x, int wc,
mdc.SelectObject(wxNullBitmap); mdc.SelectObject(wxNullBitmap);
Image img_large = buffer.ConvertToImage(); Image img_large = buffer.ConvertToImage();
// step 2. sample down // step 2. sample down
Image img_small(stretch_x * w, h, false); if ((angle & 2) == 0) w *= stretch;
else h *= stretch;
Image img_small(w, h, false);
fill_image(img_small, dc.GetTextForeground()); fill_image(img_small, dc.GetTextForeground());
downsample_to_alpha(img_large, img_small); downsample_to_alpha(img_large, img_small);
// blur // blur
......
...@@ -19,14 +19,19 @@ DEFINE_EVENT_TYPE(EVENT_SIZE_CHANGE); ...@@ -19,14 +19,19 @@ DEFINE_EVENT_TYPE(EVENT_SIZE_CHANGE);
// ----------------------------------------------------------------------------- : CardViewer // ----------------------------------------------------------------------------- : CardViewer
CardViewer::CardViewer(Window* parent, int id, long style) CardViewer::CardViewer(Window* parent, int id, long style)
: wxControl(parent, id, wxDefaultPosition, wxDefaultSize, style | wxNO_FULL_REPAINT_ON_RESIZE) : wxControl(parent, id, wxDefaultPosition, wxDefaultSize, style)
, up_to_date(false) , up_to_date(false)
{} {}
wxSize CardViewer::DoGetBestSize() const { wxSize CardViewer::DoGetBestSize() const {
wxSize ws = GetSize(), cs = GetClientSize(); wxSize ws = GetSize(), cs = GetClientSize();
if (set) { if (set) {
return (wxSize)getRotation().getExternalSize() + ws - cs; if (!stylesheet) stylesheet = set->stylesheet;
StyleSheetSettings& ss = settings.stylesheetSettingsFor(*stylesheet);
wxSize size(stylesheet->card_width * ss.card_zoom(), stylesheet->card_height * ss.card_zoom());
bool sideways = (ss.card_angle() & 2) != 0;
if (sideways) swap(size.x, size.y);
return size + ws - cs;
} }
return cs; return cs;
} }
...@@ -129,7 +134,7 @@ Rotation CardViewer::getRotation() const { ...@@ -129,7 +134,7 @@ Rotation CardViewer::getRotation() const {
if (!stylesheet) stylesheet = set->stylesheet; if (!stylesheet) stylesheet = set->stylesheet;
StyleSheetSettings& ss = settings.stylesheetSettingsFor(*stylesheet); StyleSheetSettings& ss = settings.stylesheetSettingsFor(*stylesheet);
int dx = GetScrollPos(wxHORIZONTAL), dy = GetScrollPos(wxVERTICAL); int dx = GetScrollPos(wxHORIZONTAL), dy = GetScrollPos(wxVERTICAL);
return Rotation(ss.card_angle(), stylesheet->getCardRect().move(-dx,-dy,0,0), ss.card_zoom(), true); return Rotation(ss.card_angle(), stylesheet->getCardRect().move(-dx,-dy,0,0), ss.card_zoom(), 1.0, true);
} }
// ----------------------------------------------------------------------------- : Event table // ----------------------------------------------------------------------------- : Event table
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment