grub-devel
[Top][All Lists]
Advanced

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

Re: [PATCH] 3/5 Bitmap scaling


From: Vesa Jääskeläinen
Subject: Re: [PATCH] 3/5 Bitmap scaling
Date: Sat, 31 Jan 2009 23:27:55 +0200
User-agent: Thunderbird 2.0.0.19 (Windows/20081209)

Colin D Bennett wrote:
> This patch adds bitmap scaling support to GRUB.
> 
> It also adds support to gfxterm for scaling the background image to fit
> the screen.  The background_image command supports a new -m/--mode
> option, which takes "stretch" (the default) or "normal" as values.
> 
> The patch is against GRUB trunk revision 1964.

After commit this needs to be documented to wiki/gfxterm with an example
perhaps...

> Vesa started a discussion about more flexible handling of bitmaps
> including the concept of optimizing loaded bitmaps into a
> display-specific format, at which point they could no longer be
> modified by functions like the bitmap scaling functions.
> 
> This bitmap format optimization would be nice to add, but I think we
> can at least add this basic bitmap scaling functionality to start
> with.  It only supports 24/32 bpp direct color modes at this point to
> keep things simple.

True. Lets not block the feature because of this.

> === added file 'include/grub/bitmap_scale.h'
> --- include/grub/bitmap_scale.h       1970-01-01 00:00:00 +0000
> +++ include/grub/bitmap_scale.h       2009-01-31 20:18:45 +0000
> @@ -0,0 +1,48 @@
> +/* bitmap_scale.h - Bitmap scaling functions. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008,2009  Free Software Foundation, Inc.

New file. Change copyright to 2009.

> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef GRUB_BITMAP_SCALE_HEADER
> +#define GRUB_BITMAP_SCALE_HEADER 1
> +
> +#include <grub/err.h>
> +#include <grub/types.h>
> +#include <grub/bitmap_scale.h>
> +
> +enum grub_video_bitmap_scale_method
> +{
> +  /* Choose the fastest interpolation algorithm.  */
> +  GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST,
> +  /* Choose the highest quality interpolation algorithm.  */
> +  GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST,
> +
> +  /* Specific algorithms:  */
> +  /* Nearest neighbor interpolation.  */
> +  GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST,
> +  /* Bilinear interpolation.  */
> +  GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR
> +};
> +
> +grub_err_t
> +grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
> +                                 int dst_width, int dst_height,
> +                                 struct grub_video_bitmap *src,
> +                                 enum
> +                                 grub_video_bitmap_scale_method 
> scale_method);
> +
> +#endif /* ! GRUB_BITMAP_SCALE_HEADER */
> 
> === modified file 'term/gfxterm.c'
> --- term/gfxterm.c    2009-01-19 17:09:53 +0000
> +++ term/gfxterm.c    2009-01-31 20:28:20 +0000
> @@ -27,6 +27,7 @@
>  #include <grub/env.h>
>  #include <grub/video.h>
>  #include <grub/bitmap.h>
> +#include <grub/bitmap_scale.h>
>  
>  #define DEFAULT_VIDEO_WIDTH  640
>  #define DEFAULT_VIDEO_HEIGHT 480
> @@ -1095,8 +1096,18 @@
>    dirty_region_redraw ();
>  }
>  
> +
> +/* Option array indices. */
> +#define BACKGROUND_CMD_ARGINDEX_MODE 0
> +
> +static const struct grub_arg_option background_image_cmd_options[] = {
> +  {"mode", 'm', 0, "Background image mode (`stretch', `normal').", 0, 
> +    ARG_TYPE_STRING},
> +  {0, 0, 0, 0, 0, 0}
> +};
> +
>  static grub_err_t
> -grub_gfxterm_background_image_cmd (struct grub_arg_list *state __attribute__ 
> ((unused)),
> +grub_gfxterm_background_image_cmd (struct grub_arg_list *state,
>                                     int argc,
>                                     char **args)
>  {
> @@ -1123,12 +1134,36 @@
>      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)

Extra parentheses would be nice around grub_rtrcmp () == 0 compare.

> +        {
> +          if (mode_info.width != grub_video_bitmap_get_width (bitmap)
> +              || mode_info.height != grub_video_bitmap_get_height (bitmap)) 

This would benefit the same...

> +            {
> +              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. */

Space...

> +                  grub_video_bitmap_destroy (bitmap);
> +                  bitmap = scaled_bitmap;
> +                }
> +            }
> +        }
> +
> +
>      /* If bitmap was loaded correctly, display it.  */
>      if (bitmap)
>        {
>          /* 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);
>          
>          /* Mark whole screen as dirty.  */
>          dirty_region_reset ();
> @@ -1171,7 +1206,7 @@
>                           GRUB_COMMAND_FLAG_BOTH,
>                           "background_image",
>                           "Load background image for active terminal",
> -                         0);
> +                         background_image_cmd_options);
>  }
>  
>  GRUB_MOD_FINI(term_gfxterm)
> 
> === added file 'video/bitmap_scale.c'
> --- video/bitmap_scale.c      1970-01-01 00:00:00 +0000
> +++ video/bitmap_scale.c      2009-01-31 20:22:55 +0000
> @@ -0,0 +1,307 @@
> +/* bitmap_scale.c - Bitmap scaling. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2006,2007,2008,2009  Free Software Foundation, Inc.

New file. Change to 2009.

> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/mm.h>
> +#include <grub/misc.h>
> +#include <grub/video.h>
> +#include <grub/bitmap.h>
> +#include <grub/bitmap_scale.h>
> +#include <grub/types.h>
> +
> +/* Prototypes for module-local functions.  */
> +static grub_err_t scale_nn (struct grub_video_bitmap *dst,
> +                            struct grub_video_bitmap *src);
> +static grub_err_t scale_bilinear (struct grub_video_bitmap *dst,
> +                                  struct grub_video_bitmap *src);
> +
> +/* This function creates a new scaled version of the bitmap SRC.  The new
> +   bitmap has dimensions DST_WIDTH by DST_HEIGHT.  The scaling algorithm
> +   is given by SCALE_METHOD.  If an error is encountered, the return code is
> +   not equal to GRUB_ERR_NONE, and the bitmap DST is either not created, or
> +   it is destroyed before this function returns.
> +
> +   Supports only direct color modes which have components separated
> +   into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color).
> +   But because of this simplifying assumption, the implementation is
> +   greatly simplified.  */
> +grub_err_t
> +grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
> +                                 int dst_width, int dst_height,
> +                                 struct grub_video_bitmap *src,
> +                                 enum grub_video_bitmap_scale_method
> +                                 scale_method)
> +{
> +  *dst = 0;
> +
> +  /* Verify the simplifying assumptions. */

Space..

> +  if (src == 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT,
> +                       "null src bitmap in grub_video_bitmap_create_scaled");

Add some parentheses below...

> +  if (src->mode_info.red_field_pos % 8 != 0
> +      || src->mode_info.green_field_pos % 8 != 0
> +      || src->mode_info.blue_field_pos % 8 != 0
> +      || src->mode_info.reserved_field_pos % 8 != 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT,
> +                       "src format not supported for scale");
> +  if (src->mode_info.width == 0 || src->mode_info.height == 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension");
> +  if (dst_width <= 0 || dst_height <= 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT,
> +                       "requested to scale to a size w/ a zero dimension");
> +  if (src->mode_info.bytes_per_pixel * 8 != src->mode_info.bpp)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT,
> +                       "bitmap to scale has inconsistent Bpp and bpp");
> +

Space...

> +  /* Create the new bitmap. */
> +  grub_err_t ret;
> +  ret = grub_video_bitmap_create (dst, dst_width, dst_height,
> +                                  src->mode_info.blit_format);

Move comment to own line (or remove it)...

> +  if (ret != GRUB_ERR_NONE)
> +    return ret;                 /* Error. */
> +
> +  switch (scale_method)
> +    {
> +    case GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST:
> +    case GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST:
> +      ret = scale_nn (*dst, src);
> +      break;
> +    case GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST:
> +    case GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR:
> +      ret = scale_bilinear (*dst, src);
> +      break;
> +    default:
> +      ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid scale_method value");
> +      break;
> +    }
> +
> +  if (ret == GRUB_ERR_NONE)
> +    {

Remove one space and add one...

> +      /* Success:  *dst is now a pointer to the scaled bitmap. */
> +      return GRUB_ERR_NONE;
> +    }
> +  else
> +    {

Space..

> +      /* Destroy the bitmap and return the error code. */
> +      grub_video_bitmap_destroy (*dst);
> +      *dst = 0;
> +      return ret;
> +    }
> +}
> +
> +/* Nearest neighbor bitmap scaling algorithm.
> +
> +   Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the
> +   dimensions of DST.  This function uses the nearest neighbor algorithm to
> +   interpolate the pixels.
> +
> +   Supports only direct color modes which have components separated
> +   into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color).
> +   But because of this simplifying assumption, the implementation is
> +   greatly simplified.  */
> +static grub_err_t
> +scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
> +{

Space..

> +  /* Verify the simplifying assumptions. */
> +  if (dst == 0 || src == 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale_nn");

Add parentheses below... Please feel free to add empty line between
different if's if you see it fit.

> +  if (dst->mode_info.red_field_pos % 8 != 0
> +      || dst->mode_info.green_field_pos % 8 != 0
> +      || dst->mode_info.blue_field_pos % 8 != 0
> +      || dst->mode_info.reserved_field_pos % 8 != 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported");
> +  if (src->mode_info.red_field_pos % 8 != 0
> +      || src->mode_info.green_field_pos % 8 != 0
> +      || src->mode_info.blue_field_pos % 8 != 0
> +      || src->mode_info.reserved_field_pos % 8 != 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported");
> +  if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos
> +      || dst->mode_info.red_mask_size != src->mode_info.red_mask_size
> +      || dst->mode_info.green_field_pos != src->mode_info.green_field_pos
> +      || dst->mode_info.green_mask_size != src->mode_info.green_mask_size
> +      || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos
> +      || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size
> +      || dst->mode_info.reserved_field_pos !=
> +      src->mode_info.reserved_field_pos
> +      || dst->mode_info.reserved_mask_size !=
> +      src->mode_info.reserved_mask_size)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible");
> +  if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible");
> +  if (dst->mode_info.width == 0 || dst->mode_info.height == 0
> +      || src->mode_info.width == 0 || src->mode_info.height == 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension");
> +

Didn't the compile complain about declaring variables within code... or
were we targetting for c99 ?

> +  grub_uint8_t *ddata = dst->data;
> +  grub_uint8_t *sdata = src->data;
> +  int dw = dst->mode_info.width;
> +  int dh = dst->mode_info.height;
> +  int sw = src->mode_info.width;
> +  int sh = src->mode_info.height;
> +  int dstride = dst->mode_info.pitch;
> +  int sstride = src->mode_info.pitch;

Space.

> +  /* bytes_per_pixel is the same for both src and dst. */
> +  int bytes_per_pixel = dst->mode_info.bytes_per_pixel;
> +
> +  int dy;
> +  for (dy = 0; dy < dh; dy++)
> +    {
> +      int dx;
> +      for (dx = 0; dx < dw; dx++)
> +        {
> +          grub_uint8_t *dptr;
> +          grub_uint8_t *sptr;
> +          int sx;
> +          int sy;
> +          int comp;
> +

Space.

> +          /* Compute the source coordinate that the destination coordinate
> +             maps to.  Note: sx/sw = dx/dw  =>  sx = sw*dx/dw. */
> +          sx = sw * dx / dw;
> +          sy = sh * dy / dh;
> +

Space.

> +          /* Get the address of the pixels in src and dst. */
> +          dptr = ddata + dy * dstride + dx * bytes_per_pixel;
> +          sptr = sdata + sy * sstride + sx * bytes_per_pixel;
> +

...

> +          /* Copy the pixel color value. */
> +          for (comp = 0; comp < bytes_per_pixel; comp++)
> +            dptr[comp] = sptr[comp];
> +        }
> +    }
> +  return GRUB_ERR_NONE;
> +}
> +
> +/* Bilinear interpolation image scaling algorithm.
> +
> +   Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the
> +   dimensions of DST.  This function uses the bilinear interpolation 
> algorithm
> +   to interpolate the pixels.
> +
> +   Supports only direct color modes which have components separated
> +   into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color).
> +   But because of this simplifying assumption, the implementation is
> +   greatly simplified.  */
> +static grub_err_t
> +scale_bilinear (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
> +{

Same story here...

> +  /* Verify the simplifying assumptions. */
> +  if (dst == 0 || src == 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale func");
> +  if (dst->mode_info.red_field_pos % 8 != 0
> +      || dst->mode_info.green_field_pos % 8 != 0
> +      || dst->mode_info.blue_field_pos % 8 != 0
> +      || dst->mode_info.reserved_field_pos % 8 != 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported");
> +  if (src->mode_info.red_field_pos % 8 != 0
> +      || src->mode_info.green_field_pos % 8 != 0
> +      || src->mode_info.blue_field_pos % 8 != 0
> +      || src->mode_info.reserved_field_pos % 8 != 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported");
> +  if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos
> +      || dst->mode_info.red_mask_size != src->mode_info.red_mask_size
> +      || dst->mode_info.green_field_pos != src->mode_info.green_field_pos
> +      || dst->mode_info.green_mask_size != src->mode_info.green_mask_size
> +      || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos
> +      || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size
> +      || dst->mode_info.reserved_field_pos !=
> +      src->mode_info.reserved_field_pos
> +      || dst->mode_info.reserved_mask_size !=
> +      src->mode_info.reserved_mask_size)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible");
> +  if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible");
> +  if (dst->mode_info.width == 0 || dst->mode_info.height == 0
> +      || src->mode_info.width == 0 || src->mode_info.height == 0)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension");
> +
> +  grub_uint8_t *ddata = dst->data;
> +  grub_uint8_t *sdata = src->data;
> +  int dw = dst->mode_info.width;
> +  int dh = dst->mode_info.height;
> +  int sw = src->mode_info.width;
> +  int sh = src->mode_info.height;
> +  int dstride = dst->mode_info.pitch;
> +  int sstride = src->mode_info.pitch;
> +  /* bytes_per_pixel is the same for both src and dst. */
> +  int bytes_per_pixel = dst->mode_info.bytes_per_pixel;
> +
> +  int dy;
> +  for (dy = 0; dy < dh; dy++)
> +    {
> +      int dx;
> +      for (dx = 0; dx < dw; dx++)
> +        {
> +          grub_uint8_t *dptr;
> +          grub_uint8_t *sptr;
> +          int sx;
> +          int sy;
> +          int comp;
> +
> +          /* Compute the source coordinate that the destination coordinate
> +             maps to.  Note: sx/sw = dx/dw  =>  sx = sw*dx/dw. */
> +          sx = sw * dx / dw;
> +          sy = sh * dy / dh;
> +
> +          /* Get the address of the pixels in src and dst. */
> +          dptr = ddata + dy * dstride + dx * bytes_per_pixel;
> +          sptr = sdata + sy * sstride + sx * bytes_per_pixel;
> +
> +          /* If we have enough space to do so, use bilinear interpolation.
> +             Otherwise, fall back to nearest neighbor for this pixel. */
> +          if (sx < sw - 1 && sy < sh - 1)
> +            {
> +              /* Do bilinear interpolation. */
> +
> +              /* Fixed-point .8 numbers representing the fraction of the
> +                 distance in the x (u) and y (v) direction within the
> +                 box of 4 pixels in the source. */
> +              int u = (256 * sw * dx / dw) - (sx * 256);
> +              int v = (256 * sh * dy / dh) - (sy * 256);
> +
> +              for (comp = 0; comp < bytes_per_pixel; comp++)
> +                {
> +                  /* Get the component's values for the
> +                     four source corner pixels. */
> +                  grub_uint8_t f00 = sptr[comp];
> +                  grub_uint8_t f10 = sptr[comp + bytes_per_pixel];
> +                  grub_uint8_t f01 = sptr[comp + sstride];
> +                  grub_uint8_t f11 = sptr[comp + sstride + bytes_per_pixel];
> +
> +                  /* Do linear interpolations along the top and bottom
> +                     rows of the box. */
> +                  grub_uint8_t f0y = (256 - v) * f00 / 256 + v * f01 / 256;
> +                  grub_uint8_t f1y = (256 - v) * f10 / 256 + v * f11 / 256;
> +
> +                  /* Interpolate vertically. */
> +                  grub_uint8_t fxy = (256 - u) * f0y / 256 + u * f1y / 256;
> +
> +                  dptr[comp] = fxy;
> +                }
> +            }
> +          else
> +            {
> +              /* Fall back to nearest neighbor interpolation. */
> +              /* Copy the pixel color value. */
> +              for (comp = 0; comp < bytes_per_pixel; comp++)
> +                dptr[comp] = sptr[comp];
> +            }
> +        }
> +    }
> +  return GRUB_ERR_NONE;
> +}




reply via email to

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