1 | /*****************************************************************************\ |
2 | Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. |
3 | This file is licensed under the Snes9x License. |
4 | For further information, consult the LICENSE file in the root directory. |
5 | \*****************************************************************************/ |
6 | |
7 | #ifdef HAVE_LIBPNG |
8 | #include <png.h> |
9 | #endif |
10 | #include "snes9x.h" |
11 | #include "memmap.h" |
12 | #include "display.h" |
13 | #include "screenshot.h" |
14 | |
15 | |
16 | bool8 S9xDoScreenshot (int width, int height) |
17 | { |
18 | Settings.TakeScreenshot = FALSE; |
19 | |
20 | #ifdef HAVE_LIBPNG |
21 | FILE *fp; |
22 | png_structp png_ptr; |
23 | png_infop info_ptr; |
24 | png_color_8 sig_bit; |
25 | int imgwidth, imgheight; |
26 | const char *fname; |
27 | |
28 | fname = S9xGetFilenameInc(".png" , SCREENSHOT_DIR); |
29 | |
30 | fp = fopen(fname, "wb" ); |
31 | if (!fp) |
32 | { |
33 | S9xMessage(S9X_ERROR, 0, "Failed to take screenshot." ); |
34 | return (FALSE); |
35 | } |
36 | |
37 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
38 | if (!png_ptr) |
39 | { |
40 | fclose(fp); |
41 | remove(fname); |
42 | S9xMessage(S9X_ERROR, 0, "Failed to take screenshot." ); |
43 | return (FALSE); |
44 | } |
45 | |
46 | info_ptr = png_create_info_struct(png_ptr); |
47 | if (!info_ptr) |
48 | { |
49 | png_destroy_write_struct(&png_ptr, (png_infopp) NULL); |
50 | fclose(fp); |
51 | remove(fname); |
52 | S9xMessage(S9X_ERROR, 0, "Failed to take screenshot." ); |
53 | return (FALSE); |
54 | } |
55 | |
56 | if (setjmp(png_jmpbuf(png_ptr))) |
57 | { |
58 | png_destroy_write_struct(&png_ptr, &info_ptr); |
59 | fclose(fp); |
60 | remove(fname); |
61 | S9xMessage(S9X_ERROR, 0, "Failed to take screenshot." ); |
62 | return (FALSE); |
63 | } |
64 | |
65 | imgwidth = width; |
66 | imgheight = height; |
67 | |
68 | if (Settings.StretchScreenshots == 1) |
69 | { |
70 | if (width > SNES_WIDTH && height <= SNES_HEIGHT_EXTENDED) |
71 | imgheight = height << 1; |
72 | } |
73 | else |
74 | if (Settings.StretchScreenshots == 2) |
75 | { |
76 | if (width <= SNES_WIDTH) |
77 | imgwidth = width << 1; |
78 | if (height <= SNES_HEIGHT_EXTENDED) |
79 | imgheight = height << 1; |
80 | } |
81 | |
82 | png_init_io(png_ptr, fp); |
83 | |
84 | png_set_IHDR(png_ptr, info_ptr, imgwidth, imgheight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); |
85 | |
86 | sig_bit.red = 5; |
87 | sig_bit.green = 5; |
88 | sig_bit.blue = 5; |
89 | png_set_sBIT(png_ptr, info_ptr, &sig_bit); |
90 | png_set_shift(png_ptr, &sig_bit); |
91 | |
92 | png_write_info(png_ptr, info_ptr); |
93 | |
94 | png_set_packing(png_ptr); |
95 | |
96 | png_byte *row_pointer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)]; |
97 | uint16 *screen = GFX.Screen; |
98 | |
99 | for (int y = 0; y < height; y++, screen += GFX.RealPPL) |
100 | { |
101 | png_byte *rowpix = row_pointer; |
102 | |
103 | for (int x = 0; x < width; x++) |
104 | { |
105 | uint32 r, g, b; |
106 | |
107 | DECOMPOSE_PIXEL(screen[x], r, g, b); |
108 | |
109 | *(rowpix++) = r; |
110 | *(rowpix++) = g; |
111 | *(rowpix++) = b; |
112 | |
113 | if (imgwidth != width) |
114 | { |
115 | *(rowpix++) = r; |
116 | *(rowpix++) = g; |
117 | *(rowpix++) = b; |
118 | } |
119 | } |
120 | |
121 | png_write_row(png_ptr, row_pointer); |
122 | if (imgheight != height) |
123 | png_write_row(png_ptr, row_pointer); |
124 | } |
125 | |
126 | delete [] row_pointer; |
127 | |
128 | png_write_end(png_ptr, info_ptr); |
129 | png_destroy_write_struct(&png_ptr, &info_ptr); |
130 | |
131 | fclose(fp); |
132 | |
133 | fprintf(stderr, "%s saved.\n" , fname); |
134 | |
135 | const char *base = S9xBasename(fname); |
136 | sprintf(String, "Saved screenshot %s" , base); |
137 | S9xMessage(S9X_INFO, 0, String); |
138 | |
139 | return (TRUE); |
140 | #else |
141 | fprintf(stderr, "Screenshot support not available (libpng was not found at build time).\n" ); |
142 | return (FALSE); |
143 | #endif |
144 | } |
145 | |