* [patch] background_image: image centering and scaling
@ 2008-08-29 1:46 Olaf Mandel
2008-08-29 14:56 ` Vesa Jääskeläinen
0 siblings, 1 reply; 10+ messages in thread
From: Olaf Mandel @ 2008-08-29 1:46 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1.1: Type: text/plain, Size: 2143 bytes --]
Hello,
on (some) computers with LCD monitors, the image is not automatically
scaled to full screen if the video mode is set to a lower resolution. So
the user has to set the gfxmode variable to the correct value in this
case. But then the background image provided by their distribution needs
to be rescaled by the user to fit the new screen resolution of grub.
It would be much preferable (IMO) to have grub2 rescale an existing
image automatically on loading. This seems to be the cleaner, more
sustainable solution: no extra files in the file system, works nicely
even if the user changes the screen resolution manually, ...
This patch adds two new functions to video/bitmap.c:
grub_video_bitmap_scale() and grub_video_bitmap_scale_keepaspect(). They
are called from term/gfxterm.c after reading in the bitmap in
grub_gfxterm_background_image_cmd(). At the moment, the scaling
algorithm used is very simple, no interpolation is used. But this should
be a good starting point to expand into smooth scaling later.
Additionally, this patch adds the ability to place the bitmap at any
position of the screen, not only in the top/left corner. This is done by
extending redraw_screen_rect() to also clear the areas to the left and
top of the image.
These changes can be controlled at by editing term/gfxterm.c: the three
preprocessor variables BITMAP_CENTERED, BITMAP_SCALED and
BITMAP_KEEPASPECTRATIO default to 1, but setting them to 0 restores the
old behavior.
This patch fixes one minor bug in grub_gfxterm_background_image_cmd():
the stored height of the bitmap was its width. This caused the screen to
not be cleared correctly in some cases.
TODO:
* Use a better scaling algorithm (linear or bi-linear interpolation).
* Change the scaling algorithm to work in-place. At the moment, a new
memory location is acquired, and the old one is freed after copying
(change malloc -> realloc).
Best regards,
Olaf Mandel
--
Olaf Mandel <olaf@mandel.name> <http://www.olaf.mandel.name/>
PGP key: 1024D/33398848 2002-09-19
Fingerprint: 0E33 BEA6 1A71 9C5E 62BD FC0E 99A7 D2C6 3339 8848
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: centering+scaling.diff --]
[-- Type: text/x-patch; name="centering+scaling.diff", Size: 9864 bytes --]
Index: video/bitmap.c
===================================================================
--- video/bitmap.c (revision 1832)
+++ video/bitmap.c (working copy)
@@ -245,6 +245,82 @@
return bitmap->data;
}
+grub_err_t
+grub_video_bitmap_scale (struct grub_video_bitmap **out,
+ struct grub_video_bitmap *in,
+ unsigned int width, unsigned int height)
+{
+ grub_err_t res;
+ unsigned int x, y;
+ unsigned int w, h;
+
+ if (!in)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid argument.");
+ w = in->mode_info.width;
+ h = in->mode_info.height;
+
+ res = grub_video_bitmap_create (out, width, height,
+ in->mode_info.blit_format);
+ if (res != GRUB_ERR_NONE)
+ return res;
+
+ /* This is a very simple scaling, just copying the pixel value of the
+ * pixel to the top / left of the correct position. */
+ for (y = 0; y < height; ++y)
+ {
+ unsigned int offsy = y * (*out)->mode_info.pitch;
+ unsigned int oldy;
+ unsigned int oldoffsy;
+
+ oldy = y * h / height;
+ oldoffsy = oldy * in->mode_info.pitch;
+
+ for (x = 0; x < width; ++x)
+ {
+ unsigned int offsx = x * in->mode_info.bytes_per_pixel;
+ unsigned int oldx;
+ unsigned int oldoffsx;
+
+ oldx = x * w / width;
+ oldoffsx = oldx * in->mode_info.bytes_per_pixel;
+
+ grub_memcpy ((char *)(*out)->data + offsy + offsx,
+ (char *)in->data + oldoffsy + oldoffsx,
+ in->mode_info.bytes_per_pixel);
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_video_bitmap_scale_keepaspect (struct grub_video_bitmap **out,
+ struct grub_video_bitmap *in,
+ unsigned int maxwidth,
+ unsigned int maxheight)
+{
+ unsigned int w;
+ unsigned int h;
+ unsigned int width = maxwidth;
+ unsigned int height = maxheight;
+
+ if (!in)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid argument.");
+ w = in->mode_info.width;
+ h = in->mode_info.height;
+
+ /* Is the new region wider than the old bitmap? Use products instead of
+ * fractions. */
+ if ( w * maxheight < maxwidth * h)
+ width = w * maxheight / h;
+
+ /* Is the new region higher than the old bitmap? */
+ if ( w * maxheight > maxwidth * h)
+ height = h * maxwidth / w;
+
+ return grub_video_bitmap_scale (out, in, width, height);
+}
+
/* Initialize bitmap module. */
GRUB_MOD_INIT(video_bitmap)
{
Index: include/grub/bitmap.h
===================================================================
--- include/grub/bitmap.h (revision 1832)
+++ include/grub/bitmap.h (working copy)
@@ -67,4 +67,12 @@
void *grub_video_bitmap_get_data (struct grub_video_bitmap *bitmap);
+grub_err_t grub_video_bitmap_scale (struct grub_video_bitmap **out,
+ struct grub_video_bitmap *in,
+ unsigned int width, unsigned int height);
+
+grub_err_t grub_video_bitmap_scale_keepaspect (struct grub_video_bitmap **out,
+ struct grub_video_bitmap *in,
+ unsigned int maxwidth,
+ unsigned int maxheight);
#endif /* ! GRUB_BITMAP_HEADER */
Index: ChangeLog
===================================================================
--- ChangeLog (revision 1832)
+++ ChangeLog (working copy)
@@ -1,3 +1,13 @@
+2008-08-28 Olaf Mandel <olaf@mandel.name>
+
+ * term/gfxterm.c: Correctly store height of background image, add
+ support for centering images on viewport (opposed to having them in
+ the upper-left corner). Use new scaling feature below.
+
+ * video/bitmap.c: Add ability to scale pictures to arbitrary
+ dimensions (very simple scaling at the moment, linear or bilinear
+ scaling would be better).
+
2008-08-28 Robert Millan <rmh@aybabtu.com>
* util/biosdisk.c (find_grub_drive): Declare missing `i' variable.
Index: term/gfxterm.c
===================================================================
--- term/gfxterm.c (revision 1832)
+++ term/gfxterm.c (working copy)
@@ -43,6 +43,10 @@
#define DEFAULT_NORMAL_COLOR 0x07
#define DEFAULT_HIGHLIGHT_COLOR 0x70
+#define BITMAP_CENTERED 1
+#define BITMAP_SCALED 1
+#define BITMAP_KEEPASPECTRATIO 1
+
struct grub_dirty_region
{
int top_left_x;
@@ -112,6 +116,8 @@
static struct grub_video_render_target *text_layer;
+static int bitmap_x;
+static int bitmap_y;
static unsigned int bitmap_width;
static unsigned int bitmap_height;
static struct grub_video_bitmap *bitmap;
@@ -513,43 +519,95 @@
{
/* Render bitmap as background. */
grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_REPLACE, x, y,
- x, y,
+ x - bitmap_x, y - bitmap_y,
width, height);
/* If bitmap is smaller than requested blit area, use background
color. */
color = virtual_screen.bg_color;
+ /* Fill top side of the bitmap (including corners) if needed. */
+ if ((int)y < bitmap_y)
+ {
+ int h = height;
+
+ if (y + h > bitmap_y)
+ {
+ h = bitmap_y - y;
+ }
+
+ /* Render background layer. */
+ grub_video_fill_rect (color, x, y, width, h);
+ }
+
+ /* Fill left side of the bitmap if needed. */
+ if ((x < bitmap_x) && (y < bitmap_y + bitmap_height)
+ && (y + height > bitmap_y))
+ {
+ int w = width;
+ int h = height;
+ unsigned int ty = y;
+
+ if (x + w > bitmap_x)
+ {
+ w = bitmap_x - x;
+ }
+
+ if (ty < bitmap_y)
+ {
+ h -= bitmap_y - ty;
+ ty = bitmap_y;
+ }
+
+ if (ty + h > bitmap_y + bitmap_height)
+ {
+ h = bitmap_y + bitmap_height - ty;
+ }
+
+ /* Render background layer. */
+ grub_video_fill_rect (color, x, ty, w, h);
+ }
+
/* Fill right side of the bitmap if needed. */
- if ((x + width >= bitmap_width) && (y < bitmap_height))
+ if ((x + width > bitmap_x + bitmap_width)
+ && (y < bitmap_y + bitmap_height) && (y + height > bitmap_y))
{
- int w = (x + width) - bitmap_width;
+ int w = width;
int h = height;
unsigned int tx = x;
+ unsigned int ty = y;
- if (y + height >= bitmap_height)
+ if (tx < bitmap_x + bitmap_width)
{
- h = bitmap_height - y;
+ w -= bitmap_x + bitmap_width - tx;
+ tx = bitmap_x + bitmap_width;
}
- if (bitmap_width > tx)
+ if (ty < bitmap_y)
{
- tx = bitmap_width;
+ h -= bitmap_y - ty;
+ ty = bitmap_y;
}
+ if (ty + h > bitmap_y + bitmap_height)
+ {
+ h = bitmap_y + bitmap_height - ty;
+ }
+
/* Render background layer. */
- grub_video_fill_rect (color, tx, y, w, h);
+ grub_video_fill_rect (color, tx, ty, w, h);
}
- /* Fill bottom side of the bitmap if needed. */
- if (y + height >= bitmap_height)
+ /* Fill bottom side of the bitmap (including corners) if needed. */
+ if (y + height > bitmap_y + bitmap_height)
{
- int h = (y + height) - bitmap_height;
+ int h = height;
unsigned int ty = y;
- if (bitmap_height > ty)
+ if (ty < bitmap_y + bitmap_height)
{
- ty = bitmap_height;
+ h -= bitmap_y + bitmap_height - ty;
+ ty = bitmap_y + bitmap_height;
}
/* Render background layer. */
@@ -1041,10 +1099,36 @@
/* If bitmap was loaded correctly, display it. */
if (bitmap)
{
+ /* Scale the bitmap if desired. There is the option of preserving
+ * the aspect ratio of the bitmap. */
+#if BITMAP_SCALED
+ struct grub_video_bitmap *scaled_bitmap = 0;
+# if BITMAP_KEEPASPECTRATIO
+ grub_video_bitmap_scale_keepaspect (&scaled_bitmap, bitmap,
+ mode_info.width, mode_info.height);
+# else
+ grub_video_bitmap_scale (&scaled_bitmap, bitmap,
+ mode_info.width, mode_info.height);
+# endif
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+ grub_video_bitmap_destroy (bitmap);
+ bitmap = scaled_bitmap;
+#endif
+
/* Determine bitmap dimensions. */
bitmap_width = grub_video_bitmap_get_width (bitmap);
- bitmap_height = grub_video_bitmap_get_width (bitmap);
+ bitmap_height = grub_video_bitmap_get_height (bitmap);
+ /* Either center bitmap or put it in upper left corner. */
+#if BITMAP_CENTERED
+ bitmap_x = ((int)mode_info.width-(int)bitmap_width)/2;
+ bitmap_y = ((int)mode_info.height-(int)bitmap_height)/2;
+#else
+ bitmap_x = 0;
+ bitmap_y = 0;
+#endif
+
/* Mark whole screen as dirty. */
dirty_region_reset ();
dirty_region_add (0, 0, mode_info.width, mode_info.height);
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [patch] background_image: image centering and scaling 2008-08-29 1:46 [patch] background_image: image centering and scaling Olaf Mandel @ 2008-08-29 14:56 ` Vesa Jääskeläinen 2008-08-29 15:17 ` Felix Zielcke ` (2 more replies) 0 siblings, 3 replies; 10+ messages in thread From: Vesa Jääskeläinen @ 2008-08-29 14:56 UTC (permalink / raw) To: The development of GRUB 2 Olaf Mandel wrote: > Hello, > > on (some) computers with LCD monitors, the image is not automatically > scaled to full screen if the video mode is set to a lower resolution. So > the user has to set the gfxmode variable to the correct value in this > case. But then the background image provided by their distribution needs > to be rescaled by the user to fit the new screen resolution of grub. > > It would be much preferable (IMO) to have grub2 rescale an existing > image automatically on loading. This seems to be the cleaner, more > sustainable solution: no extra files in the file system, works nicely > even if the user changes the screen resolution manually, ... > > This patch adds two new functions to video/bitmap.c: > grub_video_bitmap_scale() and grub_video_bitmap_scale_keepaspect(). They > are called from term/gfxterm.c after reading in the bitmap in > grub_gfxterm_background_image_cmd(). At the moment, the scaling > algorithm used is very simple, no interpolation is used. But this should > be a good starting point to expand into smooth scaling later. > > Additionally, this patch adds the ability to place the bitmap at any > position of the screen, not only in the top/left corner. This is done by > extending redraw_screen_rect() to also clear the areas to the left and > top of the image. > > These changes can be controlled at by editing term/gfxterm.c: the three > preprocessor variables BITMAP_CENTERED, BITMAP_SCALED and > BITMAP_KEEPASPECTRATIO default to 1, but setting them to 0 restores the > old behavior. > > This patch fixes one minor bug in grub_gfxterm_background_image_cmd(): > the stored height of the bitmap was its width. This caused the screen to > not be cleared correctly in some cases. > > TODO: > * Use a better scaling algorithm (linear or bi-linear interpolation). > * Change the scaling algorithm to work in-place. At the moment, a new > memory location is acquired, and the old one is freed after copying > (change malloc -> realloc). Hi Olaf, Thanks for your effort, but there is already code that does this, altought not committed yet. Colin D Bennett has worked under GSoC 2008 program to create graphical menu code which includes better scaler and another enhancements also relating to graphical terminal. So unfortunately your code cannot be used as is. You can have a sneak peak of the feature at address: http://grub.gibibit.com/ However, please wait that we have had enough time to integrate that completely before continuing to enhance it. (Should you do that) Next time, try to discuss it first before implementing ;) I will however look at if there are some ideas that you have provided what is still missing from new graphical menu implementation that should be there. Thanks, Vesa Jääskeläinen ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch] background_image: image centering and scaling 2008-08-29 14:56 ` Vesa Jääskeläinen @ 2008-08-29 15:17 ` Felix Zielcke 2008-08-30 5:11 ` Olaf Mandel 2008-08-30 12:05 ` Robert Millan 2 siblings, 0 replies; 10+ messages in thread From: Felix Zielcke @ 2008-08-29 15:17 UTC (permalink / raw) To: The development of GRUB 2 Am Freitag, den 29.08.2008, 17:56 +0300 schrieb Vesa Jääskeläinen: > Next time, try to discuss it first before implementing ;) Actually this is more my fault, because I hadn't Colin's GsoC project in mind. Shame on me :( He send a different patch to Debian BTS, related to this and then he just came up with the idea that GRUB should resize the picture itself. So I just told him to forward this and I even saw now that Robert did it too :) http://bugs.debian.org/495754 -- Felix Zielcke ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch] background_image: image centering and scaling 2008-08-29 14:56 ` Vesa Jääskeläinen 2008-08-29 15:17 ` Felix Zielcke @ 2008-08-30 5:11 ` Olaf Mandel 2008-08-30 15:00 ` Vesa Jääskeläinen 2008-08-31 15:46 ` Colin D Bennett 2008-08-30 12:05 ` Robert Millan 2 siblings, 2 replies; 10+ messages in thread From: Olaf Mandel @ 2008-08-30 5:11 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 879 bytes --] Vesa Jääskeläinen schrieb: -Snipp- > I will however look at if there are some ideas that you have provided > what is still missing from new graphical menu implementation that should > be there. -Snipp- Hello, thanks. I must admit to not looking at the source code for the project. Will scaling also be used for "simple" background_image commands? If yes and if the scaling does preserve the aspect ratio of the image, then the background picture is not necessarily in the upper left corner of the screen (an assumption in the code in grub2 trunk). I hope some version of the gfxmenu project finds its way into the trunk of the grub2 repository soon. :-) Best regards, Olaf -- Olaf Mandel <olaf@mandel.name> <http://www.olaf.mandel.name/> PGP key: 1024D/33398848 2002-09-19 Fingerprint: 0E33 BEA6 1A71 9C5E 62BD FC0E 99A7 D2C6 3339 8848 [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch] background_image: image centering and scaling 2008-08-30 5:11 ` Olaf Mandel @ 2008-08-30 15:00 ` Vesa Jääskeläinen 2008-08-30 18:57 ` colin 2008-08-31 15:46 ` Colin D Bennett 1 sibling, 1 reply; 10+ messages in thread From: Vesa Jääskeläinen @ 2008-08-30 15:00 UTC (permalink / raw) To: The development of GRUB 2 Olaf Mandel wrote: > thanks. I must admit to not looking at the source code for the project. > Will scaling also be used for "simple" background_image commands? If yes > and if the scaling does preserve the aspect ratio of the image, then the > background picture is not necessarily in the upper left corner of the > screen (an assumption in the code in grub2 trunk). Basically there is no background_image command anymore in new implementation. Idea is that you specify behavior in theme file. In theme file you could have attributes what is the scaling behavior (if it was not there already). > I hope some version of the gfxmenu project finds its way into the trunk > of the grub2 repository soon. :-) Me too :). It just needs to be fine tuned and then committed. We should receive sliced patches in here in near term. Colin will be on holiday for a while so don't hold your breath. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch] background_image: image centering and scaling 2008-08-30 15:00 ` Vesa Jääskeläinen @ 2008-08-30 18:57 ` colin 2008-08-30 19:07 ` Vesa Jääskeläinen 0 siblings, 1 reply; 10+ messages in thread From: colin @ 2008-08-30 18:57 UTC (permalink / raw) To: The development of GRUB 2 On Sat, 30 Aug 2008 18:00:27 +0300, Vesa Jääskeläinen <chaac@nic.fi> wrote: > Olaf Mandel wrote: >> thanks. I must admit to not looking at the source code for the project. >> Will scaling also be used for "simple" background_image commands? If yes >> and if the scaling does preserve the aspect ratio of the image, then the >> background picture is not necessarily in the upper left corner of the >> screen (an assumption in the code in grub2 trunk). > > Basically there is no background_image command anymore in new > implementation. Idea is that you specify behavior in theme file. In > theme file you could have attributes what is the scaling behavior (if it > was not there already). Actually I have left the 'background_image' in the gfxterm module, and the background of the terminal windows contents (but not the frame) is still controlled through it. I did add scale-to-fit functionality to it, however. >> I hope some version of the gfxmenu project finds its way into the trunk >> of the grub2 repository soon. :-) > > Me too :). It just needs to be fine tuned and then committed. We should > receive sliced patches in here in near term. Colin will be on holiday > for a while so don't hold your breath. I'm working on slicing-and-dicing some patches up today! I probably won't have everything done by Wednesday (when I'm leaving) but I hope to at least have several patches ready. Regards, Colin ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch] background_image: image centering and scaling 2008-08-30 18:57 ` colin @ 2008-08-30 19:07 ` Vesa Jääskeläinen 0 siblings, 0 replies; 10+ messages in thread From: Vesa Jääskeläinen @ 2008-08-30 19:07 UTC (permalink / raw) To: The development of GRUB 2 colin@gibibit.com wrote: > On Sat, 30 Aug 2008 18:00:27 +0300, Vesa Jääskeläinen <chaac@nic.fi> >> Olaf Mandel wrote: >> Basically there is no background_image command anymore in new >> implementation. Idea is that you specify behavior in theme file. In >> theme file you could have attributes what is the scaling behavior (if it >> was not there already). > > Actually I have left the 'background_image' in the gfxterm module, and the > background of the terminal windows contents (but not the frame) is still > controlled through it. I did add scale-to-fit functionality to it, > however. Ok. Then we will change it at later date then. Other new functionality has higher priority :) >>> I hope some version of the gfxmenu project finds its way into the trunk >>> of the grub2 repository soon. :-) >> Me too :). It just needs to be fine tuned and then committed. We should >> receive sliced patches in here in near term. Colin will be on holiday >> for a while so don't hold your breath. > > I'm working on slicing-and-dicing some patches up today! I probably won't > have everything done by Wednesday (when I'm leaving) but I hope to at least > have several patches ready. Nice. Waiting for them :) Thanks, Vesa Jääskeläinen ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch] background_image: image centering and scaling 2008-08-30 5:11 ` Olaf Mandel 2008-08-30 15:00 ` Vesa Jääskeläinen @ 2008-08-31 15:46 ` Colin D Bennett 2008-09-02 7:16 ` Olaf Mandel 1 sibling, 1 reply; 10+ messages in thread From: Colin D Bennett @ 2008-08-31 15:46 UTC (permalink / raw) To: The development of GRUB 2; +Cc: olaf [-- Attachment #1: Type: text/plain, Size: 2021 bytes --] On Fri, 29 Aug 2008 22:11:02 -0700 Olaf Mandel <olaf@mandel.name> wrote: > Vesa Jääskeläinen schrieb: > -Snipp- > > I will however look at if there are some ideas that you have > > provided what is still missing from new graphical menu > > implementation that should be there. > -Snipp- > > Hello, > > thanks. I must admit to not looking at the source code for the > project. Will scaling also be used for "simple" background_image > commands? If yes and if the scaling does preserve the aspect ratio of > the image, then the background picture is not necessarily in the > upper left corner of the screen (an assumption in the code in grub2 > trunk). > > I hope some version of the gfxmenu project finds its way into the > trunk of the grub2 repository soon. :-) > > Best regards, > Olaf Hi Olaf, Thanks for your work! It would be great if you wanted to enhance my code by adding a preserve-aspect-ratio mode; currently my background_image command scales to fit the screen without regard for the image's original aspect ratio. Currently the '--mode' / '-m' option to 'background_image' accepts the following values: stretch Stretch the image to fit without regard for the original aspect ratio. normal Do not scale the image; origin anchored to upper-left corner. I think if you added a "fit" option which would fit the image preserving aspect, that would be nice. Also, you could either add a "center" option which would center the background image without altering its size. I think the "normal" option will not be very desirable when scaling and centering are both available, since I can't imagine why you'd want an image stuck in the corner instead of centered or scaled in some way. If you want to see the code for this, take a look at the message I sent to the grub-devel list today entitled "[PATCH] GSoC #09 Bitmap scaling". This patch may require some of the prior patches as well, however (possibly #06 and/or #07). Regards, Colin [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch] background_image: image centering and scaling 2008-08-31 15:46 ` Colin D Bennett @ 2008-09-02 7:16 ` Olaf Mandel 0 siblings, 0 replies; 10+ messages in thread From: Olaf Mandel @ 2008-09-02 7:16 UTC (permalink / raw) To: Colin D Bennett; +Cc: The development of GRUB 2 [-- Attachment #1.1: Type: text/plain, Size: 1705 bytes --] Colin D Bennett schrieb: -Snipp- > Thanks for your work! It would be great if you wanted to enhance my > code by adding a preserve-aspect-ratio mode; currently my > background_image command scales to fit the screen without regard for > the image's original aspect ratio. [...] -Snipp- Hello, I have a patch that adds one more setting for --mode that allows the picture to be scaled while keeping the aspectratio constant: fit. Also, there is now a second option --pos / -p that has 9 possible settings: tl, t, tr, l, c, r, bl, b, br. The center-position is the default. Start off with SVN r1845, apply the GsoC patch 09_bitmap-scaling.patch and then the one attached here. The patch does not work correctly for me though: the string comparisons, e.g.: grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg, "stretch") do not work reliable. On some occasions, the command works as expected, but often the command goes with the default value, even if something else was specified. This appears to be random... For example, the command: background_image --mode=normal --pos=tl /grub/grub.png will often display the image fitted into the larger screen (wrong), and sometimes as a small picture in the upper left corner (correct). I have had no luck trying to output the content of the variables on the screen or the like... What would the correct code for that be? I hope someone finds the bug or can tell me how to continue about debugging it myself. Best regards, Olaf Mandel -- Olaf Mandel <olaf@mandel.name> <http://www.olaf.mandel.name/> PGP key: 1024D/33398848 2002-09-19 Fingerprint: 0E33 BEA6 1A71 9C5E 62BD FC0E 99A7 D2C6 3339 8848 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1.2: new_centering+scaling.patch --] [-- Type: text/x-patch; name="new_centering+scaling.patch", Size: 14326 bytes --] diff -urN grub2/include/grub/bitmap_scale.h grub3/include/grub/bitmap_scale.h --- grub2/include/grub/bitmap_scale.h 2008-09-01 19:05:55.000000000 -0700 +++ grub3/include/grub/bitmap_scale.h 2008-09-01 22:26:35.000000000 -0700 @@ -51,4 +51,11 @@ enum grub_video_bitmap_scale_method scale_method); +grub_err_t +grub_video_bitmap_create_fitted (struct grub_video_bitmap **dst, + int max_width, int max_height, + struct grub_video_bitmap *src, + enum + grub_video_bitmap_scale_method scale_method); + #endif /* ! GRUB_BITMAP_SCALE_HEADER */ diff -urN grub2/term/gfxterm.c grub3/term/gfxterm.c --- grub2/term/gfxterm.c 2008-09-01 19:05:55.000000000 -0700 +++ grub3/term/gfxterm.c 2008-09-01 23:58:24.000000000 -0700 @@ -113,6 +113,8 @@ static struct grub_video_render_target *text_layer; +static int bitmap_x; +static int bitmap_y; static unsigned int bitmap_width; static unsigned int bitmap_height; static struct grub_video_bitmap *bitmap; @@ -514,43 +516,96 @@ { /* Render bitmap as background. */ grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_REPLACE, x, y, - x, y, + x - bitmap_x, y - bitmap_y, width, height); /* If bitmap is smaller than requested blit area, use background color. */ color = virtual_screen.bg_color; + /* Fill top side of the bitmap (including corners) if needed. */ + if ((int)y < bitmap_y) + { + int h = height; + + if ((int)y + h > bitmap_y) + { + h = bitmap_y - y; + } + + /* Render background layer. */ + grub_video_fill_rect (color, x, y, width, h); + } + + /* Fill left side of the bitmap if needed. */ + if (((int)x < bitmap_x) && ((int)y < bitmap_y + (int)bitmap_height) + && ((int)(y + height) > bitmap_y)) + { + int w = width; + int h = height; + unsigned int ty = y; + + if ((int)x + w > bitmap_x) + { + w = bitmap_x - x; + } + + if ((int)ty < bitmap_y) + { + h -= bitmap_y - ty; + ty = bitmap_y; + } + + if (ty + h > bitmap_y + bitmap_height) + { + h = bitmap_y + bitmap_height - ty; + } + + /* Render background layer. */ + grub_video_fill_rect (color, x, ty, w, h); + } + /* Fill right side of the bitmap if needed. */ - if ((x + width >= bitmap_width) && (y < bitmap_height)) + if ((x + width > bitmap_x + bitmap_width) + && ((int)y < bitmap_y + (int)bitmap_height) + && ((int)(y + height) > bitmap_y)) { - int w = (x + width) - bitmap_width; + int w = width; int h = height; unsigned int tx = x; + unsigned int ty = y; - if (y + height >= bitmap_height) + if (tx < bitmap_x + bitmap_width) { - h = bitmap_height - y; + w -= bitmap_x + bitmap_width - tx; + tx = bitmap_x + bitmap_width; } - if (bitmap_width > tx) + if ((int)ty < bitmap_y) { - tx = bitmap_width; + h -= bitmap_y - ty; + ty = bitmap_y; } + if (ty + h > bitmap_y + bitmap_height) + { + h = bitmap_y + bitmap_height - ty; + } + /* Render background layer. */ - grub_video_fill_rect (color, tx, y, w, h); + grub_video_fill_rect (color, tx, ty, w, h); } - /* Fill bottom side of the bitmap if needed. */ - if (y + height >= bitmap_height) + /* Fill bottom side of the bitmap (including corners) if needed. */ + if (y + height > bitmap_y + bitmap_height) { - int h = (y + height) - bitmap_height; + int h = height; unsigned int ty = y; - if (bitmap_height > ty) + if (ty < bitmap_y + bitmap_height) { - ty = bitmap_height; + h -= bitmap_y + bitmap_height - ty; + ty = bitmap_y + bitmap_height; } /* Render background layer. */ @@ -1014,10 +1069,12 @@ /* Option array indices. */ #define BACKGROUND_CMD_ARGINDEX_MODE 0 +#define BACKGROUND_CMD_ARGINDEX_POS 1 static const struct grub_arg_option background_image_cmd_options[] = { - {"mode", 'm', 0, "Background image mode (`stretch', `normal').", 0, + {"mode", 'm', 0, "Background image mode ([`fit'], `stretch', `normal').", 0, ARG_TYPE_STRING}, + {"pos", 'p', 0, "Position of image (`tl', `t', `tr', `l', [`c'], `r', `bl', `b', `br').", 0, ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -1049,30 +1106,6 @@ if (grub_errno != GRUB_ERR_NONE) return grub_errno; - /* Determine if the bitmap should be scaled to fit the screen. */ - if (!state[BACKGROUND_CMD_ARGINDEX_MODE].set - || grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg, - "stretch") == 0) - { - if (mode_info.width != grub_video_bitmap_get_width (bitmap) - || mode_info.height != grub_video_bitmap_get_height (bitmap)) - { - struct grub_video_bitmap *scaled_bitmap; - grub_video_bitmap_create_scaled (&scaled_bitmap, - mode_info.width, - mode_info.height, - bitmap, - GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); - if (grub_errno == GRUB_ERR_NONE) - { - /* Replace the original bitmap with the scaled one. */ - grub_video_bitmap_destroy (bitmap); - bitmap = scaled_bitmap; - } - } - } - - /* If bitmap was loaded correctly, display it. */ if (bitmap) { @@ -1080,6 +1113,119 @@ bitmap_width = grub_video_bitmap_get_width (bitmap); bitmap_height = grub_video_bitmap_get_height (bitmap); + /* Determine if the bitmap should be scaled to fit the screen. */ + if (mode_info.width != bitmap_width + || mode_info.height != bitmap_height) + { + if (state[BACKGROUND_CMD_ARGINDEX_MODE].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg, + "stretch") == 0) + { + struct grub_video_bitmap *scaled_bitmap; + grub_video_bitmap_create_scaled (&scaled_bitmap, + mode_info.width, + mode_info.height, + bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + if (grub_errno == GRUB_ERR_NONE) + { + /* Replace the original bitmap with the scaled one. */ + grub_video_bitmap_destroy (bitmap); + bitmap = scaled_bitmap; + } + } + else if (state[BACKGROUND_CMD_ARGINDEX_MODE].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg, + "normal") == 0) + { + /* There is nothing to do in this case */ + } + else /* This is for mode="fit", for unknown values of mode and if no + mode parameter is given. */ + { + struct grub_video_bitmap *fitted_bitmap; + grub_video_bitmap_create_fitted (&fitted_bitmap, + mode_info.width, + mode_info.height, + bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + if (grub_errno == GRUB_ERR_NONE) + { + /* Replace the original bitmap with the fitted one. */ + grub_video_bitmap_destroy (bitmap); + bitmap = fitted_bitmap; + } + } + + /* Re-Determine bitmap dimensions. */ + bitmap_width = grub_video_bitmap_get_width (bitmap); + bitmap_height = grub_video_bitmap_get_height (bitmap); + } + + /* Determine where to place the bitmap on the screen. */ + if (state[BACKGROUND_CMD_ARGINDEX_POS].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_POS].arg, + "tl") == 0) + { + bitmap_x = 0; + bitmap_y = 0; + } + else if (state[BACKGROUND_CMD_ARGINDEX_POS].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_POS].arg, + "t") == 0) + { + bitmap_x = (int)(mode_info.width - bitmap_width) / 2; + bitmap_y = 0; + } + else if (state[BACKGROUND_CMD_ARGINDEX_POS].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_POS].arg, + "tr") == 0) + { + bitmap_x = mode_info.width - bitmap_width; + bitmap_y = 0; + } + else if (state[BACKGROUND_CMD_ARGINDEX_POS].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_POS].arg, + "l") == 0) + { + bitmap_x = 0; + bitmap_y = (int)(mode_info.height - bitmap_height) / 2; + } + else if (state[BACKGROUND_CMD_ARGINDEX_POS].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_POS].arg, + "r") == 0) + { + bitmap_x = mode_info.width - bitmap_width; + bitmap_y = (int)(mode_info.height - bitmap_height) / 2; + } + else if (state[BACKGROUND_CMD_ARGINDEX_POS].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_POS].arg, + "bl") == 0) + { + bitmap_x = 0; + bitmap_y = mode_info.height - bitmap_height; + } + else if (state[BACKGROUND_CMD_ARGINDEX_POS].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_POS].arg, + "b") == 0) + { + bitmap_x = (int)(mode_info.width - bitmap_width) / 2; + bitmap_y = mode_info.height - bitmap_height; + } + else if (state[BACKGROUND_CMD_ARGINDEX_POS].set + && grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_POS].arg, + "br") == 0) + { + bitmap_x = mode_info.width - bitmap_width; + bitmap_y = mode_info.height - bitmap_height; + } + else /* This is for pos="c", for unknown values of pos and if no + pos parameter is given. */ + { + bitmap_x = (int)(mode_info.width - bitmap_width) / 2; + bitmap_y = (int)(mode_info.height - bitmap_height) / 2; + } + /* Mark whole screen as dirty. */ dirty_region_reset (); dirty_region_add (0, 0, mode_info.width, mode_info.height); diff -urN grub2/video/bitmap_scale.c grub3/video/bitmap_scale.c --- grub2/video/bitmap_scale.c 2008-09-01 19:05:55.000000000 -0700 +++ grub3/video/bitmap_scale.c 2008-09-01 22:26:28.000000000 -0700 @@ -99,3 +99,49 @@ return ret; } } + +/* + * This function creates a new scaled version of the bitmap SRC. The new + * bitmap has the same aspect ratio as SRC and is smaller or equal in size + * to MAX_WIDTH and MAX_HEIGHT. One of these two dimensions is exactly right, + * the other may be smaller in order to preserve the aspect ratio. The scaling + * algorithm is given by SCALE_METHOD. + * + * This function internally uses grub_video_bitmap_create_scaled(), so the + * error handling is identical to that function. Also, all limitations of + * *_scaled() also apply to *_fitted(). + */ +grub_err_t +grub_video_bitmap_create_fitted (struct grub_video_bitmap **dst, + int max_width, int max_height, + struct grub_video_bitmap *src, + enum grub_video_bitmap_scale_method + scale_method) +{ + int w; + int h; + int width = max_width; + int height = max_height; + + /* Verify the simplifying assumptions and get src dimensions. */ + if (src == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "null src bitmap in grub_video_bitmap_create_fitted"); + w = src->mode_info.width; + h = src->mode_info.height; + if (max_width <= 0 || max_height <= 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "requested to fit to a size w/ a zero dimension"); + + /* Is the new region wider than the old bitmap? Use products instead of + * fractions. */ + if (w * max_height < max_width * h) + width = w * max_height / h; + + /* Is the new region higher than the old bitmap? */ + if (w * max_height > max_width * h) + height = h * max_width / w; + + return grub_video_bitmap_create_scaled (dst, width, height, src, + scale_method); +} [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch] background_image: image centering and scaling 2008-08-29 14:56 ` Vesa Jääskeläinen 2008-08-29 15:17 ` Felix Zielcke 2008-08-30 5:11 ` Olaf Mandel @ 2008-08-30 12:05 ` Robert Millan 2 siblings, 0 replies; 10+ messages in thread From: Robert Millan @ 2008-08-30 12:05 UTC (permalink / raw) To: The development of GRUB 2 On Fri, Aug 29, 2008 at 05:56:21PM +0300, Vesa Jääskeläinen wrote: > > Thanks for your effort, but there is already code that does this, > altought not committed yet. My apologises; I was unaware of this when I told Olaf to go ahead and bring this to grub-devel. Olaf, sorry if I wasted your time, I should have known better. -- Robert Millan The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and how) you may access your data; but nobody's threatening your freedom: we still allow you to remove your data and not access it at all." ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2008-09-02 7:16 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-08-29 1:46 [patch] background_image: image centering and scaling Olaf Mandel 2008-08-29 14:56 ` Vesa Jääskeläinen 2008-08-29 15:17 ` Felix Zielcke 2008-08-30 5:11 ` Olaf Mandel 2008-08-30 15:00 ` Vesa Jääskeläinen 2008-08-30 18:57 ` colin 2008-08-30 19:07 ` Vesa Jääskeläinen 2008-08-31 15:46 ` Colin D Bennett 2008-09-02 7:16 ` Olaf Mandel 2008-08-30 12:05 ` Robert Millan
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.