Mercurial > pygame
view src/image.c @ 3194:9fcb7abf3185 default tip
Remove some gcc 4.7.2 compiler warnings
| author | Lenard Lindstrom <len-l@telus.net> |
|---|---|
| date | Tue, 23 Apr 2013 19:53:36 -0700 |
| parents | 5c3f0f965568 |
| children |
line wrap: on
line source
/* pygame - Python Game Library Copyright (C) 2000-2001 Pete Shinners Copyright (C) 2006 Rene Dudfield This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Pete Shinners pete@shinners.org */ /* * image module for pygame */ #include "pygame.h" #include "pgcompat.h" #include "doc/image_doc.h" #include "pgopengl.h" struct _module_state { int is_extended; }; #if PY3 #define GETSTATE(m) PY3_GETSTATE (_module_state, m) #else static struct _module_state _state = { 0 }; #define GETSTATE(m) PY2_GETSTATE (_state) #endif static int SaveTGA (SDL_Surface *surface, const char *file, int rle); static int SaveTGA_RW (SDL_Surface *surface, SDL_RWops *out, int rle); static SDL_Surface* opengltosdl (void); #define DATAROW(data, row, width, height, flipped) \ ((flipped) ? (((char*) data) + (height - row - 1) * width) : \ (((char*) data) + row * width)) static PyObject* image_load_basic(PyObject *self, PyObject *arg) { PyObject *obj; PyObject *final; PyObject *oencoded; const char *name = NULL; SDL_Surface* surf; SDL_RWops *rw; if (!PyArg_ParseTuple(arg, "O|s", &obj, &name)) { return NULL; } oencoded = RWopsEncodeFilePath(obj, PyExc_SDLError); if (oencoded == NULL) { return NULL; } if (oencoded != Py_None) { Py_BEGIN_ALLOW_THREADS; surf = SDL_LoadBMP(Bytes_AS_STRING(oencoded)); Py_END_ALLOW_THREADS; Py_DECREF(oencoded); } else { Py_DECREF(oencoded); rw = RWopsFromFileObject(obj); if (rw == NULL) { return NULL; } if (RWopsCheckObject(rw)) { surf = SDL_LoadBMP_RW (rw, 1); } else { Py_BEGIN_ALLOW_THREADS; surf = SDL_LoadBMP_RW(rw, 1); Py_END_ALLOW_THREADS; } } if (surf == NULL) { return RAISE(PyExc_SDLError, SDL_GetError()); } final = PySurface_New(surf); if (final == NULL) { SDL_FreeSurface(surf); } return final; } static SDL_Surface* opengltosdl () { /*we need to get ahold of the pyopengl glReadPixels function*/ /*we use pyopengl's so we don't need to link with opengl at compiletime*/ SDL_Surface *surf = NULL; Uint32 rmask, gmask, bmask; int i; unsigned char *pixels = NULL; GL_glReadPixels_Func p_glReadPixels = NULL; p_glReadPixels = (GL_glReadPixels_Func) SDL_GL_GetProcAddress("glReadPixels"); surf = SDL_GetVideoSurface (); if(!surf) { RAISE (PyExc_RuntimeError, "Cannot get video surface."); return NULL; } if(!p_glReadPixels) { RAISE (PyExc_RuntimeError, "Cannot find glReadPixels function."); return NULL; } /* GL_UNSIGNED_BYTE = 5121 GL_RGB = 6407 */ pixels = (unsigned char*) malloc(surf->w * surf->h * 3); if(!pixels) { RAISE (PyExc_MemoryError, "Cannot allocate enough memory for pixels."); return NULL; } //p_glReadPixels(0, 0, surf->w, surf->h, 6407, 5121, pixels); //glReadPixels(0, 0, surf->w, surf->h, 0x1907, 0x1401, pixels); p_glReadPixels(0, 0, surf->w, surf->h, 0x1907, 0x1401, pixels); if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { rmask=0x000000FF; gmask=0x0000FF00; bmask=0x00FF0000; } else { rmask=0x00FF0000; gmask=0x0000FF00; bmask=0x000000FF; } surf = SDL_CreateRGBSurface (SDL_SWSURFACE, surf->w, surf->h, 24, rmask, gmask, bmask, 0); if (!surf) { free(pixels); RAISE (PyExc_SDLError, SDL_GetError ()); return NULL; } for (i = 0; i < surf->h; ++i) { memcpy (((char *) surf->pixels) + surf->pitch * i, pixels + 3 * surf->w * (surf->h - i - 1), surf->w * 3); } free(pixels); return surf; } PyObject* image_save(PyObject *self, PyObject *arg) { PyObject *surfobj; PyObject *obj; PyObject *oencoded; PyObject *imgext = NULL; SDL_Surface *surf; SDL_Surface *temp = NULL; int result = 1; if (!PyArg_ParseTuple(arg, "O!O", &PySurface_Type, &surfobj, &obj)) { return NULL; } surf = PySurface_AsSurface(surfobj); if (surf->flags & SDL_OPENGL) { temp = surf = opengltosdl(); if (surf == NULL) { return NULL; } } else { PySurface_Prep(surfobj); } oencoded = RWopsEncodeFilePath(obj, PyExc_SDLError); if (oencoded == Py_None) { SDL_RWops *rw = RWopsFromFileObject(obj); if (rw != NULL) { result = SaveTGA_RW(surf, rw, 1); } else { result = -2; } } else if (oencoded != NULL) { const char *name = Bytes_AS_STRING(oencoded); Py_ssize_t namelen = Bytes_GET_SIZE(oencoded); int written = 0; if (namelen > 3) { if ((name[namelen - 1]=='p' || name[namelen - 1]=='P') && (name[namelen - 2]=='m' || name[namelen - 2]=='M') && (name[namelen - 3]=='b' || name[namelen - 3]=='B')) { Py_BEGIN_ALLOW_THREADS; result = SDL_SaveBMP(surf, name); Py_END_ALLOW_THREADS; written = 1; } else if (((name[namelen - 1]=='g' || name[namelen - 1]=='G') && (name[namelen - 2]=='n' || name[namelen - 2]=='N') && (name[namelen - 3]=='p' || name[namelen - 3]=='P')) || ((name[namelen - 1]=='g' || name[namelen - 1]=='G') && (name[namelen - 2]=='e' || name[namelen - 2]=='E') && (name[namelen - 3]=='p' || name[namelen - 3]=='P') && (name[namelen - 4]=='j' || name[namelen - 4]=='J')) || ((name[namelen - 1]=='g' || name[namelen - 1]=='G') && (name[namelen - 2]=='p' || name[namelen - 2]=='P') && (name[namelen - 3]=='j' || name[namelen - 3]=='J'))) { /* If it is .png .jpg .jpeg use the extended module. */ /* try to get extended formats */ imgext = PyImport_ImportModule(IMPPREFIX "imageext"); if (imgext != NULL) { PyObject *extsave = PyObject_GetAttrString(imgext, "save_extended"); PyObject *data; Py_DECREF(imgext); if (extsave != NULL) { data = PyObject_CallObject(extsave, arg); Py_DECREF(extsave); if (data == NULL) { result = -2; } else { Py_DECREF(data); result = 0; } } else { result = -2; } } else { result = -2; } written = 1; } } if (!written) { Py_BEGIN_ALLOW_THREADS; result = SaveTGA(surf, name, 1); Py_END_ALLOW_THREADS; } } else { result = -2; } Py_XDECREF(oencoded); if (temp) { SDL_FreeSurface (temp); } else { PySurface_Unprep (surfobj); } if (result == -2) { /* Python error raised elsewhere */ return NULL; } if (result == -1) { /* SDL error: translate to Python error */ return RAISE(PyExc_SDLError, SDL_GetError()); } if (result == 1) { /* Should never get here */ return RAISE(PyExc_SDLError, "Unrecognized image type"); } Py_RETURN_NONE; } PyObject* image_get_extended (PyObject* self, PyObject* arg) { return PyInt_FromLong (GETSTATE (self)->is_extended); } PyObject* image_tostring (PyObject* self, PyObject* arg) { PyObject *surfobj, *string = NULL; char *format, *data, *pixels; SDL_Surface *surf, *temp = NULL; int w, h, color, flipped = 0; Py_ssize_t len; Uint32 Rmask, Gmask, Bmask, Amask, Rshift, Gshift, Bshift, Ashift, Rloss, Gloss, Bloss, Aloss; int hascolorkey, colorkey; Uint32 alpha; if (!PyArg_ParseTuple (arg, "O!s|i", &PySurface_Type, &surfobj, &format, &flipped)) return NULL; surf = PySurface_AsSurface (surfobj); if (surf->flags & SDL_OPENGL) { temp = surf = opengltosdl (); if (!surf) return NULL; } Rmask = surf->format->Rmask; Gmask = surf->format->Gmask; Bmask = surf->format->Bmask; Amask = surf->format->Amask; Rshift = surf->format->Rshift; Gshift = surf->format->Gshift; Bshift = surf->format->Bshift; Ashift = surf->format->Ashift; Rloss = surf->format->Rloss; Gloss = surf->format->Gloss; Bloss = surf->format->Bloss; Aloss = surf->format->Aloss; hascolorkey = (surf->flags & SDL_SRCCOLORKEY) && !Amask; colorkey = surf->format->colorkey; if (!strcmp (format, "P")) { if (surf->format->BytesPerPixel != 1) return RAISE (PyExc_ValueError, "Can only create \"P\" format data with 8bit Surfaces"); string = Bytes_FromStringAndSize (NULL, surf->w * surf->h); if (!string) return NULL; Bytes_AsStringAndSize (string, &data, &len); PySurface_Lock (surfobj); pixels = (char*) surf->pixels; for (h = 0; h < surf->h; ++h) memcpy (DATAROW (data, h, surf->w, surf->h, flipped), pixels + (h * surf->pitch), surf->w); PySurface_Unlock (surfobj); } else if (!strcmp (format, "RGB")) { string = Bytes_FromStringAndSize (NULL, surf->w * surf->h * 3); if (!string) return NULL; Bytes_AsStringAndSize (string, &data, &len); if (!temp) PySurface_Lock (surfobj); pixels = (char*) surf->pixels; switch (surf->format->BytesPerPixel) { case 1: for (h = 0; h < surf->h; ++h) { Uint8* ptr = (Uint8*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for (w = 0; w < surf->w; ++w) { color = *ptr++; data[0] = (char) surf->format->palette->colors[color].r; data[1] = (char) surf->format->palette->colors[color].g; data[2] = (char) surf->format->palette->colors[color].b; data += 3; } } break; case 2: for (h = 0; h < surf->h; ++h) { Uint16* ptr = (Uint16*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { color = *ptr++; data[0] = (char) (((color & Rmask) >> Rshift) << Rloss); data[1] = (char) (((color & Gmask) >> Gshift) << Gloss); data[2] = (char) (((color & Bmask) >> Bshift) << Bloss); data += 3; } } break; case 3: for (h = 0; h < surf->h; ++h) { Uint8* ptr = (Uint8*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN color = ptr[0] + (ptr[1]<<8) + (ptr[2]<<16); #else color = ptr[2] + (ptr[1]<<8) + (ptr[0]<<16); #endif ptr += 3; data[0] = (char) (((color & Rmask) >> Rshift) << Rloss); data[1] = (char) (((color & Gmask) >> Gshift) << Gloss); data[2] = (char) (((color & Bmask) >> Bshift) << Bloss); data += 3; } } break; case 4: for (h = 0; h < surf->h; ++h) { Uint32* ptr = (Uint32*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for (w = 0; w < surf->w; ++w) { color = *ptr++; data[0] = (char) (((color & Rmask) >> Rshift) << Rloss); data[1] = (char) (((color & Gmask) >> Gshift) << Rloss); data[2] = (char) (((color & Bmask) >> Bshift) << Rloss); data += 3; } } break; } if (!temp) PySurface_Unlock (surfobj); } else if (!strcmp (format, "RGBX") || !strcmp (format, "RGBA")) { if (strcmp (format, "RGBA")) hascolorkey = 0; string = Bytes_FromStringAndSize (NULL, surf->w * surf->h * 4); if (!string) return NULL; Bytes_AsStringAndSize (string, &data, &len); PySurface_Lock (surfobj); pixels = (char*) surf->pixels; switch (surf->format->BytesPerPixel) { case 1: for(h = 0; h < surf->h; ++h) { Uint8* ptr = (Uint8*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { color = *ptr++; data[0] = (char) surf->format->palette->colors[color].r; data[1] = (char) surf->format->palette->colors[color].g; data[2] = (char) surf->format->palette->colors[color].b; data[3] = hascolorkey ? (char)(color != colorkey) * 255 : (char)255; data += 4; } } break; case 2: for (h = 0; h < surf->h; ++h) { Uint16* ptr = (Uint16*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { color = *ptr++; data[0] = (char) (((color & Rmask) >> Rshift) << Rloss); data[1] = (char) (((color & Gmask) >> Gshift) << Gloss); data[2] = (char) (((color & Bmask) >> Bshift) << Bloss); data[3] = hascolorkey ? (char)(color!=colorkey) * 255 : (char)(Amask ? (((color & Amask) >> Ashift) << Aloss) : 255); data += 4; } } break; case 3: for (h = 0; h < surf->h; ++h) { Uint8* ptr = (Uint8*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for (w = 0; w < surf->w; ++w) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN color = ptr[0] + (ptr[1]<<8) + (ptr[2]<<16); #else color = ptr[2] + (ptr[1]<<8) + (ptr[0]<<16); #endif ptr += 3; data[0] = (char) (((color & Rmask) >> Rshift) << Rloss); data[1] = (char) (((color & Gmask) >> Gshift) << Gloss); data[2] = (char) (((color & Bmask) >> Bshift) << Bloss); data[3] = hascolorkey ? (char)(color!=colorkey)*255 : (char)(Amask ? (((color & Amask) >> Ashift) << Aloss) : 255); data += 4; } } break; case 4: for (h = 0; h < surf->h; ++h) { Uint32* ptr = (Uint32*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { color = *ptr++; data[0] = (char) (((color & Rmask) >> Rshift) << Rloss); data[1] = (char) (((color & Gmask) >> Gshift) << Gloss); data[2] = (char) (((color & Bmask) >> Bshift) << Bloss); data[3] = hascolorkey ? (char)(color!=colorkey)*255 : (char)(Amask ? (((color & Amask) >> Ashift) << Aloss) : 255); data += 4; } } break; } PySurface_Unlock (surfobj); } else if (!strcmp (format, "ARGB")) { hascolorkey = 0; string = Bytes_FromStringAndSize (NULL, surf->w * surf->h * 4); if (!string) return NULL; Bytes_AsStringAndSize (string, &data, &len); PySurface_Lock (surfobj); pixels = (char*) surf->pixels; switch (surf->format->BytesPerPixel) { case 1: for (h = 0; h < surf->h; ++h) { Uint8* ptr = (Uint8*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for (w = 0; w < surf->w; ++w) { color = *ptr++; data[1] = (char)surf->format->palette->colors[color].r; data[2] = (char)surf->format->palette->colors[color].g; data[3] = (char)surf->format->palette->colors[color].b; data[0] = hascolorkey ? (char)(color!=colorkey)*255 : (char)255; data += 4; } } break; case 2: for(h = 0; h < surf->h; ++h) { Uint16* ptr = (Uint16*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { color = *ptr++; data[1] = (char) (((color & Rmask) >> Rshift) << Rloss); data[2] = (char) (((color & Gmask) >> Gshift) << Gloss); data[3] = (char) (((color & Bmask) >> Bshift) << Bloss); data[0] = hascolorkey ? (char)(color!=colorkey)*255 : (char)(Amask ? (((color & Amask) >> Ashift) << Aloss) : 255); data += 4; } } break; case 3: for (h = 0; h < surf->h; ++h) { Uint8* ptr = (Uint8*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for (w = 0; w < surf->w; ++w) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN color = ptr[0] + (ptr[1]<<8) + (ptr[2]<<16); #else color = ptr[2] + (ptr[1]<<8) + (ptr[0]<<16); #endif ptr += 3; data[1] = (char) (((color & Rmask) >> Rshift) << Rloss); data[2] = (char) (((color & Gmask) >> Gshift) << Gloss); data[3] = (char) (((color & Bmask) >> Bshift) << Bloss); data[0] = hascolorkey ? (char)(color!=colorkey)*255 : (char)(Amask ? (((color & Amask) >> Ashift) << Aloss) : 255); data += 4; } } break; case 4: for (h = 0; h < surf->h; ++h) { Uint32* ptr = (Uint32*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for (w = 0; w < surf->w; ++w) { color = *ptr++; data[1] = (char) (((color & Rmask) >> Rshift) << Rloss); data[2] = (char) (((color & Gmask) >> Gshift) << Gloss); data[3] = (char) (((color & Bmask) >> Bshift) << Bloss); data[0] = hascolorkey ? (char)(color!=colorkey)*255 : (char)(Amask ? (((color & Amask) >> Ashift) << Aloss) : 255); data += 4; } } break; } PySurface_Unlock (surfobj); } else if (!strcmp (format, "RGBA_PREMULT")) { if (surf->format->BytesPerPixel == 1 || surf->format->Amask == 0) return RAISE (PyExc_ValueError, "Can only create pre-multiplied alpha strings if the surface has per-pixel alpha"); hascolorkey = 0; string = Bytes_FromStringAndSize (NULL, surf->w * surf->h * 4); if (!string) return NULL; Bytes_AsStringAndSize (string, &data, &len); PySurface_Lock (surfobj); pixels = (char*) surf->pixels; switch (surf->format->BytesPerPixel) { case 2: for (h = 0; h < surf->h; ++h) { Uint16* ptr = (Uint16*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { color = *ptr++; alpha = ((color & Amask) >> Ashift) << Aloss; data[0] = (char) ((((color & Rmask) >> Rshift) << Rloss)*alpha/255); data[1] = (char) ((((color & Gmask) >> Gshift) << Gloss)*alpha/255); data[2] = (char) ((((color & Bmask) >> Bshift) << Bloss)*alpha/255); data[3] = (char) alpha; data += 4; } } break; case 3: for (h = 0; h < surf->h; ++h) { Uint8* ptr = (Uint8*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for (w = 0; w < surf->w; ++w) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN color = ptr[0] + (ptr[1]<<8) + (ptr[2]<<16); #else color = ptr[2] + (ptr[1]<<8) + (ptr[0]<<16); #endif ptr += 3; alpha = ((color & Amask) >> Ashift) << Aloss; data[0] = (char) ((((color & Rmask) >> Rshift) << Rloss)*alpha/255); data[1] = (char) ((((color & Gmask) >> Gshift) << Gloss)*alpha/255); data[2] = (char) ((((color & Bmask) >> Bshift) << Bloss)*alpha/255); data[3] = (char) alpha; data += 4; } } break; case 4: for (h = 0; h < surf->h; ++h) { Uint32* ptr = (Uint32*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { color = *ptr++; alpha = ((color & Amask) >> Ashift) << Aloss; if (alpha == 0) { data[0] = data[1] = data[2] = 0; } else { data[0] = (char) ((((color & Rmask) >> Rshift) << Rloss)*alpha/255); data[1] = (char) ((((color & Gmask) >> Gshift) << Gloss)*alpha/255); data[2] = (char) ((((color & Bmask) >> Bshift) << Bloss)*alpha/255); } data[3] = (char) alpha; data += 4; } } break; } PySurface_Unlock (surfobj); } else if (!strcmp (format, "ARGB_PREMULT")) { if (surf->format->BytesPerPixel == 1 || surf->format->Amask == 0) return RAISE (PyExc_ValueError, "Can only create pre-multiplied alpha strings if the surface has per-pixel alpha"); hascolorkey = 0; string = Bytes_FromStringAndSize (NULL, surf->w * surf->h * 4); if (!string) return NULL; Bytes_AsStringAndSize (string, &data, &len); PySurface_Lock (surfobj); pixels = (char*) surf->pixels; switch (surf->format->BytesPerPixel) { case 2: for (h = 0; h < surf->h; ++h) { Uint16* ptr = (Uint16*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { color = *ptr++; alpha = ((color & Amask) >> Ashift) << Aloss; data[1] = (char) ((((color & Rmask) >> Rshift) << Rloss)*alpha/255); data[2] = (char) ((((color & Gmask) >> Gshift) << Gloss)*alpha/255); data[3] = (char) ((((color & Bmask) >> Bshift) << Bloss)*alpha/255); data[0] = (char) alpha; data += 4; } } break; case 3: for (h = 0; h < surf->h; ++h) { Uint8* ptr = (Uint8*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for (w = 0; w < surf->w; ++w) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN color = ptr[0] + (ptr[1]<<8) + (ptr[2]<<16); #else color = ptr[2] + (ptr[1]<<8) + (ptr[0]<<16); #endif ptr += 3; alpha = ((color & Amask) >> Ashift) << Aloss; data[1] = (char) ((((color & Rmask) >> Rshift) << Rloss)*alpha/255); data[2] = (char) ((((color & Gmask) >> Gshift) << Gloss)*alpha/255); data[3] = (char) ((((color & Bmask) >> Bshift) << Bloss)*alpha/255); data[0] = (char) alpha; data += 4; } } break; case 4: for (h = 0; h < surf->h; ++h) { Uint32* ptr = (Uint32*) DATAROW (surf->pixels, h, surf->pitch, surf->h, flipped); for(w = 0; w < surf->w; ++w) { color = *ptr++; alpha = ((color & Amask) >> Ashift) << Aloss; if (alpha == 0) { data[1] = data[2] = data[3] = 0; } else { data[1] = (char) ((((color & Rmask) >> Rshift) << Rloss)*alpha/255); data[2] = (char) ((((color & Gmask) >> Gshift) << Gloss)*alpha/255); data[3] = (char) ((((color & Bmask) >> Bshift) << Bloss)*alpha/255); } data[0] = (char) alpha; data += 4; } } break; } PySurface_Unlock (surfobj); } else { if (temp) SDL_FreeSurface (temp); return RAISE (PyExc_ValueError, "Unrecognized type of format"); } if (temp) SDL_FreeSurface (temp); return string; } PyObject* image_fromstring (PyObject* self, PyObject* arg) { PyObject *string; char *format, *data; SDL_Surface *surf = NULL; int w, h, flipped=0; Py_ssize_t len; int loopw, looph; if (!PyArg_ParseTuple (arg, "O!(ii)s|i", &Bytes_Type, &string, &w, &h, &format, &flipped)) return NULL; if (w < 1 || h < 1) return RAISE (PyExc_ValueError, "Resolution must be positive values"); Bytes_AsStringAndSize (string, &data, &len); if (!strcmp (format, "P")) { if (len != w * h) return RAISE (PyExc_ValueError, "String length does not equal format and resolution size"); surf = SDL_CreateRGBSurface (0, w, h, 8, 0, 0, 0, 0); if (!surf) return RAISE (PyExc_SDLError, SDL_GetError ()); SDL_LockSurface (surf); for (looph = 0; looph < h; ++looph) memcpy(((char*) surf->pixels) + looph * surf->pitch, DATAROW (data, looph, w, h, flipped), w); SDL_UnlockSurface (surf); } else if (!strcmp (format, "RGB")) { if (len != w * h * 3) return RAISE (PyExc_ValueError, "String length does not equal format and resolution size"); surf = SDL_CreateRGBSurface (0, w, h, 24, 0xFF<<16, 0xFF<<8, 0xFF, 0); if (!surf) return RAISE (PyExc_SDLError, SDL_GetError ()); SDL_LockSurface (surf); for (looph = 0; looph < h; ++looph) { Uint8* pix = (Uint8*) DATAROW (surf->pixels, looph, surf->pitch, h, flipped); for (loopw = 0; loopw < w; ++loopw) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN pix[2] = data[0]; pix[1] = data[1]; pix[0] = data[2]; #else pix[0] = data[0]; pix[1] = data[1]; pix[2] = data[2]; #endif pix += 3; data += 3; } } SDL_UnlockSurface (surf); } else if (!strcmp (format, "RGBA") || !strcmp (format, "RGBX")) { int alphamult = !strcmp (format, "RGBA"); if (len != w * h * 4) return RAISE (PyExc_ValueError, "String length does not equal format and resolution size"); surf = SDL_CreateRGBSurface ((alphamult ? SDL_SRCALPHA : 0), w, h, 32, #if SDL_BYTEORDER == SDL_LIL_ENDIAN 0xFF, 0xFF<<8, 0xFF<<16, (alphamult ? 0xFF << 24 : 0)); #else 0xFF<<24, 0xFF<<16, 0xFF<<8, (alphamult ? 0xFF : 0)); #endif if (!surf) return RAISE (PyExc_SDLError, SDL_GetError ()); SDL_LockSurface (surf); for (looph = 0; looph < h; ++looph) { Uint32* pix = (Uint32*) DATAROW (surf->pixels, looph, surf->pitch, h, flipped); for (loopw = 0; loopw < w; ++loopw) { *pix++ = *((Uint32*) data); data += 4; } } SDL_UnlockSurface (surf); } else if (!strcmp (format, "ARGB")) { if (len != w * h * 4) return RAISE (PyExc_ValueError, "String length does not equal format and resolution size"); surf = SDL_CreateRGBSurface (SDL_SRCALPHA, w, h, 32, #if SDL_BYTEORDER == SDL_LIL_ENDIAN 0xFF<<8, 0xFF<<16, 0xFF<<24, 0xFF); #else 0xFF<<16, 0xFF<<8, 0xFF, 0xFF<<24); #endif if (!surf) return RAISE (PyExc_SDLError, SDL_GetError ()); SDL_LockSurface (surf); for (looph = 0; looph < h; ++looph) { Uint32* pix = (Uint32*) DATAROW (surf->pixels, looph, surf->pitch, h, flipped); for (loopw = 0; loopw < w; ++loopw) { *pix++ = *((Uint32*) data); data += 4; } } SDL_UnlockSurface (surf); } else return RAISE (PyExc_ValueError, "Unrecognized type of format"); if (!surf) return NULL; return PySurface_New (surf); } PyObject* image_frombuffer (PyObject* self, PyObject* arg) { PyObject *buffer; char *format, *data; SDL_Surface *surf = NULL; int w, h; Py_ssize_t len; PyObject *surfobj; if (!PyArg_ParseTuple (arg, "O(ii)s|i", &buffer, &w, &h, &format)) return NULL; if (w < 1 || h < 1) return RAISE (PyExc_ValueError, "Resolution must be positive values"); /* breaking constness here, we should really not change this string */ if (PyObject_AsCharBuffer (buffer, (const char**)&data, &len) == -1) return NULL; if (!strcmp (format, "P")) { if (len != w * h) return RAISE (PyExc_ValueError, "Buffer length does not equal format and resolution size"); surf = SDL_CreateRGBSurfaceFrom (data, w, h, 8, w, 0, 0, 0, 0); } else if (!strcmp (format, "RGB")) { if (len != w * h * 3) return RAISE (PyExc_ValueError, "Buffer length does not equal format and resolution size"); surf = SDL_CreateRGBSurfaceFrom (data, w, h, 24, w * 3, 0xFF, 0xFF<<8, 0xFF<<16, 0); /* #if SDL_BYTEORDER == SDL_LIL_ENDIAN 0xFF, 0xFF<<8, 0xFF<<16, 0xFF<<24 #else 0xFF<<24, 0xFF<<16, 0xFF<<8, 0xFF #endif ); */ } else if (!strcmp (format, "RGBA") || !strcmp (format, "RGBX")) { int alphamult = !strcmp (format, "RGBA"); if (len != w * h * 4) return RAISE (PyExc_ValueError, "Buffer length does not equal format and resolution size"); surf = SDL_CreateRGBSurfaceFrom (data, w, h, 32, w * 4, #if SDL_BYTEORDER == SDL_LIL_ENDIAN 0xFF, 0xFF<<8, 0xFF<<16, (alphamult ? 0xFF << 24 : 0)); #else 0xFF<<24, 0xFF<<16, 0xFF<<8, (alphamult ? 0xFF : 0)); #endif if(alphamult) surf->flags |= SDL_SRCALPHA; } else if (!strcmp (format, "ARGB")) { if (len != w * h * 4) return RAISE (PyExc_ValueError, "Buffer length does not equal format and resolution size"); surf = SDL_CreateRGBSurfaceFrom (data, w, h, 32, w*4, #if SDL_BYTEORDER == SDL_LIL_ENDIAN 0xFF<<24, 0xFF, 0xFF<<8, 0xFF<<16); #else 0xFF, 0xFF<<24, 0xFF<<16, 0xFF<<8); #endif surf->flags |= SDL_SRCALPHA; } else return RAISE(PyExc_ValueError, "Unrecognized type of format"); if (!surf) return RAISE (PyExc_SDLError, SDL_GetError ()); surfobj = PySurface_New (surf); Py_INCREF (buffer); ((PySurfaceObject*) surfobj)->dependency = buffer; return surfobj; } /*******************************************************/ /* tga code by Mattias Engdegard, in the public domain */ /*******************************************************/ struct TGAheader { Uint8 infolen; /* length of info field */ Uint8 has_cmap; /* 1 if image has colormap, 0 otherwise */ Uint8 type; Uint8 cmap_start[2]; /* index of first colormap entry */ Uint8 cmap_len[2]; /* number of entries in colormap */ Uint8 cmap_bits; /* bits per colormap entry */ Uint8 yorigin[2]; /* image origin (ignored here) */ Uint8 xorigin[2]; Uint8 width[2]; /* image size */ Uint8 height[2]; Uint8 pixel_bits; /* bits/pixel */ Uint8 flags; }; enum tga_type { TGA_TYPE_INDEXED = 1, TGA_TYPE_RGB = 2, TGA_TYPE_BW = 3, TGA_TYPE_RLE = 8 /* additive */ }; #define TGA_INTERLEAVE_MASK 0xc0 #define TGA_INTERLEAVE_NONE 0x00 #define TGA_INTERLEAVE_2WAY 0x40 #define TGA_INTERLEAVE_4WAY 0x80 #define TGA_ORIGIN_MASK 0x30 #define TGA_ORIGIN_LEFT 0x00 #define TGA_ORIGIN_RIGHT 0x10 #define TGA_ORIGIN_LOWER 0x00 #define TGA_ORIGIN_UPPER 0x20 /* read/write unaligned little-endian 16-bit ints */ #define LE16(p) ((p)[0] + ((p)[1] << 8)) #define SETLE16(p, v) ((p)[0] = (v), (p)[1] = (v) >> 8) #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif #define TGA_RLE_MAX 128 /* max length of a TGA RLE chunk */ /* return the number of bytes in the resulting buffer after RLE-encoding a line of TGA data */ static int rle_line (Uint8 *src, Uint8 *dst, int w, int bpp) { int x = 0; int out = 0; int raw = 0; while (x < w) { Uint32 pix; int x0 = x; memcpy (&pix, src + x * bpp, bpp); x++; while (x < w && memcmp (&pix, src + x * bpp, bpp) == 0 && x - x0 < TGA_RLE_MAX) x++; /* use a repetition chunk iff the repeated pixels would consume two bytes or more */ if ((x - x0 - 1) * bpp >= 2 || x == w) { /* output previous raw chunks */ while (raw < x0) { int n = MIN (TGA_RLE_MAX, x0 - raw); dst[out++] = n - 1; memcpy (dst + out, src + raw * bpp, n * bpp); out += n * bpp; raw += n; } if (x - x0 > 0) { /* output new repetition chunk */ dst[out++] = 0x7f + x - x0; memcpy (dst + out, &pix, bpp); out += bpp; } raw = x; } } return out; } /* * Save a surface to an output stream in TGA format. * 8bpp surfaces are saved as indexed images with 24bpp palette, or with * 32bpp palette if colourkeying is used. * 15, 16, 24 and 32bpp surfaces are saved as 24bpp RGB images, * or as 32bpp RGBA images if alpha channel is used. * * RLE compression is not used in the output file. * * Returns -1 upon error, 0 if success */ static int SaveTGA_RW (SDL_Surface *surface, SDL_RWops *out, int rle) { SDL_Surface *linebuf = NULL; int alpha = 0; int ckey = -1; struct TGAheader h; int srcbpp; unsigned surf_flags; unsigned surf_alpha; Uint32 rmask, gmask, bmask, amask; SDL_Rect r; int bpp; Uint8 *rlebuf = NULL; h.infolen = 0; SETLE16 (h.cmap_start, 0); srcbpp = surface->format->BitsPerPixel; if (srcbpp < 8) { SDL_SetError ("cannot save <8bpp images as TGA"); return -1; } if (srcbpp == 8) { h.has_cmap = 1; h.type = TGA_TYPE_INDEXED; if (surface->flags & SDL_SRCCOLORKEY) { ckey = surface->format->colorkey; h.cmap_bits = 32; } else h.cmap_bits = 24; SETLE16 (h.cmap_len, surface->format->palette->ncolors); h.pixel_bits = 8; rmask = gmask = bmask = amask = 0; } else { h.has_cmap = 0; h.type = TGA_TYPE_RGB; h.cmap_bits = 0; SETLE16 (h.cmap_len, 0); if (surface->format->Amask) { alpha = 1; h.pixel_bits = 32; } else h.pixel_bits = 24; if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { int s = alpha ? 0 : 8; amask = 0x000000ff >> s; rmask = 0x0000ff00 >> s; gmask = 0x00ff0000 >> s; bmask = 0xff000000 >> s; } else { amask = alpha ? 0xff000000 : 0; rmask = 0x00ff0000; gmask = 0x0000ff00; bmask = 0x000000ff; } } bpp = h.pixel_bits >> 3; if (rle) h.type += TGA_TYPE_RLE; SETLE16 (h.yorigin, 0); SETLE16 (h.xorigin, 0); SETLE16 (h.width, surface->w); SETLE16 (h.height, surface->h); h.flags = TGA_ORIGIN_UPPER | (alpha ? 8 : 0); if (!SDL_RWwrite (out, &h, sizeof (h), 1)) return -1; if (h.has_cmap) { int i; SDL_Palette *pal = surface->format->palette; Uint8 entry[4]; for (i = 0; i < pal->ncolors; i++) { entry[0] = pal->colors[i].b; entry[1] = pal->colors[i].g; entry[2] = pal->colors[i].r; entry[3] = (i == ckey) ? 0 : 0xff; if (!SDL_RWwrite (out, entry, h.cmap_bits >> 3, 1)) return -1; } } linebuf = SDL_CreateRGBSurface (SDL_SWSURFACE, surface->w, 1, h.pixel_bits, rmask, gmask, bmask, amask); if (!linebuf) return -1; if (h.has_cmap) SDL_SetColors (linebuf, surface->format->palette->colors, 0, surface->format->palette->ncolors); if (rle) { rlebuf = malloc (bpp * surface->w + 1 + surface->w / TGA_RLE_MAX); if (!rlebuf) { SDL_SetError ("out of memory"); goto error; } } /* Temporarily remove colourkey and alpha from surface so copies are opaque */ surf_flags = surface->flags & (SDL_SRCALPHA | SDL_SRCCOLORKEY); surf_alpha = surface->format->alpha; if (surf_flags & SDL_SRCALPHA) SDL_SetAlpha (surface, 0, 255); if (surf_flags & SDL_SRCCOLORKEY) SDL_SetColorKey (surface, 0, surface->format->colorkey); r.x = 0; r.w = surface->w; r.h = 1; for (r.y = 0; r.y < surface->h; r.y++) { int n; void *buf; if (SDL_BlitSurface (surface, &r, linebuf, NULL) < 0) break; if (rle) { buf = rlebuf; n = rle_line (linebuf->pixels, rlebuf, surface->w, bpp); } else { buf = linebuf->pixels; n = surface->w * bpp; } if (!SDL_RWwrite (out, buf, n, 1)) break; } /* restore flags */ if (surf_flags & SDL_SRCALPHA) SDL_SetAlpha (surface, SDL_SRCALPHA, (Uint8)surf_alpha); if (surf_flags & SDL_SRCCOLORKEY) SDL_SetColorKey (surface, SDL_SRCCOLORKEY, surface->format->colorkey); error: free (rlebuf); SDL_FreeSurface (linebuf); return 0; } static int SaveTGA (SDL_Surface *surface, const char *file, int rle) { SDL_RWops *out = SDL_RWFromFile (file, "wb"); int ret; if (!out) return -1; ret = SaveTGA_RW (surface, out, rle); SDL_RWclose (out); return ret; } static PyMethodDef _image_methods[] = { { "load_basic", image_load_basic, METH_VARARGS, DOC_PYGAMEIMAGELOAD }, { "save", image_save, METH_VARARGS, DOC_PYGAMEIMAGESAVE }, { "get_extended", (PyCFunction) image_get_extended, METH_NOARGS, DOC_PYGAMEIMAGEGETEXTENDED }, { "tostring", image_tostring, METH_VARARGS, DOC_PYGAMEIMAGETOSTRING }, { "fromstring", image_fromstring, METH_VARARGS, DOC_PYGAMEIMAGEFROMSTRING }, { "frombuffer", image_frombuffer, METH_VARARGS, DOC_PYGAMEIMAGEFROMBUFFER }, { NULL, NULL, 0, NULL } }; MODINIT_DEFINE (image) { PyObject *module; PyObject *extmodule; struct _module_state *st; #if PY3 static struct PyModuleDef _module = { PyModuleDef_HEAD_INIT, "image", DOC_PYGAMEIMAGE, sizeof (struct _module_state), _image_methods, NULL, NULL, NULL, NULL }; #endif /* imported needed apis; Do this first so if there is an error the module is not loaded. */ import_pygame_base (); if (PyErr_Occurred ()) { MODINIT_ERROR; } import_pygame_surface (); if (PyErr_Occurred ()) { MODINIT_ERROR; } import_pygame_rwobject (); if (PyErr_Occurred ()) { MODINIT_ERROR; } /* create the module */ #if PY3 module = PyModule_Create (&_module); #else module = Py_InitModule3 (MODPREFIX "image", _image_methods, DOC_PYGAMEIMAGE); #endif if (module == NULL) { MODINIT_ERROR; } st = GETSTATE (module); /* try to get extended formats */ extmodule = PyImport_ImportModule (IMPPREFIX "imageext"); if (extmodule) { PyObject *extload; PyObject *extsave; extload = PyObject_GetAttrString (extmodule, "load_extended"); if (!extload) { Py_DECREF (extmodule); MODINIT_ERROR; } extsave = PyObject_GetAttrString (extmodule, "save_extended"); if (!extsave) { Py_DECREF (extload); Py_DECREF (extmodule); MODINIT_ERROR; } if (PyModule_AddObject (module, "load_extended", extload)) { Py_DECREF (extload); Py_DECREF (extsave); Py_DECREF (extmodule); MODINIT_ERROR; } if (PyModule_AddObject (module, "save_extended", extsave)) { Py_DECREF(extsave); Py_DECREF(extmodule); MODINIT_ERROR; } Py_INCREF (extload); if (PyModule_AddObject (module, "load", extload)) { Py_DECREF (extload); Py_DECREF (extmodule); MODINIT_ERROR; } Py_DECREF (extmodule); st->is_extended = 1; } else { PyObject* basicload = PyObject_GetAttrString (module, "load_basic"); PyErr_Clear (); PyModule_AddObject (module, "load_extended", Py_None); PyModule_AddObject (module, "save_extended", Py_None); PyModule_AddObject (module, "load", basicload); st->is_extended = 0; } MODINIT_RETURN (module); }
