grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [patch] background_image: image centering and scaling


From: Olaf Mandel
Subject: Re: [patch] background_image: image centering and scaling
Date: Tue, 02 Sep 2008 00:16:53 -0700
User-agent: IceDove 1.5.0.14eol (X11/20080724)

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   <address@hidden>   <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/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: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]