/* 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. */ static grub_err_t grub_video_bitmap_create_scaled_internal (struct grub_video_bitmap **dst, int dst_width, int dst_height, struct grub_video_bitmap *src, int scale_method) { /* Create the new bitmap. */ grub_err_t ret; ret = grub_video_bitmap_create (dst, dst_width, dst_height, src->mode_info.blit_format); if (ret != GRUB_ERR_NONE) return ret; /* Error. */ (*dst)->transparent = src->transparent; 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) { /* 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 = 0; return ret; } }
/* 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; grub_err_t err = verify_source_bitmap(src); if (err != GRUB_ERR_NONE) return err; if (dst_width <= 0 || dst_height <= 0) return grub_error (GRUB_ERR_BUG, "requested to scale to a size w/ a zero dimension"); /* Create the new bitmap. */ grub_err_t ret; ret = grub_video_bitmap_create (dst, dst_width, dst_height, src->mode_info.blit_format); if (ret != GRUB_ERR_NONE) return ret; /* Error. */ ret = grub_video_bitmap_scale (*dst, src, scale_method); if (ret == 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 = 0; return ret; } }
grub_err_t grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst, int dst_width, int dst_height, struct grub_video_bitmap *src, int scale, grub_video_color_t color) { int type, method; int src_width, src_height, width, height; struct grub_video_fbblit_info dst_info; struct grub_video_bitmap *tmp = 0; grub_err_t ret; *dst = 0; /* Verify the simplifying assumptions. */ if (src == 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 != 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, "source 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"); type = scale & GRUB_VIDEO_BITMAP_SCALE_TYPE_MASK; method = scale & GRUB_VIDEO_BITMAP_SCALE_METHOD_MASK; src_width = src->mode_info.width; src_height = src->mode_info.height; if ((src_width == dst_width) && (src_height == dst_height)) type = GRUB_VIDEO_BITMAP_SCALE_TYPE_CENTER; if ((type == GRUB_VIDEO_BITMAP_SCALE_TYPE_NORMAL) || (((type == GRUB_VIDEO_BITMAP_SCALE_TYPE_MINFIT) || (type == GRUB_VIDEO_BITMAP_SCALE_TYPE_MAXFIT)) && (src_width * dst_height == src_height * dst_width))) return grub_video_bitmap_create_scaled_internal (dst, dst_width, dst_height, src, method); ret = grub_video_bitmap_create (dst, dst_width, dst_height, src->mode_info.blit_format); if (ret != GRUB_ERR_NONE) return ret; /* Error. */ (*dst)->transparent = src->transparent; dst_info.mode_info = &(*dst)->mode_info; dst_info.data = (*dst)->data; color = map_color (dst_info.mode_info, color); switch (type) { case GRUB_VIDEO_BITMAP_SCALE_TYPE_MINFIT: case GRUB_VIDEO_BITMAP_SCALE_TYPE_MAXFIT: { if ((src_width * dst_height > src_height * dst_width) == (type == GRUB_VIDEO_BITMAP_SCALE_TYPE_MAXFIT)) { width = src_width * dst_height / src_height; height = dst_height; } else { width = dst_width; height = src_height * dst_width / src_width; } ret = grub_video_bitmap_create_scaled_internal (&tmp, width, height, src, method); if (ret) return ret; src = tmp; src_width = width; src_height = height; } case GRUB_VIDEO_BITMAP_SCALE_TYPE_CENTER: { int src_x, src_y, dst_x, dst_y; struct grub_video_fbblit_info src_info; width = (src_width > dst_width) ? dst_width : src_width; height = (src_height > dst_height) ? dst_height : src_height; src_x = (src_width - width) >> 1; src_y = (src_height - height) >> 1; dst_x = (dst_width - width) >> 1; dst_y = (dst_height - height) >> 1; if (dst_y) { grub_video_fbfill (&dst_info, color, 0, 0, dst_width, dst_y); grub_video_fbfill (&dst_info, color, 0, dst_y + height, dst_width, dst_height - dst_y - height); } if (dst_x) { grub_video_fbfill (&dst_info, color, 0, dst_y, dst_x, height); grub_video_fbfill (&dst_info, color, dst_x + width, dst_y, dst_width - dst_x - width, height); } src_info.mode_info = &src->mode_info; src_info.data = src->data; grub_video_fbblit (&dst_info, &src_info, GRUB_VIDEO_BLIT_REPLACE, dst_x, dst_y, width, height, src_x, src_y); break; } case GRUB_VIDEO_BITMAP_SCALE_TYPE_TILING: { int x, y; struct grub_video_fbblit_info src_info; src_info.mode_info = &src->mode_info; src_info.data = src->data; for (y = 0; y < dst_height; y += src_height) { for (x = 0; x < dst_width; x += src_width) { int w, h; w = src_width; if (x + w > dst_width) w = dst_width - x; h = src_height; if (y + h > dst_height) h = dst_height - y; grub_video_fbblit (&dst_info, &src_info, GRUB_VIDEO_BLIT_REPLACE, x, y, w, h, 0, 0); } } break; } default: return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid scale type value"); } if (tmp) grub_video_bitmap_destroy (tmp); return 0; }
/* 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. */ if (src == 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 != 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, "source 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"); /* Create the new bitmap. */ grub_err_t ret; ret = grub_video_bitmap_create (dst, dst_width, dst_height, src->mode_info.blit_format); 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) { /* 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 = 0; return ret; } }
grub_err_t grub_video_bitmap_scale_proportional (struct grub_video_bitmap **dst, int dst_width, int dst_height, struct grub_video_bitmap *src, enum grub_video_bitmap_scale_method scale_method, grub_video_bitmap_selection_method_t selection_method, grub_video_bitmap_v_align_t v_align, grub_video_bitmap_h_align_t h_align) { *dst = 0; grub_err_t ret = verify_source_bitmap(src); if (ret != GRUB_ERR_NONE) return ret; if (dst_width <= 0 || dst_height <= 0) return grub_error (GRUB_ERR_BUG, "requested to scale to a size w/ a zero dimension"); ret = grub_video_bitmap_create (dst, dst_width, dst_height, src->mode_info.blit_format); if (ret != GRUB_ERR_NONE) return ret; /* Error. */ unsigned dx0 = 0; unsigned dy0 = 0; unsigned dw = dst_width; unsigned dh = dst_height; unsigned sx0 = 0; unsigned sy0 = 0; unsigned sw = src->mode_info.width; unsigned sh = src->mode_info.height; switch (selection_method) { case GRUB_VIDEO_BITMAP_SELECTION_METHOD_CROP: /* Comparing sw/sh VS dw/dh. */ if (sw * dh < dw * sh) ret = make_v_align (&sy0, &sh, sw * dh / dw, v_align); else ret = make_h_align (&sx0, &sw, sh * dw / dh, h_align); break; case GRUB_VIDEO_BITMAP_SELECTION_METHOD_PADDING: if (sw * dh < dw * sh) ret = make_h_align (&dx0, &dw, sw * dh / sh, h_align); else ret = make_v_align (&dy0, &dh, sh * dw / sw, v_align); break; case GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITWIDTH: if (sw * dh < dw * sh) ret = make_v_align (&sy0, &sh, sw * dh / dw, v_align); else ret = make_v_align (&dy0, &dh, sh * dw / sw, v_align); break; case GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITHEIGHT: if (sw * dh < dw * sh) ret = make_h_align (&dx0, &dw, sw * dh / sh, h_align); else ret = make_h_align (&sx0, &sw, sh * dw / dh, h_align); break; default: ret = grub_error (GRUB_ERR_BUG, "Invalid selection_method value"); break; } if (ret == GRUB_ERR_NONE) { /* Backup original data. */ int src_width_orig = src->mode_info.width; int src_height_orig = src->mode_info.height; grub_uint8_t *src_data_orig = src->data; int dst_width_orig = (*dst)->mode_info.width; int dst_height_orig = (*dst)->mode_info.height; grub_uint8_t *dst_data_orig = (*dst)->data; 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 = src->mode_info.bytes_per_pixel; /* Crop src and dst. */ src->mode_info.width = sw; src->mode_info.height = sh; src->data = (grub_uint8_t *) src->data + sx0 * bytes_per_pixel + sy0 * sstride; (*dst)->mode_info.width = dw; (*dst)->mode_info.height = dh; (*dst)->data = (grub_uint8_t *) (*dst)->data + dx0 * bytes_per_pixel + dy0 * dstride; /* Scale our image. */ ret = grub_video_bitmap_scale (*dst, src, scale_method); /* Restore original data. */ src->mode_info.width = src_width_orig; src->mode_info.height = src_height_orig; src->data = src_data_orig; (*dst)->mode_info.width = dst_width_orig; (*dst)->mode_info.height = dst_height_orig; (*dst)->data = dst_data_orig; } if (ret == 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 = 0; return ret; } }
static grub_err_t grub_video_reader_tga (struct grub_video_bitmap **bitmap, const char *filename) { grub_file_t file; grub_ssize_t pos; struct grub_tga_header header; int has_alpha; file = grub_buffile_open (filename, 0); if (! file) return grub_errno; /* TGA Specification states that we SHOULD start by reading ID from end of file, but we really don't care about that as we are not going to support developer area & extensions at this point. */ /* Read TGA header from beginning of file. */ if (grub_file_read (file, &header, sizeof (header)) != sizeof (header)) { grub_file_close (file); return grub_errno; } /* Skip ID field. */ pos = grub_file_tell (file); pos += header.id_length; grub_file_seek (file, pos); if (grub_errno != GRUB_ERR_NONE) { grub_file_close (file); return grub_errno; } #if defined(TGA_DEBUG) grub_printf("tga: header\n"); dump_int_field(header.id_length); dump_int_field(header.color_map_type); dump_int_field(header.image_type); dump_int_field(header.color_map_first_index); dump_int_field(header.color_map_length); dump_int_field(header.color_map_bpp); dump_int_field(header.image_x_origin); dump_int_field(header.image_y_origin); dump_int_field(header.image_width); dump_int_field(header.image_height); dump_int_field(header.image_bpp); dump_int_field(header.image_descriptor); #endif /* Check that bitmap encoding is supported. */ switch (header.image_type) { case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR: case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR: break; default: grub_file_close (file); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported bitmap format (unknown encoding)"); } /* Check that bitmap depth is supported. */ switch (header.image_bpp) { case 24: has_alpha = 0; break; case 32: has_alpha = 1; break; default: grub_file_close (file); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported bitmap format (bpp=%d)", header.image_bpp); } /* Allocate bitmap. If there is alpha information store it too. */ if (has_alpha) { grub_video_bitmap_create (bitmap, header.image_width, header.image_height, GRUB_VIDEO_BLIT_FORMAT_RGBA_8888); if (grub_errno != GRUB_ERR_NONE) { grub_file_close (file); return grub_errno; } /* Load bitmap data. */ switch (header.image_type) { case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR: tga_load_truecolor_R8G8B8A8 (*bitmap, &header, file); break; case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR: tga_load_truecolor_rle_R8G8B8A8 (*bitmap, &header, file); break; } } else { grub_video_bitmap_create (bitmap, header.image_width, header.image_height, GRUB_VIDEO_BLIT_FORMAT_RGB_888); if (grub_errno != GRUB_ERR_NONE) { grub_file_close (file); return grub_errno; } /* Load bitmap data. */ switch (header.image_type) { case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR: tga_load_truecolor_R8G8B8 (*bitmap, &header, file); break; case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR: tga_load_truecolor_rle_R8G8B8 (*bitmap, &header, file); break; } } /* If there was a loading problem, destroy bitmap. */ if (grub_errno != GRUB_ERR_NONE) { grub_video_bitmap_destroy (*bitmap); *bitmap = 0; } grub_file_close (file); return grub_errno; }
static grub_err_t grub_video_reader_tga (struct grub_video_bitmap **bitmap, const char *filename) { grub_ssize_t pos; struct tga_data data; grub_memset (&data, 0, sizeof (data)); data.file = grub_buffile_open (filename, 0); if (! data.file) return grub_errno; /* TGA Specification states that we SHOULD start by reading ID from end of file, but we really don't care about that as we are not going to support developer area & extensions at this point. */ /* Read TGA header from beginning of file. */ if (grub_file_read (data.file, &data.hdr, sizeof (data.hdr)) != sizeof (data.hdr)) { grub_file_close (data.file); return grub_errno; } /* Skip ID field. */ pos = grub_file_tell (data.file); pos += data.hdr.id_length; grub_file_seek (data.file, pos); if (grub_errno != GRUB_ERR_NONE) { grub_file_close (data.file); return grub_errno; } grub_dprintf("tga", "tga: header\n"); dump_int_field(data.hdr.id_length); dump_int_field(data.hdr.color_map_type); dump_int_field(data.hdr.image_type); dump_int_field(data.hdr.color_map_first_index); dump_int_field(data.hdr.color_map_length); dump_int_field(data.hdr.color_map_bpp); dump_int_field(data.hdr.image_x_origin); dump_int_field(data.hdr.image_y_origin); dump_int_field(data.hdr.image_width); dump_int_field(data.hdr.image_height); dump_int_field(data.hdr.image_bpp); dump_int_field(data.hdr.image_descriptor); data.image_width = grub_le_to_cpu16 (data.hdr.image_width); data.image_height = grub_le_to_cpu16 (data.hdr.image_height); /* Check that bitmap encoding is supported. */ switch (data.hdr.image_type) { case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR: case GRUB_TGA_IMAGE_TYPE_RLE_BLACK_AND_WHITE: case GRUB_TGA_IMAGE_TYPE_RLE_INDEXCOLOR: data.uses_rle = 1; break; case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR: case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_BLACK_AND_WHITE: case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_INDEXCOLOR: data.uses_rle = 0; break; default: grub_file_close (data.file); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported bitmap format (unknown encoding %d)", data.hdr.image_type); } data.bpp = data.hdr.image_bpp / 8; /* Check that bitmap depth is supported. */ switch (data.hdr.image_type) { case GRUB_TGA_IMAGE_TYPE_RLE_BLACK_AND_WHITE: case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_BLACK_AND_WHITE: if (data.hdr.image_bpp != 8) { grub_file_close (data.file); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported bitmap format (bpp=%d)", data.hdr.image_bpp); } grub_video_bitmap_create (bitmap, data.image_width, data.image_height, GRUB_VIDEO_BLIT_FORMAT_RGB_888); if (grub_errno != GRUB_ERR_NONE) { grub_file_close (data.file); return grub_errno; } data.bitmap = *bitmap; /* Load bitmap data. */ tga_load_grayscale (&data); break; case GRUB_TGA_IMAGE_TYPE_RLE_INDEXCOLOR: case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_INDEXCOLOR: if (data.hdr.image_bpp != 8 || data.hdr.color_map_bpp != 24 || data.hdr.color_map_first_index != 0) { grub_file_close (data.file); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported bitmap format (bpp=%d)", data.hdr.image_bpp); } grub_video_bitmap_create (bitmap, data.image_width, data.image_height, GRUB_VIDEO_BLIT_FORMAT_RGB_888); if (grub_errno != GRUB_ERR_NONE) { grub_file_close (data.file); return grub_errno; } data.bitmap = *bitmap; /* Load bitmap data. */ tga_load_palette (&data); tga_load_index_color (&data); break; case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR: case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR: switch (data.hdr.image_bpp) { case 24: grub_video_bitmap_create (bitmap, data.image_width, data.image_height, GRUB_VIDEO_BLIT_FORMAT_RGB_888); if (grub_errno != GRUB_ERR_NONE) { grub_file_close (data.file); return grub_errno; } data.bitmap = *bitmap; /* Load bitmap data. */ tga_load_truecolor_R8G8B8 (&data); break; case 32: grub_video_bitmap_create (bitmap, data.image_width, data.image_height, GRUB_VIDEO_BLIT_FORMAT_RGBA_8888); if (grub_errno != GRUB_ERR_NONE) { grub_file_close (data.file); return grub_errno; } data.bitmap = *bitmap; /* Load bitmap data. */ tga_load_truecolor_R8G8B8A8 (&data); break; default: grub_file_close (data.file); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported bitmap format (bpp=%d)", data.hdr.image_bpp); } } /* If there was a loading problem, destroy bitmap. */ if (grub_errno != GRUB_ERR_NONE) { grub_video_bitmap_destroy (*bitmap); *bitmap = 0; } grub_file_close (data.file); return grub_errno; }