savepcx.cc

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2000 Willem Jan Palenstijn
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 
00020 /*
00021 A large part of this code is from the GIMP's PCX plugin:
00022 "This code is based in parts on code by Francisco Bustamante, but the
00023 largest portion of the code has been rewritten and is now maintained
00024 occasionally by Nick Lamb njl195@zepler.org.uk."
00025 
00026 It has been partly rewritten to use an SDL surface as input.
00027 */
00028 
00029 #ifdef HAVE_CONFIG_H
00030 #  include <config.h>
00031 #endif
00032 
00033 #ifndef ALPHA_LINUX_CXX
00034 #  include <cstdlib>
00035 #endif
00036 
00037 #include "SDL_video.h"
00038 #include "SDL_endian.h"
00039 #include <iostream>
00040 
00041 #ifndef UNDER_CE
00042 using std::cout;
00043 using std::endl;
00044 using std::free;
00045 using std::malloc;
00046 #endif
00047 
00048 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
00049 #define qtohl(x) (x)
00050 #define qtohs(x) (x)
00051 #else
00052 #define qtohl(x) \
00053         ((Uint32)((((Uint32)(x) & 0x000000ffU) << 24) | \
00054                   (((Uint32)(x) & 0x0000ff00U) <<  8) | \
00055                   (((Uint32)(x) & 0x00ff0000U) >>  8) | \
00056                   (((Uint32)(x) & 0xff000000U) >> 24)))
00057 #define qtohs(x) \
00058         ((Uint16)((((Uint16)(x) & 0x00ff) << 8) | \
00059                   (((Uint16)(x) & 0xff00) >> 8)))
00060 #endif
00061 #define htoql(x) qtohl(x)
00062 #define htoqs(x) qtohs(x)
00063 
00064 typedef struct PCX_Header {
00065   Uint8 manufacturer;
00066   Uint8 version;
00067   Uint8 compression;
00068   Uint8 bpp;
00069   Sint16 x1, y1;
00070   Sint16 x2, y2;
00071   Sint16 hdpi;
00072   Sint16 vdpi;
00073   Uint8 colormap[48];
00074   Uint8 reserved;
00075   Uint8 planes;
00076   Sint16 bytesperline;
00077   Sint16 color;
00078   Uint8 filler[58];
00079 } PCX_Header;
00080 
00081 static void writeline (SDL_RWops *dst, Uint8* buffer, int bytes) {
00082   Uint8 value, count, tmp;
00083   Uint8 *finish = buffer + bytes;
00084 
00085   while (buffer < finish) {
00086   
00087     value = *(buffer++);
00088     count = 1;
00089     
00090     while (buffer < finish && count < 63 && *buffer == value) {
00091       count++; buffer++;
00092     }
00093     
00094     if (value < 0xc0 && count == 1) {
00095       SDL_RWwrite(dst, &value, 1, 1);
00096     } else {
00097       tmp = count + 0xc0;
00098       SDL_RWwrite(dst, &tmp, 1, 1);
00099       SDL_RWwrite(dst, &value, 1, 1);
00100     }
00101   }
00102 }
00103 
00104 
00105 static void save_8 (SDL_RWops *dst, int width, int height, 
00106         int pitch, Uint8* buffer)
00107 {
00108   int row;
00109 
00110   for (row = 0; row < height; ++row) 
00111     {
00112       writeline (dst, buffer, width);
00113       buffer += pitch;
00114     }
00115 }
00116 
00117 
00118 static void save_24 (SDL_RWops *dst, int width, int height,
00119          int pitch, Uint8* buffer)
00120 {
00121   int x, y, c;
00122   Uint8 *line;
00123 
00124   line = (Uint8 *) malloc (width);
00125 
00126   for (y = 0; y < height; ++y) {
00127     for (c = 2; c >= 0; --c) {
00128       for (x = 0; x < width; ++x) {
00129   line[x] = buffer[(3*x) + c];
00130       }
00131       writeline (dst, line, width);
00132     }
00133     buffer += pitch;
00134   }
00135   free (line);
00136 }
00137 
00138 static bool save_image(SDL_Surface *surface, SDL_RWops *dst)
00139 {
00140   Uint8 *cmap = 0;
00141   Uint8 *pixels;
00142   Uint8 tmp;
00143   int width, height, pitch;
00144   int colors = 0, i;
00145   PCX_Header header;
00146 
00147   width = surface->w;
00148   height = surface->h;
00149   pixels = (Uint8*)surface->pixels;
00150   pitch = surface->pitch;
00151 
00152   header.manufacturer = 0x0a;
00153   header.version = 5;
00154   header.compression = 1;
00155 
00156   if (surface->format->palette && surface->format->BitsPerPixel == 8) {
00157     colors = surface->format->palette->ncolors;
00158     cmap = (Uint8*)malloc(3*colors);
00159     for (i = 0; i < colors; i++) {
00160       cmap[3*i] = surface->format->palette->colors[i].r;
00161       cmap[3*i+1] = surface->format->palette->colors[i].g;
00162       cmap[3*i+2] = surface->format->palette->colors[i].b;
00163     }
00164     header.bpp = 8;
00165     header.bytesperline = htoqs (width);
00166     header.planes = 1;
00167     header.color = htoqs (1);
00168   } else if (surface->format->BitsPerPixel == 24) {
00169     header.bpp = 8;
00170     header.bytesperline = htoqs (width);
00171     header.planes = 3;
00172     header.color = htoqs(1);
00173   } else {
00174     return false;
00175   }
00176   
00177   header.x1 = 0;
00178   header.y1 = 0;
00179   header.x2 = htoqs (width - 1);
00180   header.y2 = htoqs (height - 1);
00181 
00182   header.hdpi = htoqs (300);
00183   header.vdpi = htoqs (300);
00184   header.reserved = 0;
00185 
00186   /* write header */
00187   /*  fp_offset = SDL_RWtell(dst);*/
00188   SDL_RWwrite(dst, &header, sizeof(PCX_Header), 1);
00189 
00190   if (cmap) {
00191     save_8 (dst, width, height, pitch, pixels);
00192 
00193     /* write palette */
00194     tmp = 0x0c;
00195     SDL_RWwrite(dst, &tmp, 1, 1);
00196     SDL_RWwrite(dst, cmap, 3, colors);
00197 
00198     /* fill unused colors */
00199     tmp = 0;
00200     for (i = colors; i < 256; i++) {
00201       SDL_RWwrite(dst, &tmp, 1, 1);
00202       SDL_RWwrite(dst, &tmp, 1, 1);
00203       SDL_RWwrite(dst, &tmp, 1, 1);
00204     }
00205 
00206     free(cmap);
00207   } else {
00208     save_24 (dst, width, height, pitch, pixels);
00209   }
00210 
00211   return true;
00212 }
00213 
00214 bool SavePCX_RW (SDL_Surface *saveme, SDL_RWops *dst, bool freedst)
00215 {
00216   SDL_Surface *surface;
00217   bool found_error = false;
00218 
00219   cout << "Taking screenshot...";
00220 
00221   surface = NULL;
00222   if ( dst ) {
00223     if ( saveme->format->palette ) {
00224       if ( saveme->format->BitsPerPixel == 8 ) {
00225   surface = saveme;
00226       } else {
00227   found_error = true;
00228   cout << saveme->format->BitsPerPixel 
00229        << "bpp PCX files not supported" << endl;
00230       }
00231     }
00232     else if ( (saveme->format->BitsPerPixel == 24) &&
00233 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
00234         (saveme->format->Rmask == 0x00FF0000) &&
00235         (saveme->format->Gmask == 0x0000FF00) &&
00236         (saveme->format->Bmask == 0x000000FF)
00237 #else
00238         (saveme->format->Rmask == 0x000000FF) &&
00239         (saveme->format->Gmask == 0x0000FF00) &&
00240         (saveme->format->Bmask == 0x00FF0000)
00241 #endif
00242         ) {
00243       surface = saveme;
00244     } else {
00245       SDL_Rect bounds;
00246       
00247       /* Convert to 24 bits per pixel */
00248       surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
00249              saveme->w, saveme->h, 24,
00250 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
00251              0x00FF0000, 0x0000FF00, 0x000000FF,
00252 #else
00253              0x000000FF, 0x0000FF00, 0x00FF0000,
00254 #endif
00255              0);
00256 
00257       if ( surface != NULL ) {
00258   bounds.x = 0;
00259   bounds.y = 0;
00260   bounds.w = saveme->w;
00261   bounds.h = saveme->h;
00262   if ( SDL_LowerBlit(saveme, &bounds, surface,
00263          &bounds) < 0 ) {
00264     SDL_FreeSurface(surface);
00265     cout << "Couldn't convert image to 24 bpp for screenshot";
00266     found_error = true;
00267     surface = NULL;
00268   }
00269       }
00270     }
00271   } else {
00272     /* no valid target */
00273   }
00274 
00275   if ( surface && (SDL_LockSurface(surface) == 0) ) {
00276     
00277     found_error |= !save_image(surface, dst);
00278 
00279     /* Close it up.. */
00280     SDL_UnlockSurface(surface);
00281     if ( surface != saveme ) {
00282       SDL_FreeSurface(surface);
00283     }
00284   }
00285 
00286   
00287   if ( freedst && dst ) {
00288     SDL_RWclose(dst);
00289   }
00290 
00291   if (!found_error) {
00292     cout << "Done!" << endl;
00293     return true;
00294   }
00295 
00296   return false;
00297 }

Generated on Mon Jul 9 14:42:47 2007 for ExultEngine by  doxygen 1.5.1