コード例 #1
0
ファイル: sdl.c プロジェクト: clones/kaa
PyObject *image_to_surface(PyObject *self, PyObject *args)
{
    PyObject *pyimg;
    Imlib_Image *img;
    PySurfaceObject *pysurf;
    unsigned char *pixels;

    static int init = 0;

    CHECK_IMAGE_PYOBJECT

    if (init == 0) {
        import_pygame_surface();
        init = 1;
    }

    if (!PyArg_ParseTuple(args, "O!O!", Image_PyObject_Type, &pyimg,
                          &PySurface_Type, &pysurf))
        return NULL;

    img  = imlib_image_from_pyobject(pyimg);
    imlib_context_set_image(img);
    pixels = (unsigned char *)imlib_image_get_data_for_reading_only();
    memcpy(pysurf->surf->pixels, pixels, imlib_image_get_width() *
           imlib_image_get_height() * 4);

    Py_INCREF(Py_None);
    return Py_None;
}
コード例 #2
0
Image<uint32_t> load_image(const char* filename)
{
  Image<uint32_t> res;
  Imlib_Image image_handle = NULL;
  image_handle = imlib_load_image_immediately_without_cache(filename);
  if(image_handle) { 
    res.width = imlib_image_get_width();
    res.height = imlib_image_get_height();
    res.channels = 4; // ARGB
    res.data.set_size(res.width * res.height * res.channels);
    res.format = Image<uint32_t>::ARGB;

    DATA32* raw = imlib_image_get_data_for_reading_only(); // ARGB handle
    memcpy(res.data.ptr(), raw, res.width * res.height * sizeof(DATA32));
    
    imlib_free_image();
  }
  return res;
}
コード例 #3
0
static int img_load( img_t *img, const char *path )
{
    ImlibLoadError err = IMLIB_LOAD_ERROR_NONE;
    Imlib_Image imimg = imlib_load_image_with_error_return( path, &err );
    
    if( img )
    {
        imlib_context_set_image( imimg );
        img->size.w =  imlib_image_get_width();
        img->size.h = imlib_image_get_height();
        // allocate buffer
        img->bytes = sizeof( DATA32 ) * (size_t)img->size.w * (size_t)img->size.h;
        img->blob = malloc( img->bytes );
        if( img->blob )
        {
            char *format = imlib_image_format();
            
            if( img_format_copy( img, format, strlen( format ) ) == 0 ){
                memcpy( img->blob, imlib_image_get_data_for_reading_only(), 
                        img->bytes );
                imlib_free_image_and_decache();
                
                img->quality = 100;
                img->resize = (img_size_t){ 0, 0 };
                return 0;
            }
            // failed to copy
            free( img->blob );
        }
        
        imlib_free_image_and_decache();
    }
    else {
        liberr2errno( err );
    }
    
    return -1;
}
コード例 #4
0
ファイル: fuzzy-clock.c プロジェクト: gmelchett/sal
void fuzzy_clock_update(struct aquarium *aquarium)
{
        time_t now;
        struct tm *mt;
        int th = 0;
        int i;
        int mi;
        int x, y, cy = 0;
        int img[5] = {-1, -1, -1, -1, -1};


        if(aquarium->fuzzy_clock == AL_NO)
                return;

	now = time(NULL);
	mt = localtime(&now);

        if (mt->tm_hour == 0 || mt->tm_hour == 12)
                img[2] = 12 - 1;
        else
                img[2] = (mt->tm_hour % 12) - 1;

        mi = mt->tm_min;

        if (mi >= 30) {
                img[1] = TO;
                img[2]++;
                img[2] = img[2] % 12;
        } else
                img[1] = PAST;

        mi = mi / 5;

        switch(mi) {
        case 0: /* H o'clock*/
                img[0] = img[2];
                img[1] = OCLOCK;
                img[2] = -1;
                break;
        case 6:
                img[0] = HALF;
                img[1] = PAST;
                img[2]--;
                if (img[2] < 0)
                        img[2] = 11;
                break;
        case 1: /* Five to/past H */
        case 11:
                img[0] = 5 - 1;
                break;
        case 2: /* Ten to/past H */
        case 10:
                img[0] = 10 - 1;
                break;
        case 3:/* Quarter to/past H */
        case 9:
                img[0] = QUARTER;
                break;
        case 4: /* Twenty to/past H */
        case 8:
                img[0] = TWENTY;
                break;
        case 5: /* Twenty five to/past H */
        case 7:
                img[0] = TWENTY;
                img[3] = img[2];
                img[2] = img[1];
                img[1] = 5 - 1;
                break;
        default:
                break;
        }

        for (i = 0 ; img[i] != -1; i++) {
                imlib_context_set_image(fuzzy_images[img[i]]);
                th += imlib_image_get_height();
        }

        for (i = 0 ; img[i] != -1; i++) {
                imlib_context_set_image(fuzzy_images[img[i]]);
                aquarium_transform(aquarium->fuzzy_clock,
                                   imlib_image_get_width(), th,
                                   &x, &y);
                window_draw_blend((unsigned char *)imlib_image_get_data_for_reading_only(),
                                  0, 0,
                                  imlib_image_get_width(),
                                  imlib_image_get_height(),
                                  x, y + cy,
                                  128);
                cy += imlib_image_get_height();
        }
}
コード例 #5
0
ファイル: rpng_test.c プロジェクト: AirBrowse/RetroArch
static int test_blocking_rpng(const char *in_path)
{
#ifdef HAVE_IMLIB2
   Imlib_Image img;
   const uint32_t *imlib_data = NULL;
#endif
   const uint32_t test_data[] = {
      0xff000000 | 0x50, 0xff000000 | 0x80,
      0xff000000 | 0x40, 0xff000000 | 0x88,
      0xff000000 | 0x50, 0xff000000 | 0x80,
      0xff000000 | 0x40, 0xff000000 | 0x88,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3,
   };
   uint32_t *data = NULL;
   unsigned width = 0;
   unsigned height = 0;

   if (!rpng_save_image_argb("/tmp/test.png", test_data, 4, 4, 16))
      return 1;


   if (!rpng_load_image_argb(in_path, &data, &width, &height))
      return 2;

   fprintf(stderr, "Path: %s.\n", in_path);
   fprintf(stderr, "Got image: %u x %u.\n", width, height);

#if 0
   fprintf(stderr, "\nRPNG:\n");
   for (unsigned h = 0; h < height; h++)
   {
      unsigned w;
      for (w = 0; w < width; w++)
         fprintf(stderr, "[%08x] ", data[h * width + w]);
      fprintf(stderr, "\n");
   }
#endif

#ifdef HAVE_IMLIB2
   /* Validate with imlib2 as well. */
   img = imlib_load_image(in_path);
   if (!img)
      return 4;

   imlib_context_set_image(img);

   width      = imlib_image_get_width();
   height     = imlib_image_get_width();
   imlib_data = imlib_image_get_data_for_reading_only();

#if 0
   fprintf(stderr, "\nImlib:\n");
   for (unsigned h = 0; h < height; h++)
   {
      for (unsigned w = 0; w < width; w++)
         fprintf(stderr, "[%08x] ", imlib_data[h * width + w]);
      fprintf(stderr, "\n");
   }
#endif

   if (memcmp(imlib_data, data, width * height * sizeof(uint32_t)) != 0)
   {
      fprintf(stderr, "Imlib and RPNG differs!\n");
      return 5;
   }
   else
      fprintf(stderr, "Imlib and RPNG are equivalent!\n");

   imlib_free_image();
#endif
   free(data);

   return 0;
}
コード例 #6
0
ファイル: glselectrectangle.cpp プロジェクト: Jasonic/slop
unsigned int slop::GLSelectRectangle::loadImage( unsigned int* texture, std::string path ) {
    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);
    glGenTextures( 1, texture );
    glBindTexture( GL_TEXTURE_2D, *texture );
    Imlib_Load_Error err;
    Imlib_Image image = imlib_load_image_with_error_return( path.c_str(), &err );
    if ( err != IMLIB_LOAD_ERROR_NONE ) {
        std::string message = "Failed to load image: ";
        message += path;
        message += "\n\t";
        switch( err ) {
            default: {
                message += "unknown error ";
                message += (int)err;
                message += "\n";
                break;
            }
            case IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS:
                message += "out of file descriptors\n";
                break;
            case IMLIB_LOAD_ERROR_OUT_OF_MEMORY:
                message += "out of memory\n";
                break;
            case IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS:
                message += "path contains too many symbolic links\n";
                break;
            case IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE:
                message += "path points outside address space\n";
                break;
            case IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY:
                message += "path component is not a directory\n";
                break;
            case IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT:
                message += "path component is non-existant (~ isn't expanded inside quotes!)\n";
                break;
            case IMLIB_LOAD_ERROR_PATH_TOO_LONG:
                message += "path is too long\n";
                break;
            case IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT:
                message += "no loader for file format (unsupported format)\n";
                break;
            case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE: {
                message += "not enough disk space\n";
                break;
            }
            case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST: {
                message += "file does not exist\n";
                break;
            }
            case IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY: {
                message += "file is a directory\n";
                break;
            }
            case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE:
            case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ: {
                message += "permission denied\n";
                break;
            }
        }
        throw std::runtime_error( message.c_str() );
        return *texture;
    }
    imlib_context_set_image( image );
    DATA32* data = imlib_image_get_data_for_reading_only();
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, imlib_image_get_width(), imlib_image_get_height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)data );
    if ( GLEW_VERSION_3_0 ) {
        glHint( GL_GENERATE_MIPMAP_HINT, GL_NICEST );
        glGenerateMipmap( GL_TEXTURE_2D );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    } else {
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    }
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    imlib_free_image();
    glDisable(GL_TEXTURE_2D);
    return *texture;
}
コード例 #7
0
ファイル: image.c プロジェクト: JulioJu/sxiv
bool img_load_gif(img_t *img, const fileinfo_t *file)
{
	GifFileType *gif;
	GifRowType *rows = NULL;
	GifRecordType rec;
	ColorMapObject *cmap;
	DATA32 bgpixel, *data, *ptr;
	DATA32 *prev_frame = NULL;
	Imlib_Image im;
	int i, j, bg, r, g, b;
	int x, y, w, h, sw, sh;
	int px, py, pw, ph;
	int intoffset[] = { 0, 4, 2, 1 };
	int intjump[] = { 8, 8, 4, 2 };
	int transp = -1;
	unsigned int disposal = 0, prev_disposal = 0;
	unsigned int delay = 0;
	bool err = false;

	if (img->multi.cap == 0) {
		img->multi.cap = 8;
		img->multi.frames = (img_frame_t*)
		                    s_malloc(sizeof(img_frame_t) * img->multi.cap);
	}
	img->multi.cnt = img->multi.sel = 0;
	img->multi.length = 0;

#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
	gif = DGifOpenFileName(file->path, NULL);
#else
	gif = DGifOpenFileName(file->path);
#endif
	if (gif == NULL) {
		warn("could not open gif file: %s", file->name);
		return false;
	}
	bg = gif->SBackGroundColor;
	sw = gif->SWidth;
	sh = gif->SHeight;
	px = py = pw = ph = 0;

	do {
		if (DGifGetRecordType(gif, &rec) == GIF_ERROR) {
			err = true;
			break;
		}
		if (rec == EXTENSION_RECORD_TYPE) {
			int ext_code;
			GifByteType *ext = NULL;

			DGifGetExtension(gif, &ext_code, &ext);
			while (ext) {
				if (ext_code == GRAPHICS_EXT_FUNC_CODE) {
					if (ext[1] & 1)
						transp = (int) ext[4];
					else
						transp = -1;

					delay = 10 * ((unsigned int) ext[3] << 8 | (unsigned int) ext[2]);
					disposal = (unsigned int) ext[1] >> 2 & 0x7;
				}
				ext = NULL;
				DGifGetExtensionNext(gif, &ext);
			}
		} else if (rec == IMAGE_DESC_RECORD_TYPE) {
			if (DGifGetImageDesc(gif) == GIF_ERROR) {
				err = true;
				break;
			}
			x = gif->Image.Left;
			y = gif->Image.Top;
			w = gif->Image.Width;
			h = gif->Image.Height;

			rows = (GifRowType*) s_malloc(h * sizeof(GifRowType));
			for (i = 0; i < h; i++)
				rows[i] = (GifRowType) s_malloc(w * sizeof(GifPixelType));
			if (gif->Image.Interlace) {
				for (i = 0; i < 4; i++) {
					for (j = intoffset[i]; j < h; j += intjump[i])
						DGifGetLine(gif, rows[j], w);
				}
			} else {
				for (i = 0; i < h; i++)
					DGifGetLine(gif, rows[i], w);
			}

			ptr = data = (DATA32*) s_malloc(sizeof(DATA32) * sw * sh);
			cmap = gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap;
			r = cmap->Colors[bg].Red;
			g = cmap->Colors[bg].Green;
			b = cmap->Colors[bg].Blue;
			bgpixel = 0x00ffffff & (r << 16 | g << 8 | b);

			for (i = 0; i < sh; i++) {
				for (j = 0; j < sw; j++) {
					if (i < y || i >= y + h || j < x || j >= x + w ||
					    rows[i-y][j-x] == transp)
					{
						if (prev_frame != NULL && (prev_disposal != 2 ||
						    i < py || i >= py + ph || j < px || j >= px + pw))
						{
							*ptr = prev_frame[i * sw + j];
						} else {
							*ptr = bgpixel;
						}
					} else {
						r = cmap->Colors[rows[i-y][j-x]].Red;
						g = cmap->Colors[rows[i-y][j-x]].Green;
						b = cmap->Colors[rows[i-y][j-x]].Blue;
						*ptr = 0xff << 24 | r << 16 | g << 8 | b;
					}
					ptr++;
				}
			}

			im = imlib_create_image_using_copied_data(sw, sh, data);

			for (i = 0; i < h; i++)
				free(rows[i]);
			free(rows);
			free(data);

			if (im == NULL) {
				err = true;
				break;
			}

			imlib_context_set_image(im);
			imlib_image_set_format("gif");
			if (transp >= 0)
				imlib_image_set_has_alpha(1);

			if (disposal != 3)
				prev_frame = imlib_image_get_data_for_reading_only();
			prev_disposal = disposal;
			px = x, py = y, pw = w, ph = h;

			if (img->multi.cnt == img->multi.cap) {
				img->multi.cap *= 2;
				img->multi.frames = (img_frame_t*)
				                    s_realloc(img->multi.frames,
				                              img->multi.cap * sizeof(img_frame_t));
			}
			img->multi.frames[img->multi.cnt].im = im;
			img->multi.frames[img->multi.cnt].delay = delay > 0 ? delay : DEF_GIF_DELAY;
			img->multi.length += img->multi.frames[img->multi.cnt].delay;
			img->multi.cnt++;
		}
	} while (rec != TERMINATE_RECORD_TYPE);
コード例 #8
0
ファイル: image.c プロジェクト: paradigm/sxiv
/* Originally based on, but in its current form merely inspired by Imlib2's
 * src/modules/loaders/loader_gif.c:load(), written by Carsten Haitzler.
 */
bool img_load_gif(img_t *img, const fileinfo_t *file) {
	GifFileType *gif;
	GifRowType *rows = NULL;
	GifRecordType rec;
	ColorMapObject *cmap;
	DATA32 bgpixel, *data, *ptr;
	DATA32 *prev_frame = NULL;
	Imlib_Image *im;
	int i, j, bg, r, g, b;
	int x, y, w, h, sw, sh;
	int intoffset[] = { 0, 4, 2, 1 };
	int intjump[] = { 8, 8, 4, 2 };
	int transp = -1;
	unsigned int delay = 0;
	bool err = false;

	if (img->multi.cap == 0) {
		img->multi.cap = 8;
		img->multi.frames = (img_frame_t*)
		                    s_malloc(sizeof(img_frame_t) * img->multi.cap);
	}
	img->multi.cnt = 0;
	img->multi.sel = 0;

	gif = DGifOpenFileName(file->path);
	if (gif == NULL) {
		warn("could not open gif file: %s", file->name);
		return false;
	}
	bg = gif->SBackGroundColor;
	sw = gif->SWidth;
	sh = gif->SHeight;

	do {
		if (DGifGetRecordType(gif, &rec) == GIF_ERROR) {
			err = true;
			break;
		}
		if (rec == EXTENSION_RECORD_TYPE) {
			int ext_code;
			GifByteType *ext = NULL;

			DGifGetExtension(gif, &ext_code, &ext);
			while (ext) {
				if (ext_code == 0xf9) {
					if (ext[1] & 1)
						transp = (int) ext[4];
					else
						transp = -1;

					delay = 10 * ((unsigned int) ext[3] << 8 | (unsigned int) ext[2]);
					if (delay)
						delay = MAX(delay, MIN_GIF_DELAY);

					/* TODO: handle disposal method, section 23.c.iv of
					         http://www.w3.org/Graphics/GIF/spec-gif89a.txt */
				}
				ext = NULL;
				DGifGetExtensionNext(gif, &ext);
			}
		} else if (rec == IMAGE_DESC_RECORD_TYPE) {
			if (DGifGetImageDesc(gif) == GIF_ERROR) {
				err = true;
				break;
			}
			x = gif->Image.Left;
			y = gif->Image.Top;
			w = gif->Image.Width;
			h = gif->Image.Height;

			rows = (GifRowType*) s_malloc(h * sizeof(GifRowType));
			for (i = 0; i < h; i++)
				rows[i] = (GifRowType) s_malloc(w * sizeof(GifPixelType));
			if (gif->Image.Interlace) {
				for (i = 0; i < 4; i++) {
					for (j = intoffset[i]; j < h; j += intjump[i])
						DGifGetLine(gif, rows[j], w);
				}
			} else {
				for (i = 0; i < h; i++)
					DGifGetLine(gif, rows[i], w);
			}

			ptr = data = (DATA32*) s_malloc(sizeof(DATA32) * sw * sh);
			cmap = gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap;
			r = cmap->Colors[bg].Red;
			g = cmap->Colors[bg].Green;
			b = cmap->Colors[bg].Blue;
			bgpixel = 0x00ffffff & (r << 16 | g << 8 | b);

			for (i = 0; i < sh; i++) {
				for (j = 0; j < sw; j++) {
					if (i < y || i >= y + h || j < x || j >= x + w ||
					    rows[i-y][j-x] == transp)
					{
						if (prev_frame != NULL)
							*ptr = prev_frame[i * sw + j];
						else
							*ptr = bgpixel;
					} else {
						r = cmap->Colors[rows[i-y][j-x]].Red;
						g = cmap->Colors[rows[i-y][j-x]].Green;
						b = cmap->Colors[rows[i-y][j-x]].Blue;
						*ptr = 0xff << 24 | r << 16 | g << 8 | b;
					}
					ptr++;
				}
			}

			im = imlib_create_image_using_copied_data(sw, sh, data);

			for (i = 0; i < h; i++)
				free(rows[i]);
			free(rows);
			free(data);

			if (im == NULL) {
				err = true;
				break;
			}

			imlib_context_set_image(im);
			prev_frame = imlib_image_get_data_for_reading_only();

			imlib_image_set_format("gif");
			if (transp >= 0)
				imlib_image_set_has_alpha(1);

			if (img->multi.cnt == img->multi.cap) {
				img->multi.cap *= 2;
				img->multi.frames = (img_frame_t*)
				                    s_realloc(img->multi.frames,
				                              img->multi.cap * sizeof(img_frame_t));
			}
			img->multi.frames[img->multi.cnt].im = im;
			img->multi.frames[img->multi.cnt].delay = delay ? delay : GIF_DELAY;
			img->multi.cnt++;
		}
	} while (rec != TERMINATE_RECORD_TYPE);

	DGifCloseFile(gif);

	if (err && !file->loaded)
		warn("corrupted gif file: %s", file->name);

	if (img->multi.cnt > 1) {
		imlib_context_set_image(img->im);
		imlib_free_image();
		img->im = img->multi.frames[0].im;
		img->multi.animate = GIF_AUTOPLAY;
	} else if (img->multi.cnt == 1) {
		imlib_context_set_image(img->multi.frames[0].im);
		imlib_free_image();
		img->multi.cnt = 0;
		img->multi.animate = false;
	}

	imlib_context_set_image(img->im);

	return !err;
}
コード例 #9
0
ファイル: rpng_test.c プロジェクト: Jalle19/RetroArch
int main(int argc, char *argv[])
{
   if (argc > 2)
   {
      fprintf(stderr, "Usage: %s <png file>\n", argv[0]);
      return 1;
   }

   const char *in_path = argc == 2 ? argv[1] : "/tmp/test.png";

   const uint32_t test_data[] = {
      0xff000000 | 0x50, 0xff000000 | 0x80, 0xff000000 | 0x40, 0xff000000 | 0x88,
      0xff000000 | 0x50, 0xff000000 | 0x80, 0xff000000 | 0x40, 0xff000000 | 0x88,
      0xff000000 | 0xc3, 0xff000000 | 0xd3, 0xff000000 | 0xc3, 0xff000000 | 0xd3,
      0xff000000 | 0xc3, 0xff000000 | 0xd3, 0xff000000 | 0xc3, 0xff000000 | 0xd3,
   };

   if (!rpng_save_image_argb("/tmp/test.png", test_data, 4, 4, 16))
      return 1;

   uint32_t *data = NULL;
   unsigned width = 0;
   unsigned height = 0;

   if (!rpng_load_image_argb(in_path, &data, &width, &height))
      return 2;

   fprintf(stderr, "Got image: %u x %u.\n", width, height);

   fprintf(stderr, "\nRPNG:\n");
   for (unsigned h = 0; h < height; h++)
   {
      for (unsigned w = 0; w < width; w++)
         fprintf(stderr, "[%08x] ", data[h * width + w]);
      fprintf(stderr, "\n");
   }

   if (width != 4 || height != 4)
      return 3;

   // Validate with imlib2 as well.
   Imlib_Image img = imlib_load_image(in_path);
   if (!img)
      return 4;

   imlib_context_set_image(img);
   width  = imlib_image_get_width();
   height = imlib_image_get_width();
   const uint32_t *imlib_data = imlib_image_get_data_for_reading_only();

   fprintf(stderr, "\nImlib:\n");
   for (unsigned h = 0; h < height; h++)
   {
      for (unsigned w = 0; w < width; w++)
         fprintf(stderr, "[%08x] ", imlib_data[h * width + w]);
      fprintf(stderr, "\n");
   }
   imlib_free_image();

   if (memcmp(test_data, data, sizeof(test_data)) != 0)
      return 5;

   free(data);
}
コード例 #10
0
ファイル: filter_bumpmap.c プロジェクト: fatman2021/libim2
static              Imlib_Image
bump_map(Imlib_Image im, pIFunctionParam par)
{
   Imlib_Image         map = im;
   pIFunctionParam     ptr;
   double              an = 0, el = 30, d = 0x200;
   double              red = 0x200, green = 0x200, blue = 0x200;
   double              ambient = 0;

   int                 free_map = 0;
   DATA32             *src;
   DATA32             *mp, *mpy, *mpp;
   double              z, x2, y2;
   int                 w, h, i, j, w2, h2, wh2, mx, my;

   for (ptr = par; ptr; ptr = ptr->next)
     {
        ASSIGN_IMAGE("map", map);
        ASSIGN_INT("angle", an);
        ASSIGN_INT("elevation", el);
        ASSIGN_INT("depth", d);
        ASSIGN_INT("red", red);
        ASSIGN_INT("green", green);
        ASSIGN_INT("blue", blue);
        ASSIGN_INT("ambient", ambient);
     }
   if (!map)
      return im;

   red /= 0x100;
   green /= 0x100;
   blue /= 0x100;
   ambient /= 0x100;
   d /= 0x100;

   imlib_context_set_image(im);
   src = imlib_image_get_data();
   w = imlib_image_get_width();
   h = imlib_image_get_height();

   imlib_context_set_image(map);
   mpp = imlib_image_get_data_for_reading_only();
   w2 = imlib_image_get_width();
   h2 = imlib_image_get_height();
   wh2 = w2 * h2;

   an *= (PI / 180);
   el *= (PI / 180);

   x2 = sin(an) * cos(el);
   y2 = cos(an) * cos(el);
   z = sin(el);

   d /= (255 * (255 + 255 + 255));

   my = h2;
   for (j = h; --j >= 0;)
     {
        mp = mpp;
        mpp += w2;
        if (--my <= 0)
          {
             mpp -= wh2;
             my = h2;
          }
        mpy = mpp;
        mx = w2;
        for (i = w; --i >= 0;)
          {
             double              x1, y1, v;
             int                 r, g, b, gr;

             gr = A_VAL(mp) * (R_VAL(mp) + G_VAL(mp) + B_VAL(mp));
             y1 = d * (double)(A_VAL(mpy) * (R_VAL(mpy) +
                                             G_VAL(mpy) + B_VAL(mpy)) - gr);
             mp++;
             mpy++;
             if (--mx <= 0)
               {
                  mp -= w2;
                  mpy -= w2;
                  mx = w2;
               }
             x1 = d * (double)(A_VAL(mp) * (R_VAL(mp) +
                                            G_VAL(mp) + B_VAL(mp)) - gr);
             v = x1 * x2 + y1 * y2 + z;
             v /= sqrt((x1 * x1) + (y1 * y1) + 1.0);
             v += ambient;
             r = v * R_VAL(src) * red;
             g = v * G_VAL(src) * green;
             b = v * B_VAL(src) * blue;
             if (r < 0)
                r = 0;
             if (r > 255)
                r = 255;
             if (g < 0)
                g = 0;
             if (g > 255)
                g = 255;
             if (b < 0)
                b = 0;
             if (b > 255)
                b = 255;
             R_VAL(src) = r;
             G_VAL(src) = g;
             B_VAL(src) = b;

             src++;
          }
     }
   if (free_map)
     {
        imlib_context_set_image(map);
        imlib_free_image();
     }
   return im;
}