Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / video / bitmap_scale.c
blob73f50f61185b42591626123758026f6d3da82fa1
1 /* bitmap_scale.c - Bitmap scaling. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/mm.h>
21 #include <grub/misc.h>
22 #include <grub/video.h>
23 #include <grub/bitmap.h>
24 #include <grub/bitmap_scale.h>
25 #include <grub/types.h>
26 #include <grub/dl.h>
28 GRUB_MOD_LICENSE ("GPLv3+");
30 /* Prototypes for module-local functions. */
31 static grub_err_t scale_nn (struct grub_video_bitmap *dst,
32 struct grub_video_bitmap *src);
33 static grub_err_t scale_bilinear (struct grub_video_bitmap *dst,
34 struct grub_video_bitmap *src);
36 /* This function creates a new scaled version of the bitmap SRC. The new
37 bitmap has dimensions DST_WIDTH by DST_HEIGHT. The scaling algorithm
38 is given by SCALE_METHOD. If an error is encountered, the return code is
39 not equal to GRUB_ERR_NONE, and the bitmap DST is either not created, or
40 it is destroyed before this function returns.
42 Supports only direct color modes which have components separated
43 into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color).
44 But because of this simplifying assumption, the implementation is
45 greatly simplified. */
46 grub_err_t
47 grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
48 int dst_width, int dst_height,
49 struct grub_video_bitmap *src,
50 enum grub_video_bitmap_scale_method
51 scale_method)
53 *dst = 0;
55 /* Verify the simplifying assumptions. */
56 if (src == 0)
57 return grub_error (GRUB_ERR_BUG,
58 "null src bitmap in grub_video_bitmap_create_scaled");
59 if (src->mode_info.red_field_pos % 8 != 0
60 || src->mode_info.green_field_pos % 8 != 0
61 || src->mode_info.blue_field_pos % 8 != 0
62 || src->mode_info.reserved_field_pos % 8 != 0)
63 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
64 "src format not supported for scale");
65 if (src->mode_info.width == 0 || src->mode_info.height == 0)
66 return grub_error (GRUB_ERR_BAD_ARGUMENT,
67 "source bitmap has a zero dimension");
68 if (dst_width <= 0 || dst_height <= 0)
69 return grub_error (GRUB_ERR_BUG,
70 "requested to scale to a size w/ a zero dimension");
71 if (src->mode_info.bytes_per_pixel * 8 != src->mode_info.bpp)
72 return grub_error (GRUB_ERR_BUG,
73 "bitmap to scale has inconsistent Bpp and bpp");
75 /* Create the new bitmap. */
76 grub_err_t ret;
77 ret = grub_video_bitmap_create (dst, dst_width, dst_height,
78 src->mode_info.blit_format);
79 if (ret != GRUB_ERR_NONE)
80 return ret; /* Error. */
82 switch (scale_method)
84 case GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST:
85 case GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST:
86 ret = scale_nn (*dst, src);
87 break;
88 case GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST:
89 case GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR:
90 ret = scale_bilinear (*dst, src);
91 break;
92 default:
93 ret = grub_error (GRUB_ERR_BUG, "Invalid scale_method value");
94 break;
97 if (ret == GRUB_ERR_NONE)
99 /* Success: *dst is now a pointer to the scaled bitmap. */
100 return GRUB_ERR_NONE;
102 else
104 /* Destroy the bitmap and return the error code. */
105 grub_video_bitmap_destroy (*dst);
106 *dst = 0;
107 return ret;
111 /* Nearest neighbor bitmap scaling algorithm.
113 Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the
114 dimensions of DST. This function uses the nearest neighbor algorithm to
115 interpolate the pixels.
117 Supports only direct color modes which have components separated
118 into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color).
119 But because of this simplifying assumption, the implementation is
120 greatly simplified. */
121 static grub_err_t
122 scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
124 /* Verify the simplifying assumptions. */
125 if (dst == 0 || src == 0)
126 return grub_error (GRUB_ERR_BUG, "null bitmap in scale_nn");
127 if (dst->mode_info.red_field_pos % 8 != 0
128 || dst->mode_info.green_field_pos % 8 != 0
129 || dst->mode_info.blue_field_pos % 8 != 0
130 || dst->mode_info.reserved_field_pos % 8 != 0)
131 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
132 "dst format not supported");
133 if (src->mode_info.red_field_pos % 8 != 0
134 || src->mode_info.green_field_pos % 8 != 0
135 || src->mode_info.blue_field_pos % 8 != 0
136 || src->mode_info.reserved_field_pos % 8 != 0)
137 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
138 "src format not supported");
139 if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos
140 || dst->mode_info.red_mask_size != src->mode_info.red_mask_size
141 || dst->mode_info.green_field_pos != src->mode_info.green_field_pos
142 || dst->mode_info.green_mask_size != src->mode_info.green_mask_size
143 || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos
144 || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size
145 || dst->mode_info.reserved_field_pos !=
146 src->mode_info.reserved_field_pos
147 || dst->mode_info.reserved_mask_size !=
148 src->mode_info.reserved_mask_size)
149 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
150 "dst and src not compatible");
151 if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel)
152 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
153 "dst and src not compatible");
154 if (dst->mode_info.width == 0 || dst->mode_info.height == 0
155 || src->mode_info.width == 0 || src->mode_info.height == 0)
156 return grub_error (GRUB_ERR_BUG, "bitmap has a zero dimension");
158 grub_uint8_t *ddata = dst->data;
159 grub_uint8_t *sdata = src->data;
160 int dw = dst->mode_info.width;
161 int dh = dst->mode_info.height;
162 int sw = src->mode_info.width;
163 int sh = src->mode_info.height;
164 int dstride = dst->mode_info.pitch;
165 int sstride = src->mode_info.pitch;
166 /* bytes_per_pixel is the same for both src and dst. */
167 int bytes_per_pixel = dst->mode_info.bytes_per_pixel;
169 int dy;
170 for (dy = 0; dy < dh; dy++)
172 int dx;
173 for (dx = 0; dx < dw; dx++)
175 grub_uint8_t *dptr;
176 grub_uint8_t *sptr;
177 int sx;
178 int sy;
179 int comp;
181 /* Compute the source coordinate that the destination coordinate
182 maps to. Note: sx/sw = dx/dw => sx = sw*dx/dw. */
183 sx = sw * dx / dw;
184 sy = sh * dy / dh;
186 /* Get the address of the pixels in src and dst. */
187 dptr = ddata + dy * dstride + dx * bytes_per_pixel;
188 sptr = sdata + sy * sstride + sx * bytes_per_pixel;
190 /* Copy the pixel color value. */
191 for (comp = 0; comp < bytes_per_pixel; comp++)
192 dptr[comp] = sptr[comp];
195 return GRUB_ERR_NONE;
198 /* Bilinear interpolation image scaling algorithm.
200 Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the
201 dimensions of DST. This function uses the bilinear interpolation algorithm
202 to interpolate the pixels.
204 Supports only direct color modes which have components separated
205 into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color).
206 But because of this simplifying assumption, the implementation is
207 greatly simplified. */
208 static grub_err_t
209 scale_bilinear (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
211 /* Verify the simplifying assumptions. */
212 if (dst == 0 || src == 0)
213 return grub_error (GRUB_ERR_BUG, "null bitmap in scale func");
214 if (dst->mode_info.red_field_pos % 8 != 0
215 || dst->mode_info.green_field_pos % 8 != 0
216 || dst->mode_info.blue_field_pos % 8 != 0
217 || dst->mode_info.reserved_field_pos % 8 != 0)
218 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "dst format not supported");
219 if (src->mode_info.red_field_pos % 8 != 0
220 || src->mode_info.green_field_pos % 8 != 0
221 || src->mode_info.blue_field_pos % 8 != 0
222 || src->mode_info.reserved_field_pos % 8 != 0)
223 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "src format not supported");
224 if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos
225 || dst->mode_info.red_mask_size != src->mode_info.red_mask_size
226 || dst->mode_info.green_field_pos != src->mode_info.green_field_pos
227 || dst->mode_info.green_mask_size != src->mode_info.green_mask_size
228 || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos
229 || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size
230 || dst->mode_info.reserved_field_pos !=
231 src->mode_info.reserved_field_pos
232 || dst->mode_info.reserved_mask_size !=
233 src->mode_info.reserved_mask_size)
234 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "dst and src not compatible");
235 if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel)
236 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "dst and src not compatible");
237 if (dst->mode_info.width == 0 || dst->mode_info.height == 0
238 || src->mode_info.width == 0 || src->mode_info.height == 0)
239 return grub_error (GRUB_ERR_BUG, "bitmap has a zero dimension");
241 grub_uint8_t *ddata = dst->data;
242 grub_uint8_t *sdata = src->data;
243 int dw = dst->mode_info.width;
244 int dh = dst->mode_info.height;
245 int sw = src->mode_info.width;
246 int sh = src->mode_info.height;
247 int dstride = dst->mode_info.pitch;
248 int sstride = src->mode_info.pitch;
249 /* bytes_per_pixel is the same for both src and dst. */
250 int bytes_per_pixel = dst->mode_info.bytes_per_pixel;
252 int dy;
253 for (dy = 0; dy < dh; dy++)
255 int dx;
256 for (dx = 0; dx < dw; dx++)
258 grub_uint8_t *dptr;
259 grub_uint8_t *sptr;
260 int sx;
261 int sy;
262 int comp;
264 /* Compute the source coordinate that the destination coordinate
265 maps to. Note: sx/sw = dx/dw => sx = sw*dx/dw. */
266 sx = sw * dx / dw;
267 sy = sh * dy / dh;
269 /* Get the address of the pixels in src and dst. */
270 dptr = ddata + dy * dstride + dx * bytes_per_pixel;
271 sptr = sdata + sy * sstride + sx * bytes_per_pixel;
273 /* If we have enough space to do so, use bilinear interpolation.
274 Otherwise, fall back to nearest neighbor for this pixel. */
275 if (sx < sw - 1 && sy < sh - 1)
277 /* Do bilinear interpolation. */
279 /* Fixed-point .8 numbers representing the fraction of the
280 distance in the x (u) and y (v) direction within the
281 box of 4 pixels in the source. */
282 int u = (256 * sw * dx / dw) - (sx * 256);
283 int v = (256 * sh * dy / dh) - (sy * 256);
285 for (comp = 0; comp < bytes_per_pixel; comp++)
287 /* Get the component's values for the
288 four source corner pixels. */
289 grub_uint8_t f00 = sptr[comp];
290 grub_uint8_t f10 = sptr[comp + bytes_per_pixel];
291 grub_uint8_t f01 = sptr[comp + sstride];
292 grub_uint8_t f11 = sptr[comp + sstride + bytes_per_pixel];
294 /* Do linear interpolations along the top and bottom
295 rows of the box. */
296 grub_uint8_t f0y = (256 - v) * f00 / 256 + v * f01 / 256;
297 grub_uint8_t f1y = (256 - v) * f10 / 256 + v * f11 / 256;
299 /* Interpolate vertically. */
300 grub_uint8_t fxy = (256 - u) * f0y / 256 + u * f1y / 256;
302 dptr[comp] = fxy;
305 else
307 /* Fall back to nearest neighbor interpolation. */
308 /* Copy the pixel color value. */
309 for (comp = 0; comp < bytes_per_pixel; comp++)
310 dptr[comp] = sptr[comp];
314 return GRUB_ERR_NONE;