|
|
1.1 root 1: /*
2: Hatari - screenSnapShot.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: Screen Snapshots.
8: */
9: const char ScreenSnapShot_fileid[] = "Hatari screenSnapShot.c : " __DATE__ " " __TIME__;
10:
11: #include <SDL.h>
12: #include <dirent.h>
13: #include <string.h>
14: #include "main.h"
1.1.1.2 ! root 15: #include "configuration.h"
1.1 root 16: #include "log.h"
17: #include "paths.h"
18: #include "screen.h"
19: #include "screenSnapShot.h"
1.1.1.2 ! root 20: #include "statusbar.h"
1.1 root 21: #include "video.h"
22: /* after above that bring in config.h */
23: #if HAVE_LIBPNG
24: # include <png.h>
25: # include <assert.h>
26: # include "pixel_convert.h" /* inline functions */
27: #endif
28:
29:
30: static int nScreenShots = 0; /* Number of screen shots saved */
31:
32:
33: /*-----------------------------------------------------------------------*/
34: /**
35: * Scan working directory to get the screenshot number
36: */
37: static void ScreenSnapShot_GetNum(void)
38: {
39: char dummy[5];
40: int i, num;
41: DIR *workingdir = opendir(Paths_GetWorkingDir());
42: struct dirent *file;
43:
44: nScreenShots = 0;
45: if (workingdir == NULL) return;
46:
47: file = readdir(workingdir);
48: while (file != NULL)
49: {
50: if ( strncmp("grab", file->d_name, 4) == 0 )
51: {
52: /* copy next 4 numbers */
53: for (i = 0; i < 4; i++)
54: {
55: if (file->d_name[4+i] >= '0' && file->d_name[4+i] <= '9')
56: dummy[i] = file->d_name[4+i];
57: else
58: break;
59: }
60:
61: dummy[i] = '\0'; /* null terminate */
62: num = atoi(dummy);
63: if (num > nScreenShots) nScreenShots = num;
64: }
65: /* next file.. */
66: file = readdir(workingdir);
67: }
68:
69: closedir(workingdir);
70: }
71:
72:
73: #if HAVE_LIBPNG
74: /**
75: * Save given SDL surface as PNG. Return png file size > 0 for success.
76: */
77: static int ScreenSnapShot_SavePNG(SDL_Surface *surface, const char *filename)
78: {
79: FILE *fp = NULL;
1.1.1.2 ! root 80: int ret, bottom;
1.1 root 81:
82: fp = fopen(filename, "wb");
83: if (!fp)
84: return -1;
85:
1.1.1.2 ! root 86: if (ConfigureParams.Screen.bCrop)
! 87: bottom = Statusbar_GetHeight();
! 88: else
! 89: bottom = 0;
! 90:
! 91: /* default compression/filter and configured cropping */
! 92: ret = ScreenSnapShot_SavePNG_ToFile(surface, fp, -1, -1, 0, 0, 0, bottom);
1.1 root 93:
94: fclose (fp);
95: return ret; /* >0 if OK, -1 if error */
96: }
97:
98:
99: /**
100: * Save given SDL surface as PNG in an already opened FILE, eventually cropping some borders.
101: * Return png file size > 0 for success.
102: * This function is also used by avi_record.c to save individual frames as png images.
103: */
104: int ScreenSnapShot_SavePNG_ToFile(SDL_Surface *surface, FILE *fp, int png_compression_level, int png_filter ,
105: int CropLeft , int CropRight , int CropTop , int CropBottom )
106: {
107: bool do_lock;
108: int y, ret = -1;
109: int w = surface->w - CropLeft - CropRight;
110: int h = surface->h - CropTop - CropBottom;
1.1.1.2 ! root 111: Uint8 *src_ptr;
1.1 root 112: Uint8 rowbuf[3*surface->w];
113: SDL_PixelFormat *fmt = surface->format;
114: png_colorp palette_ptr = NULL;
115: png_infop info_ptr = NULL;
116: png_structp png_ptr;
117: png_text pngtext;
118: char key[] = "Title";
119: char text[] = "Hatari screenshot";
120: long start;
121:
122: /* Create and initialize the png_struct with error handler functions. */
123: png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
124: if (!png_ptr)
125: {
126: return ret;
127: }
128:
129: /* Allocate/initialize the image information data. */
130: info_ptr = png_create_info_struct(png_ptr);
131: if (!info_ptr)
132: goto png_cleanup;
133:
134: /* libpng ugliness: Set error handling when not supplying own
135: * error handling functions in the png_create_write_struct() call.
136: */
137: if (setjmp(png_jmpbuf(png_ptr)))
138: goto png_cleanup;
139:
140: /* store current pos in fp (could be != 0 for avi recording) */
141: start = ftell ( fp );
142:
143: /* initialize the png structure */
144: png_init_io(png_ptr, fp);
145:
146: /* image data properties */
147: png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB,
148: PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
149: PNG_FILTER_TYPE_DEFAULT);
150:
151: if ( png_compression_level >= 0 )
152: png_set_compression_level ( png_ptr , png_compression_level );
153: if ( png_filter >= 0 )
154: png_set_filter ( png_ptr , 0 , png_filter );
155:
156: /* image info */
157: pngtext.key = key;
158: pngtext.text = text;
159: pngtext.compression = PNG_TEXT_COMPRESSION_NONE;
160: #ifdef PNG_iTXt_SUPPORTED
161: pngtext.lang = NULL;
162: #endif
163: png_set_text(png_ptr, info_ptr, &pngtext, 1);
164:
165: /* write the file header information */
166: png_write_info(png_ptr, info_ptr);
167:
168: /* write surface data rows one at a time (after cropping if necessary) */
169: src_ptr = (Uint8 *)surface->pixels + CropTop * surface->pitch + CropLeft * surface->format->BytesPerPixel;
170: do_lock = SDL_MUSTLOCK(surface);
171: for (y = 0; y < h; y++) {
172: /* need to lock the surface while accessing it directly */
173: if (do_lock)
174: SDL_LockSurface(surface);
175: switch (fmt->BytesPerPixel) {
176: case 1:
177: /* unpack 8-bit data with RGB palette */
1.1.1.2 ! root 178: PixelConvert_8to24Bits(rowbuf, src_ptr, w, fmt->palette->colors);
1.1 root 179: break;
180: case 2:
181: /* unpack 16-bit RGB pixels */
1.1.1.2 ! root 182: PixelConvert_16to24Bits(rowbuf, (Uint16*)src_ptr, w, fmt);
1.1 root 183: break;
184: case 3:
185: /* PNG can handle 24-bits */
186: break;
187: case 4:
188: /* unpack 32-bit RGBA pixels */
1.1.1.2 ! root 189: PixelConvert_32to24Bits(rowbuf, (Uint32*)src_ptr, w, fmt);
1.1 root 190: break;
191: }
192: /* and unlock surface before syscalls */
193: if (do_lock)
194: SDL_UnlockSurface(surface);
195: src_ptr += surface->pitch;
196: png_write_row(png_ptr, rowbuf);
197: }
198:
199: /* write the additional chuncks to the PNG file */
200: png_write_end(png_ptr, info_ptr);
201:
202: ret = ftell ( fp ) - start; /* size of the png image */
203: png_cleanup:
204: if (palette_ptr)
205: free(palette_ptr);
206: if (png_ptr)
207: png_destroy_write_struct(&png_ptr, NULL);
208: return ret;
209: }
210: #endif
211:
212:
213: /*-----------------------------------------------------------------------*/
214: /**
215: * Save screen shot file with filename like 'grab0000.[png|bmp]',
216: * 'grab0001.[png|bmp]', etc... Whether screen shots are saved as BMP
217: * or PNG depends on Hatari configuration.
218: */
219: void ScreenSnapShot_SaveScreen(void)
220: {
221: char *szFileName = malloc(FILENAME_MAX);
222:
223: if (!szFileName) return;
224:
225: ScreenSnapShot_GetNum();
226: /* Create our filename */
227: nScreenShots++;
228: #if HAVE_LIBPNG
229: /* try first PNG */
230: sprintf(szFileName,"%s/grab%4.4d.png", Paths_GetWorkingDir(), nScreenShots);
231: if (ScreenSnapShot_SavePNG(sdlscrn, szFileName) > 0)
232: {
233: fprintf(stderr, "Screen dump saved to: %s\n", szFileName);
234: free(szFileName);
235: return;
236: }
237: #endif
238: sprintf(szFileName,"%s/grab%4.4d.bmp", Paths_GetWorkingDir(), nScreenShots);
239: if (SDL_SaveBMP(sdlscrn, szFileName))
240: fprintf(stderr, "Screen dump failed!\n");
241: else
242: fprintf(stderr, "Screen dump saved to: %s\n", szFileName);
243:
244: free(szFileName);
245: }
246:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.