Пример #1
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.  */
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;
    }
}
Пример #2
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;

  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;
    }
}
Пример #3
0
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;
}
Пример #4
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;
    }
}
Пример #5
0
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;
    }
}
Пример #6
0
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;
}
Пример #7
0
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;
}