Пример #1
0
/* rle_tga_read32:
 *  Helper for reading 32 bit RLE data from TGA files.
 */
static void rle_tga_read32 (uint32_t* address, int w, FILE *f)
{
  unsigned char value[4];
  int count;
  int c = 0;

  do {
    count = fgetc(f);
    if (count & 0x80) {
      count = (count & 0x7F) + 1;
      c += count;
      fread(value, 1, 4, f);
      while (count--)
        *(address++) = _rgba(value[2], value[1], value[0], value[3]);
    }
    else {
      count++;
      c += count;
      while (count--) {
        fread(value, 1, 4, f);
        *(address++) = _rgba(value[2], value[1], value[0], value[3]);
      }
    }
  } while (c < w);
}
Пример #2
0
static Palette *ase_file_read_color2_chunk(FILE *f, Sprite *sprite, int frame)
{
  int i, c, r, g, b, packets, skip, size;
  Palette* pal = new Palette(*sprite->getPalette(frame));
  pal->setFrame(frame);

  packets = fgetw(f);   // Number of packets
  skip = 0;

  // Read all packets
  for (i=0; i<packets; i++) {
    skip += fgetc(f);
    size = fgetc(f);
    if (!size) size = 256;

    for (c=skip; c<skip+size; c++) {
      r = fgetc(f);
      g = fgetc(f);
      b = fgetc(f);
      pal->setEntry(c, _rgba(r, g, b, 255));
    }
  }

  return pal;
}
Пример #3
0
 RgbTraits::pixel_t read_pixel(FILE* f) {
   r = fgetc(f);
   g = fgetc(f);
   b = fgetc(f);
   a = fgetc(f);
   return _rgba(r, g, b, a);
 }
Пример #4
0
void InvertColorFilter::applyToRgba(FilterManager* filterMgr)
{
    const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress();
    uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress();
    int w = filterMgr->getWidth();
    Target target = filterMgr->getTarget();
    int x, c, r, g, b, a;

    for (x=0; x<w; x++) {
        if (filterMgr->skipPixel()) {
            ++src_address;
            ++dst_address;
            continue;
        }

        c = *(src_address++);

        r = _rgba_getr(c);
        g = _rgba_getg(c);
        b = _rgba_getb(c);
        a = _rgba_geta(c);

        if (target & TARGET_RED_CHANNEL) r ^= 0xff;
        if (target & TARGET_GREEN_CHANNEL) g ^= 0xff;
        if (target & TARGET_BLUE_CHANNEL) b ^= 0xff;
        if (target & TARGET_ALPHA_CHANNEL) a ^= 0xff;

        *(dst_address++) = _rgba(r, g, b, a);
    }
}
Пример #5
0
void MedianFilter::applyToRgba(FilterManager* filterMgr)
{
  const Image* src = filterMgr->getSourceImage();
  uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress();
  Target target = filterMgr->getTarget();
  int color;
  int r, g, b, a;
  GetPixelsDelegateRgba delegate(m_channel);
  int x = filterMgr->getX();
  int x2 = x+filterMgr->getWidth();
  int y = filterMgr->getY();

  for (; x<x2; ++x) {
    // Avoid the non-selected region
    if (filterMgr->skipPixel()) {
      ++dst_address;
      continue;
    }

    delegate.reset();
    get_neighboring_pixels<RgbTraits>(src, x, y, m_width, m_height, m_width/2, m_height/2,
                                      m_tiledMode, delegate);

    color = image_getpixel_fast<RgbTraits>(src, x, y);

    if (target & TARGET_RED_CHANNEL) {
      std::sort(m_channel[0].begin(), m_channel[0].end());
      r = m_channel[0][m_ncolors/2];
    }
    else
      r = _rgba_getr(color);

    if (target & TARGET_GREEN_CHANNEL) {
      std::sort(m_channel[1].begin(), m_channel[1].end());
      g = m_channel[1][m_ncolors/2];
    }
    else
      g = _rgba_getg(color);

    if (target & TARGET_BLUE_CHANNEL) {
      std::sort(m_channel[2].begin(), m_channel[2].end());
      b = m_channel[2][m_ncolors/2];
    }
    else
      b = _rgba_getb(color);

    if (target & TARGET_ALPHA_CHANNEL) {
      std::sort(m_channel[3].begin(), m_channel[3].end());
      a = m_channel[3][m_ncolors/2];
    }
    else
      a = _rgba_geta(color);

    *(dst_address++) = _rgba(r, g, b, a);
  }
}
Пример #6
0
 void read_scanline(RgbTraits::address_t address, int w, uint8_t* buffer)
 {
   for (int x=0; x<w; ++x) {
     r = *(buffer++);
     g = *(buffer++);
     b = *(buffer++);
     a = *(buffer++);
     *(address++) = _rgba(r, g, b, a);
   }
 }
Пример #7
0
 inline void operator()(RgbTraits::address_t& scanline_address,
                        RgbTraits::address_t& dst_address,
                        GrayscaleTraits::address_t& src_address,
                        int opacity)
 {
   if (*src_address != m_mask_color) {
     int v = _graya_getv(*src_address);
     *scanline_address = (*m_blend_color)(*dst_address, _rgba(v, v, v, _graya_geta(*src_address)), opacity);
   }
   else
     *scanline_address = *dst_address;
 }
Пример #8
0
Sprite::Sprite(PixelFormat format, int width, int height, int ncolors)
  : GfxObj(GFXOBJ_SPRITE)
  , m_format(format)
  , m_width(width)
  , m_height(height)
  , m_frames(1)
{
  ASSERT(width > 0 && height > 0);

  m_frlens.push_back(100);      // First frame with 100 msecs of duration
  m_stock = new Stock(format);
  m_folder = new LayerFolder(this);

  // Generate palette
  Palette pal(FrameNumber(0), ncolors);

  switch (format) {

    // For colored images
    case IMAGE_RGB:
    case IMAGE_INDEXED:
      pal.resize(ncolors);
      break;

    // For black and white images
    case IMAGE_GRAYSCALE:
    case IMAGE_BITMAP:
      for (int c=0; c<ncolors; c++) {
        int g = 255 * c / (ncolors-1);
        g = MID(0, g, 255);
        pal.setEntry(c, _rgba(g, g, g, 255));
      }
      break;
  }

  // Initial RGB map
  m_rgbMap = NULL;

  // The transparent color for indexed images is 0 by default
  m_transparentColor = 0;

  setPalette(&pal, true);
}
Пример #9
0
/**
 * Resizes the source image @a src to the destination image @a dst.
 *
 * @warning If you are using the RESIZE_METHOD_BILINEAR, it is
 * recommended to use @ref image_fixup_transparent_colors function
 * over the source image @a src before using this routine.
 */
void image_resize(const Image* src, Image* dst, ResizeMethod method, const Palette* pal, const RgbMap* rgbmap)
{
  switch (method) {

    // TODO optimize this
    case RESIZE_METHOD_NEAREST_NEIGHBOR: {
      uint32_t color;
      double u, v, du, dv;
      int x, y;

      u = v = 0.0;
      du = src->w * 1.0 / dst->w;
      dv = src->h * 1.0 / dst->h;
      for (y=0; y<dst->h; ++y) {
        for (x=0; x<dst->w; ++x) {
          color = src->getpixel(MID(0, u, src->w-1),
                                MID(0, v, src->h-1));
          dst->putpixel(x, y, color);
          u += du;
        }
        u = 0.0;
        v += dv;
      }
      break;
    }

    // TODO optimize this
    case RESIZE_METHOD_BILINEAR: {
      uint32_t color[4], dst_color = 0;
      double u, v, du, dv;
      int u_floor, u_floor2;
      int v_floor, v_floor2;
      int x, y;

      u = v = 0.0;
      du = (src->w-1) * 1.0 / (dst->w-1);
      dv = (src->h-1) * 1.0 / (dst->h-1);
      for (y=0; y<dst->h; ++y) {
        for (x=0; x<dst->w; ++x) {
          u_floor = floor(u);
          v_floor = floor(v);

          if (u_floor > src->w-1) {
            u_floor = src->w-1;
            u_floor2 = src->w-1;
          }
          else if (u_floor == src->w-1)
            u_floor2 = u_floor;
          else
            u_floor2 = u_floor+1;

          if (v_floor > src->h-1) {
            v_floor = src->h-1;
            v_floor2 = src->h-1;
          }
          else if (v_floor == src->h-1)
            v_floor2 = v_floor;
          else
            v_floor2 = v_floor+1;

          // get the four colors
          color[0] = src->getpixel(u_floor,  v_floor);
          color[1] = src->getpixel(u_floor2, v_floor);
          color[2] = src->getpixel(u_floor,  v_floor2);
          color[3] = src->getpixel(u_floor2, v_floor2);

          // calculate the interpolated color
          double u1 = u - u_floor;
          double v1 = v - v_floor;
          double u2 = 1 - u1;
          double v2 = 1 - v1;

          switch (dst->getPixelFormat()) {
            case IMAGE_RGB: {
              int r = ((_rgba_getr(color[0])*u2 + _rgba_getr(color[1])*u1)*v2 +
                       (_rgba_getr(color[2])*u2 + _rgba_getr(color[3])*u1)*v1);
              int g = ((_rgba_getg(color[0])*u2 + _rgba_getg(color[1])*u1)*v2 +
                       (_rgba_getg(color[2])*u2 + _rgba_getg(color[3])*u1)*v1);
              int b = ((_rgba_getb(color[0])*u2 + _rgba_getb(color[1])*u1)*v2 +
                       (_rgba_getb(color[2])*u2 + _rgba_getb(color[3])*u1)*v1);
              int a = ((_rgba_geta(color[0])*u2 + _rgba_geta(color[1])*u1)*v2 +
                       (_rgba_geta(color[2])*u2 + _rgba_geta(color[3])*u1)*v1);
              dst_color = _rgba(r, g, b, a);
              break;
            }
            case IMAGE_GRAYSCALE: {
              int v = ((_graya_getv(color[0])*u2 + _graya_getv(color[1])*u1)*v2 +
                       (_graya_getv(color[2])*u2 + _graya_getv(color[3])*u1)*v1);
              int a = ((_graya_geta(color[0])*u2 + _graya_geta(color[1])*u1)*v2 +
                       (_graya_geta(color[2])*u2 + _graya_geta(color[3])*u1)*v1);
              dst_color = _graya(v, a);
              break;
            }
            case IMAGE_INDEXED: {
              int r = ((_rgba_getr(pal->getEntry(color[0]))*u2 + _rgba_getr(pal->getEntry(color[1]))*u1)*v2 +
                       (_rgba_getr(pal->getEntry(color[2]))*u2 + _rgba_getr(pal->getEntry(color[3]))*u1)*v1);
              int g = ((_rgba_getg(pal->getEntry(color[0]))*u2 + _rgba_getg(pal->getEntry(color[1]))*u1)*v2 +
                       (_rgba_getg(pal->getEntry(color[2]))*u2 + _rgba_getg(pal->getEntry(color[3]))*u1)*v1);
              int b = ((_rgba_getb(pal->getEntry(color[0]))*u2 + _rgba_getb(pal->getEntry(color[1]))*u1)*v2 +
                       (_rgba_getb(pal->getEntry(color[2]))*u2 + _rgba_getb(pal->getEntry(color[3]))*u1)*v1);
              int a = (((color[0] == 0 ? 0: 255)*u2 + (color[1] == 0 ? 0: 255)*u1)*v2 +
                       ((color[2] == 0 ? 0: 255)*u2 + (color[3] == 0 ? 0: 255)*u1)*v1);
              dst_color = a > 127 ? rgbmap->mapColor(r, g, b): 0;
              break;
            }
            case IMAGE_BITMAP: {
              int g = ((255*color[0]*u2 + 255*color[1]*u1)*v2 +
                       (255*color[2]*u2 + 255*color[3]*u1)*v1);
              dst_color = g > 127 ? 1: 0;
              break;
            }
          }

          dst->putpixel(x, y, dst_color);
          u += du;
        }
        u = 0.0;
        v += dv;
      }
      break;
    }

  }
}
Пример #10
0
/**
 * This routine does not modify the image to the human eye, but
 * internally tries to fixup all colors that are completelly
 * transparent (alpha = 0) with the average of its 4-neighbors.
 */
void image_fixup_transparent_colors(Image* image)
{
  int x, y, u, v;

  switch (image->getPixelFormat()) {

    case IMAGE_RGB: {
      uint32_t c;
      int r, g, b, count;

      for (y=0; y<image->h; ++y) {
        for (x=0; x<image->w; ++x) {
          c = image_getpixel_fast<RgbTraits>(image, x, y);

          // if this is a completelly-transparent pixel...
          if (_rgba_geta(c) == 0) {
            count = 0;
            r = g = b = 0;

            for (v=y-1; v<=y+1; ++v) {
              for (u=x-1; u<=x+1; ++u) {
                if ((u >= 0) && (v >= 0) && (u < image->w) && (v < image->h)) {
                  c = image_getpixel_fast<RgbTraits>(image, u, v);
                  if (_rgba_geta(c) > 0) {
                    r += _rgba_getr(c);
                    g += _rgba_getg(c);
                    b += _rgba_getb(c);
                    ++count;
                  }
                }
              }
            }

            if (count > 0) {
              r /= count;
              g /= count;
              b /= count;
              image_putpixel_fast<RgbTraits>(image, x, y, _rgba(r, g, b, 0));
            }
          }
        }
      }
      break;
    }

    case IMAGE_GRAYSCALE: {
      uint16_t c;
      int k, count;

      for (y=0; y<image->h; ++y) {
        for (x=0; x<image->w; ++x) {
          c = image_getpixel_fast<GrayscaleTraits>(image, x, y);

          // if this is a completelly-transparent pixel...
          if (_graya_geta(c) == 0) {
            count = 0;
            k = 0;

            for (v=y-1; v<=y+1; ++v) {
              for (u=x-1; u<=x+1; ++u) {
                if ((u >= 0) && (v >= 0) && (u < image->w) && (v < image->h)) {
                  c = image_getpixel_fast<GrayscaleTraits>(image, u, v);
                  if (_graya_geta(c) > 0) {
                    k += _graya_getv(c);
                    ++count;
                  }
                }
              }
            }

            if (count > 0) {
              k /= count;
              image_putpixel_fast<GrayscaleTraits>(image, x, y, _graya(k, 0));
            }
          }
        }
      }
      break;
    }

  }
}
Пример #11
0
bool JpegFormat::onLoad(FileOp* fop)
{
  struct jpeg_decompress_struct cinfo;
  struct error_mgr jerr;
  Image *image;
  FILE *file;
  JDIMENSION num_scanlines;
  JSAMPARRAY buffer;
  JDIMENSION buffer_height;
  int c;

  file = fopen(fop->filename.c_str(), "rb");
  if (!file)
    return false;

  // Initialize the JPEG decompression object with error handling.
  jerr.fop = fop;
  cinfo.err = jpeg_std_error(&jerr.head);

  jerr.head.error_exit = error_exit;
  jerr.head.output_message = output_message;

  // Establish the setjmp return context for error_exit to use.
  if (setjmp(jerr.setjmp_buffer)) {
    jpeg_destroy_decompress(&cinfo);
    fclose(file);
    return false;
  }

  jpeg_create_decompress(&cinfo);

  // Specify data source for decompression.
  jpeg_stdio_src(&cinfo, file);

  // Read file header, set default decompression parameters.
  jpeg_read_header(&cinfo, true);

  if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
    cinfo.out_color_space = JCS_GRAYSCALE;
  else
    cinfo.out_color_space = JCS_RGB;

  // Start decompressor.
  jpeg_start_decompress(&cinfo);

  // Create the image.
  image = fop_sequence_image(fop,
			     (cinfo.out_color_space == JCS_RGB ? IMAGE_RGB:
								 IMAGE_GRAYSCALE),
			     cinfo.output_width,
			     cinfo.output_height);
  if (!image) {
    jpeg_destroy_decompress(&cinfo);
    fclose(file);
    return false;
  }

  // Create the buffer.
  buffer_height = cinfo.rec_outbuf_height;
  buffer = (JSAMPARRAY)base_malloc(sizeof(JSAMPROW) * buffer_height);
  if (!buffer) {
    jpeg_destroy_decompress(&cinfo);
    fclose(file);
    return false;
  }

  for (c=0; c<(int)buffer_height; c++) {
    buffer[c] = (JSAMPROW)base_malloc(sizeof(JSAMPLE) *
				      cinfo.output_width * cinfo.output_components);
    if (!buffer[c]) {
      for (c--; c>=0; c--)
        base_free(buffer[c]);
      base_free(buffer);
      jpeg_destroy_decompress(&cinfo);
      fclose(file);
      return false;
    }
  }

  // Generate a grayscale palette if is necessary.
  if (image->imgtype == IMAGE_GRAYSCALE)
    for (c=0; c<256; c++)
      fop_sequence_set_color(fop, c, c, c, c);

  // Read each scan line.
  while (cinfo.output_scanline < cinfo.output_height) {
    // TODO
/*     if (plugin_want_close())  */
/*       break; */

    num_scanlines = jpeg_read_scanlines(&cinfo, buffer, buffer_height);

    /* RGB */
    if (image->imgtype == IMAGE_RGB) {
      uint8_t* src_address;
      uint32_t* dst_address;
      int x, y, r, g, b;

      for (y=0; y<(int)num_scanlines; y++) {
        src_address = ((uint8_t**)buffer)[y];
        dst_address = ((uint32_t**)image->line)[cinfo.output_scanline-1+y];

        for (x=0; x<image->w; x++) {
          r = *(src_address++);
          g = *(src_address++);
          b = *(src_address++);
          *(dst_address++) = _rgba(r, g, b, 255);
        }
      }
    }
    /* Grayscale */
    else {
      uint8_t* src_address;
      uint16_t* dst_address;
      int x, y;

      for (y=0; y<(int)num_scanlines; y++) {
        src_address = ((uint8_t**)buffer)[y];
        dst_address = ((uint16_t**)image->line)[cinfo.output_scanline-1+y];

        for (x=0; x<image->w; x++)
          *(dst_address++) = _graya(*(src_address++), 255);
      }
    }

    fop_progress(fop, (float)(cinfo.output_scanline+1) / (float)(cinfo.output_height));
    if (fop_is_stop(fop))
      break;
  }

  /* destroy all data */
  for (c=0; c<(int)buffer_height; c++)
    base_free(buffer[c]);
  base_free(buffer);

  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  fclose(file);
  return true;
}
Пример #12
0
static void thumbnail_render(BITMAP* bmp, const Image* image, bool has_alpha, const Palette* palette)
{
  register int c, x, y;
  int w, h, x1, y1;
  double sx, sy, scale;

  ASSERT(image != NULL);

  sx = (double)image->w / (double)bmp->w;
  sy = (double)image->h / (double)bmp->h;
  scale = MAX(sx, sy);

  w = image->w / scale;
  h = image->h / scale;
  w = MIN(bmp->w, w);
  h = MIN(bmp->h, h);

  x1 = bmp->w/2 - w/2;
  y1 = bmp->h/2 - h/2;
  x1 = MAX(0, x1);
  y1 = MAX(0, y1);

  /* with alpha blending */
  if (has_alpha) {
    register int c2;

    rectgrid(bmp, 0, 0, bmp->w-1, bmp->h-1,
             bmp->w/4, bmp->h/4);

    switch (image->getPixelFormat()) {
      case IMAGE_RGB:
        for (y=0; y<h; y++)
          for (x=0; x<w; x++) {
            c = image_getpixel(image, x*scale, y*scale);
            c2 = getpixel(bmp, x1+x, y1+y);
            c = _rgba_blend_normal(_rgba(getr(c2), getg(c2), getb(c2), 255), c, 255);

            putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c),
                                              _rgba_getg(c),
                                              _rgba_getb(c)));
          }
        break;
      case IMAGE_GRAYSCALE:
        for (y=0; y<h; y++)
          for (x=0; x<w; x++) {
            c = image_getpixel(image, x*scale, y*scale);
            c2 = getpixel(bmp, x1+x, y1+y);
            c = _graya_blend_normal(_graya(getr(c2), 255), c, 255);

            putpixel(bmp, x1+x, y1+y, makecol(_graya_getv(c),
                                              _graya_getv(c),
                                              _graya_getv(c)));
          }
        break;
      case IMAGE_INDEXED: {
        for (y=0; y<h; y++)
          for (x=0; x<w; x++) {
            c = image_getpixel(image, x*scale, y*scale);
            if (c != 0) {
              ASSERT(c >= 0 && c < palette->size());

              c = palette->getEntry(MID(0, c, palette->size()-1));
              putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c),
                                                _rgba_getg(c),
                                                _rgba_getb(c)));
            }
          }
        break;
      }
    }
  }
  /* without alpha blending */
  else {
    clear_to_color(bmp, makecol(128, 128, 128));

    switch (image->getPixelFormat()) {
      case IMAGE_RGB:
        for (y=0; y<h; y++)
          for (x=0; x<w; x++) {
            c = image_getpixel(image, x*scale, y*scale);
            putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c),
                                              _rgba_getg(c),
                                              _rgba_getb(c)));
          }
        break;
      case IMAGE_GRAYSCALE:
        for (y=0; y<h; y++)
          for (x=0; x<w; x++) {
            c = image_getpixel(image, x*scale, y*scale);
            putpixel(bmp, x1+x, y1+y, makecol(_graya_getv(c),
                                              _graya_getv(c),
                                              _graya_getv(c)));
          }
        break;
      case IMAGE_INDEXED: {
        for (y=0; y<h; y++)
          for (x=0; x<w; x++) {
            c = image_getpixel(image, x*scale, y*scale);

            ASSERT(c >= 0 && c < palette->size());

            c = palette->getEntry(MID(0, c, palette->size()-1));
            putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c),
                                              _rgba_getg(c),
                                              _rgba_getb(c)));
          }
        break;
      }
    }
  }
}
Пример #13
0
void ConvolutionMatrixFilter::applyToRgba(FilterManager* filterMgr)
{
  if (!m_matrix)
    return;

  const Image* src = filterMgr->getSourceImage();
  uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress();
  Target target = filterMgr->getTarget();
  uint32_t color;
  GetPixelsDelegateRgba delegate;
  int x = filterMgr->getX();
  int x2 = x+filterMgr->getWidth();
  int y = filterMgr->getY();

  for (; x<x2; ++x) {
    // Avoid the non-selected region
    if (filterMgr->skipPixel()) {
      ++dst_address;
      continue;
    }

    delegate.reset(m_matrix);
    get_neighboring_pixels<RgbTraits>(src, x, y,
                                      m_matrix->getWidth(),
                                      m_matrix->getHeight(),
                                      m_matrix->getCenterX(),
                                      m_matrix->getCenterY(),
                                      m_tiledMode, delegate);

    color = image_getpixel_fast<RgbTraits>(src, x, y);
    if (delegate.div == 0) {
      *(dst_address++) = color;
      continue;
    }

    if (target & TARGET_RED_CHANNEL) {
      delegate.r = delegate.r / delegate.div + m_matrix->getBias();
      delegate.r = MID(0, delegate.r, 255);
    }
    else
      delegate.r = _rgba_getr(color);

    if (target & TARGET_GREEN_CHANNEL) {
      delegate.g = delegate.g / delegate.div + m_matrix->getBias();
      delegate.g = MID(0, delegate.g, 255);
    }
    else
      delegate.g = _rgba_getg(color);

    if (target & TARGET_BLUE_CHANNEL) {
      delegate.b = delegate.b / delegate.div + m_matrix->getBias();
      delegate.b = MID(0, delegate.b, 255);
    }
    else
      delegate.b = _rgba_getb(color);

    if (target & TARGET_ALPHA_CHANNEL) {
      delegate.a = delegate.a / m_matrix->getDiv() + m_matrix->getBias();
      delegate.a = MID(0, delegate.a, 255);
    }
    else
      delegate.a = _rgba_geta(color);

    *(dst_address++) = _rgba(delegate.r, delegate.g, delegate.b, delegate.a);
  }
}
Пример #14
0
/* loads a COL file (Animator and Animator Pro format) */
Palette *load_col_file(const char *filename)
{
#if (MAKE_VERSION(4, 2, 1) >= MAKE_VERSION(ALLEGRO_VERSION,             \
                                           ALLEGRO_SUB_VERSION,         \
                                           ALLEGRO_WIP_VERSION))
  int size = file_size(filename);
#else
  int size = file_size_ex(filename);
#endif
  int pro = (size == 768)? false: true; /* is Animator Pro format? */
  div_t d = div(size-8, 3);
  Palette *pal = NULL;
  int c, r, g, b;
  FILE *f;

  if (!(size) || (pro && d.rem)) /* invalid format */
    return NULL;

  f = fopen(filename, "rb");
  if (!f)
    return NULL;

  /* Animator format */
  if (!pro) {
    pal = new Palette(FrameNumber(0), 256);

    for (c=0; c<256; c++) {
      r = fgetc(f);
      g = fgetc(f);
      b = fgetc(f);
      if (ferror(f))
        break;

      pal->setEntry(c, _rgba(_rgb_scale_6[MID(0, r, 63)],
                             _rgb_scale_6[MID(0, g, 63)],
                             _rgb_scale_6[MID(0, b, 63)], 255));
    }
  }
  /* Animator Pro format */
  else {
    int magic, version;

    fgetl(f);                   /* skip file size */
    magic = fgetw(f);           /* file format identifier */
    version = fgetw(f);         /* version file */

    /* unknown format */
    if (magic != PROCOL_MAGIC_NUMBER || version != 0) {
      fclose(f);
      return NULL;
    }

    pal = new Palette(FrameNumber(0), MIN(d.quot, 256));

    for (c=0; c<pal->size(); c++) {
      r = fgetc(f);
      g = fgetc(f);
      b = fgetc(f);
      if (ferror(f))
        break;

      pal->setEntry(c, _rgba(MID(0, r, 255),
                             MID(0, g, 255),
                             MID(0, b, 255), 255));
    }
  }

  fclose(f);
  return pal;
}