Felix Zielcke schrieb:
-Snipp-
>> I do not know how GRUB2 is _supposed_ to behave if the picture
>> dimensions are smaller (different) from the resolution of the gfxmode.
>> But at least on my machine it shows a far too small picture in the upper
>> left corner.
> 
> Me neither I just stick with the default 640*480 and the default Debian
> picure.
> 

I feel that it might be better if grub actually scales its background
picture to fit the screen size. The attached patch adds this
functionality. It adds three preprocessor switches:

* BITMAP_CENTERED selects if the (unscaled) picture should be arranged
in the upper / left corner of the screen or if it should be centered.
* BITMAP_SCALED selects if the picture should be scaled to better fit
the screen size or not. The scaling goes in both directions (smaller or
larger, as needed).
* BITMAP_KEEPASPECTRATIO selects if the bitmap aspect ratio should be
preserved during scaling. If yes, then the resulting image will be
smaller than the screen, resulting in two black stripes where the bitmap
does not fill the screen.

At the moment, the "scaling algorithm" is _very_ minimal. I did not use
bi-linear or even linear interpolation. The nearest matching pixel to
the left / top of the current position simply gets copied.

Additionally, a small copy&paste bug is fixed: gfxterm internally stored
the wrong height of the bitmap.

> Your whole idea doestn't sound that bad.
> Maybe your report should just be merged with the desktop-grub symlink
> one to have the whole discussion only at one place.

I think most of my previous patch becomes deprecated by this one. Only
the variable to set the screen resolution (as already in bug #493106
before merging) is still needed.

> However I'm still a bit new to this whole grub business, so I think it's
> just better if I leave the whole topic more to Robert.
> He has more experience then me, so he probable sees more the problems
> which could arise.
> 
I included him in the CC.

Best regards,
Olaf Mandel
-- 
Olaf Mandel   <[EMAIL PROTECTED]>   <http://www.olaf.mandel.name/>
PGP key:      1024D/33398848 2002-09-19
Fingerprint:  0E33 BEA6 1A71 9C5E 62BD  FC0E 99A7 D2C6 3339 8848
diff -urN grub2-1.96+20080724_new/ChangeLog grub2-1.96+20080724_scaling/ChangeLog
--- grub2-1.96+20080724_new/ChangeLog	2008-07-22 15:23:45.000000000 -0700
+++ grub2-1.96+20080724_scaling/ChangeLog	2008-08-24 00:49:18.000000000 -0700
@@ -1,3 +1,13 @@
+2008-08-24  Olaf Mandel  <[EMAIL PROTECTED]>
+
+	* 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).
+
+	* 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-07-23  Robert Millan  <[EMAIL PROTECTED]>
 
 	* Makefile.in (UNICODE_ARROWS, UNICODE_LINES): New variables (they
diff -urN grub2-1.96+20080724_new/include/grub/bitmap.h grub2-1.96+20080724_scaling/include/grub/bitmap.h
--- grub2-1.96+20080724_new/include/grub/bitmap.h	2007-07-21 16:32:33.000000000 -0700
+++ grub2-1.96+20080724_scaling/include/grub/bitmap.h	2008-08-24 00:34:54.000000000 -0700
@@ -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 */
diff -urN grub2-1.96+20080724_new/term/gfxterm.c grub2-1.96+20080724_scaling/term/gfxterm.c
--- grub2-1.96+20080724_new/term/gfxterm.c	2008-01-01 04:02:07.000000000 -0800
+++ grub2-1.96+20080724_scaling/term/gfxterm.c	2008-08-24 00:35:54.000000000 -0700
@@ -44,6 +44,10 @@
 #define DEFAULT_HIGHLIGHT_COLOR 0x70
 #define DEFAULT_CURSOR_COLOR	0x07
 
+#define BITMAP_CENTERED         1
+#define BITMAP_SCALED           1
+#define BITMAP_KEEPASPECTRATIO  1
+
 struct grub_dirty_region
 {
   int top_left_x;
@@ -114,6 +118,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;
@@ -517,43 +523,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 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)
+      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.  */
@@ -1045,10 +1103,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);
diff -urN grub2-1.96+20080724_new/video/bitmap.c grub2-1.96+20080724_scaling/video/bitmap.c
--- grub2-1.96+20080724_new/video/bitmap.c	2007-07-21 16:32:33.000000000 -0700
+++ grub2-1.96+20080724_scaling/video/bitmap.c	2008-08-24 00:16:20.000000000 -0700
@@ -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)
 {

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to