From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1LTMW1-0008F0-JJ for mharc-grub-devel@gnu.org; Sat, 31 Jan 2009 15:32:33 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LTMVy-0008EV-U8 for grub-devel@gnu.org; Sat, 31 Jan 2009 15:32:30 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LTMVu-0008Dj-LK for grub-devel@gnu.org; Sat, 31 Jan 2009 15:32:29 -0500 Received: from [199.232.76.173] (port=48213 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LTMVu-0008Dg-GM for grub-devel@gnu.org; Sat, 31 Jan 2009 15:32:26 -0500 Received: from gateway04.websitewelcome.com ([69.93.179.22]:35018) by monty-python.gnu.org with smtp (Exim 4.60) (envelope-from ) id 1LTMVt-0007RY-O3 for grub-devel@gnu.org; Sat, 31 Jan 2009 15:32:26 -0500 Received: (qmail 31406 invoked from network); 31 Jan 2009 20:51:02 -0000 Received: from gator297.hostgator.com (74.53.228.114) by gateway04.websitewelcome.com with SMTP; 31 Jan 2009 20:51:02 -0000 Received: from [67.185.177.95] (port=57895 helo=localhost) by gator297.hostgator.com with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.69) (envelope-from ) id 1LTMVo-0001Ao-62 for grub-devel@gnu.org; Sat, 31 Jan 2009 14:32:20 -0600 Date: Sat, 31 Jan 2009 12:32:20 -0800 From: Colin D Bennett To: The development of GRUB 2 Message-ID: <20090131123220.7c4e346b@gibibit.com> X-Mailer: Claws Mail 3.7.0 (GTK+ 2.14.7; i686-pc-linux-gnu) Mime-Version: 1.0 Content-Type: multipart/signed; boundary="Sig_/s8mhBL=G+8Akh.NAWqChULp"; protocol="application/pgp-signature"; micalg=PGP-SHA1 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - gator297.hostgator.com X-AntiAbuse: Original Domain - gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - gibibit.com X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 3) Subject: [PATCH] 3/5 Bitmap scaling X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 31 Jan 2009 20:32:31 -0000 --Sig_/s8mhBL=G+8Akh.NAWqChULp Content-Type: multipart/mixed; boundary="MP_/y1sRvsitMtO=zU/YqNMc7hS" --MP_/y1sRvsitMtO=zU/YqNMc7hS Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable Content-Disposition: inline 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. 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. Regards, Colin --MP_/y1sRvsitMtO=zU/YqNMc7hS Content-Type: text/x-patch Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename=03_bitmap-scaling.patch =3D=3D=3D modified file 'conf/common.rmk' --- conf/common.rmk 2009-01-13 16:34:26 +0000 +++ conf/common.rmk 2009-01-31 20:28:20 +0000 @@ -446,7 +446,7 @@ videotest_mod_LDFLAGS =3D $(COMMON_LDFLAGS) =20 # For bitmap.mod -bitmap_mod_SOURCES =3D video/bitmap.c +bitmap_mod_SOURCES =3D video/bitmap.c video/bitmap_scale.c bitmap_mod_CFLAGS =3D $(COMMON_CFLAGS) bitmap_mod_LDFLAGS =3D $(COMMON_LDFLAGS) =20 =3D=3D=3D 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. + * + * 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 . + */ + +#ifndef GRUB_BITMAP_SCALE_HEADER +#define GRUB_BITMAP_SCALE_HEADER 1 + +#include +#include +#include + +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_meth= od); + +#endif /* ! GRUB_BITMAP_SCALE_HEADER */ =3D=3D=3D 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 #include #include +#include =20 #define DEFAULT_VIDEO_WIDTH 640 #define DEFAULT_VIDEO_HEIGHT 480 @@ -1095,8 +1096,18 @@ dirty_region_redraw (); } =20 + +/* Option array indices. */ +#define BACKGROUND_CMD_ARGINDEX_MODE 0 + +static const struct grub_arg_option background_image_cmd_options[] =3D { + {"mode", 'm', 0, "Background image mode (`stretch', `normal').", 0,=20 + 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 !=3D GRUB_ERR_NONE) return grub_errno; =20 + /* 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") =3D=3D 0) + { + if (mode_info.width !=3D grub_video_bitmap_get_width (bitmap) + || mode_info.height !=3D grub_video_bitmap_get_height (bitma= p))=20 + { + struct grub_video_bitmap *scaled_bitmap; + grub_video_bitmap_create_scaled (&scaled_bitmap, + mode_info.width,=20 + mode_info.height, + bitmap, + GRUB_VIDEO_BITMAP_SCALE_METH= OD_BEST); + if (grub_errno =3D=3D GRUB_ERR_NONE) + { + /* Replace the original bitmap with the scaled one. */ + grub_video_bitmap_destroy (bitmap); + bitmap =3D scaled_bitmap; + } + } + } + + /* If bitmap was loaded correctly, display it. */ if (bitmap) { /* Determine bitmap dimensions. */ bitmap_width =3D grub_video_bitmap_get_width (bitmap); - bitmap_height =3D grub_video_bitmap_get_width (bitmap); + bitmap_height =3D grub_video_bitmap_get_height (bitmap); =20 /* 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); } =20 GRUB_MOD_FINI(term_gfxterm) =3D=3D=3D 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. + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +/* 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 =3D 0; + + /* Verify the simplifying assumptions. */ + if (src =3D=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "null src bitmap in grub_video_bitmap_create_scaled= "); + if (src->mode_info.red_field_pos % 8 !=3D 0 + || src->mode_info.green_field_pos % 8 !=3D 0 + || src->mode_info.blue_field_pos % 8 !=3D 0 + || src->mode_info.reserved_field_pos % 8 !=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "src format not supported for scale"); + if (src->mode_info.width =3D=3D 0 || src->mode_info.height =3D=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension= "); + if (dst_width <=3D 0 || dst_height <=3D 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 !=3D src->mode_info.bpp) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "bitmap to scale has inconsistent Bpp and bpp"); + + /* Create the new bitmap. */ + grub_err_t ret; + ret =3D grub_video_bitmap_create (dst, dst_width, dst_height, + src->mode_info.blit_format); + if (ret !=3D GRUB_ERR_NONE) + return ret; /* Error. */ + + switch (scale_method) + { + case GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST: + case GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST: + ret =3D scale_nn (*dst, src); + break; + case GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST: + case GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR: + ret =3D scale_bilinear (*dst, src); + break; + default: + ret =3D grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid scale_method val= ue"); + break; + } + + if (ret =3D=3D GRUB_ERR_NONE) + { + /* Success: *dst is now a pointer to the scaled bitmap. */ + return GRUB_ERR_NONE; + } + else + { + /* Destroy the bitmap and return the error code. */ + grub_video_bitmap_destroy (*dst); + *dst =3D 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) +{ + /* Verify the simplifying assumptions. */ + if (dst =3D=3D 0 || src =3D=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale_nn"); + if (dst->mode_info.red_field_pos % 8 !=3D 0 + || dst->mode_info.green_field_pos % 8 !=3D 0 + || dst->mode_info.blue_field_pos % 8 !=3D 0 + || dst->mode_info.reserved_field_pos % 8 !=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported"); + if (src->mode_info.red_field_pos % 8 !=3D 0 + || src->mode_info.green_field_pos % 8 !=3D 0 + || src->mode_info.blue_field_pos % 8 !=3D 0 + || src->mode_info.reserved_field_pos % 8 !=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported"); + if (dst->mode_info.red_field_pos !=3D src->mode_info.red_field_pos + || dst->mode_info.red_mask_size !=3D src->mode_info.red_mask_size + || dst->mode_info.green_field_pos !=3D src->mode_info.green_field_pos + || dst->mode_info.green_mask_size !=3D src->mode_info.green_mask_size + || dst->mode_info.blue_field_pos !=3D src->mode_info.blue_field_pos + || dst->mode_info.blue_mask_size !=3D src->mode_info.blue_mask_size + || dst->mode_info.reserved_field_pos !=3D + src->mode_info.reserved_field_pos + || dst->mode_info.reserved_mask_size !=3D + 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 !=3D src->mode_info.bytes_per_pixel) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"= ); + if (dst->mode_info.width =3D=3D 0 || dst->mode_info.height =3D=3D 0 + || src->mode_info.width =3D=3D 0 || src->mode_info.height =3D=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension= "); + + grub_uint8_t *ddata =3D dst->data; + grub_uint8_t *sdata =3D src->data; + int dw =3D dst->mode_info.width; + int dh =3D dst->mode_info.height; + int sw =3D src->mode_info.width; + int sh =3D src->mode_info.height; + int dstride =3D dst->mode_info.pitch; + int sstride =3D src->mode_info.pitch; + /* bytes_per_pixel is the same for both src and dst. */ + int bytes_per_pixel =3D dst->mode_info.bytes_per_pixel; + + int dy; + for (dy =3D 0; dy < dh; dy++) + { + int dx; + for (dx =3D 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 =3D dx/dw =3D> sx =3D sw*dx/dw. */ + sx =3D sw * dx / dw; + sy =3D sh * dy / dh; + + /* Get the address of the pixels in src and dst. */ + dptr =3D ddata + dy * dstride + dx * bytes_per_pixel; + sptr =3D sdata + sy * sstride + sx * bytes_per_pixel; + + /* Copy the pixel color value. */ + for (comp =3D 0; comp < bytes_per_pixel; comp++) + dptr[comp] =3D 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 algor= ithm + 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 *s= rc) +{ + /* Verify the simplifying assumptions. */ + if (dst =3D=3D 0 || src =3D=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale func"); + if (dst->mode_info.red_field_pos % 8 !=3D 0 + || dst->mode_info.green_field_pos % 8 !=3D 0 + || dst->mode_info.blue_field_pos % 8 !=3D 0 + || dst->mode_info.reserved_field_pos % 8 !=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported"); + if (src->mode_info.red_field_pos % 8 !=3D 0 + || src->mode_info.green_field_pos % 8 !=3D 0 + || src->mode_info.blue_field_pos % 8 !=3D 0 + || src->mode_info.reserved_field_pos % 8 !=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported"); + if (dst->mode_info.red_field_pos !=3D src->mode_info.red_field_pos + || dst->mode_info.red_mask_size !=3D src->mode_info.red_mask_size + || dst->mode_info.green_field_pos !=3D src->mode_info.green_field_pos + || dst->mode_info.green_mask_size !=3D src->mode_info.green_mask_size + || dst->mode_info.blue_field_pos !=3D src->mode_info.blue_field_pos + || dst->mode_info.blue_mask_size !=3D src->mode_info.blue_mask_size + || dst->mode_info.reserved_field_pos !=3D + src->mode_info.reserved_field_pos + || dst->mode_info.reserved_mask_size !=3D + 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 !=3D src->mode_info.bytes_per_pixel) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"= ); + if (dst->mode_info.width =3D=3D 0 || dst->mode_info.height =3D=3D 0 + || src->mode_info.width =3D=3D 0 || src->mode_info.height =3D=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension= "); + + grub_uint8_t *ddata =3D dst->data; + grub_uint8_t *sdata =3D src->data; + int dw =3D dst->mode_info.width; + int dh =3D dst->mode_info.height; + int sw =3D src->mode_info.width; + int sh =3D src->mode_info.height; + int dstride =3D dst->mode_info.pitch; + int sstride =3D src->mode_info.pitch; + /* bytes_per_pixel is the same for both src and dst. */ + int bytes_per_pixel =3D dst->mode_info.bytes_per_pixel; + + int dy; + for (dy =3D 0; dy < dh; dy++) + { + int dx; + for (dx =3D 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 =3D dx/dw =3D> sx =3D sw*dx/dw. */ + sx =3D sw * dx / dw; + sy =3D sh * dy / dh; + + /* Get the address of the pixels in src and dst. */ + dptr =3D ddata + dy * dstride + dx * bytes_per_pixel; + sptr =3D 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 =3D (256 * sw * dx / dw) - (sx * 256); + int v =3D (256 * sh * dy / dh) - (sy * 256); + + for (comp =3D 0; comp < bytes_per_pixel; comp++) + { + /* Get the component's values for the + four source corner pixels. */ + grub_uint8_t f00 =3D sptr[comp]; + grub_uint8_t f10 =3D sptr[comp + bytes_per_pixel]; + grub_uint8_t f01 =3D sptr[comp + sstride]; + grub_uint8_t f11 =3D sptr[comp + sstride + bytes_per_pix= el]; + + /* Do linear interpolations along the top and bottom + rows of the box. */ + grub_uint8_t f0y =3D (256 - v) * f00 / 256 + v * f01 / 2= 56; + grub_uint8_t f1y =3D (256 - v) * f10 / 256 + v * f11 / 2= 56; + + /* Interpolate vertically. */ + grub_uint8_t fxy =3D (256 - u) * f0y / 256 + u * f1y / 2= 56; + + dptr[comp] =3D fxy; + } + } + else + { + /* Fall back to nearest neighbor interpolation. */ + /* Copy the pixel color value. */ + for (comp =3D 0; comp < bytes_per_pixel; comp++) + dptr[comp] =3D sptr[comp]; + } + } + } + return GRUB_ERR_NONE; +} --MP_/y1sRvsitMtO=zU/YqNMc7hS-- --Sig_/s8mhBL=G+8Akh.NAWqChULp Content-Type: application/pgp-signature; name=signature.asc Content-Disposition: attachment; filename=signature.asc -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) iEYEARECAAYFAkmEtVYACgkQokx8fzcGbYc+tQCfX6Ly+IYMWE034LIcBVtPVsb6 +ksAnijSxuni8jLlnwF010LLgLUjqolW =8Hoi -----END PGP SIGNATURE----- --Sig_/s8mhBL=G+8Akh.NAWqChULp--