e1ffdeca0083f4391ed98f798eb5af4255c35c67
[geeqie.git] / src / image-load-zxscr.cc
1 /*
2  * Copyright (C) 2021 - The Geeqie Team
3  *
4  * Author: Dusan Gallo
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "main.h"
22
23 #include "image-load.h"
24 #include "image-load-zxscr.h"
25
26 struct ImageLoaderZXSCR {
27         ImageLoaderBackendCbAreaUpdated area_updated_cb;
28         ImageLoaderBackendCbSize size_cb;
29         ImageLoaderBackendCbAreaPrepared area_prepared_cb;
30         gpointer data;
31         GdkPixbuf *pixbuf;
32         guint requested_width;
33         guint requested_height;
34         gboolean abort;
35 };
36
37 const guchar palette[2][8][3] = {
38         {
39                 {0x00, 0x00, 0x00},
40                 {0x00, 0x00, 0xbf},
41                 {0xbf, 0x00, 0x00},
42                 {0xbf, 0x00, 0xbf},
43                 {0x00, 0xbf, 0x00},
44                 {0x00, 0xbf, 0xbf},
45                 {0xbf, 0xbf, 0x00},
46                 {0xbf, 0xbf, 0xbf}
47         }, {
48                 {0x00, 0x00, 0x00},
49                 {0x00, 0x00, 0xff},
50                 {0xff, 0x00, 0x00},
51                 {0xff, 0x00, 0xff},
52                 {0x00, 0xff, 0x00},
53                 {0x00, 0xff, 0xff},
54                 {0xff, 0xff, 0x00},
55                 {0xff, 0xff, 0xff}
56         }
57 };
58
59 static void free_buffer(guchar *pixels, gpointer)
60 {
61         g_free(pixels);
62 }
63
64 static gboolean image_loader_zxscr_load(gpointer loader, const guchar *buf, gsize count, GError **)
65 {
66         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
67         guint8 *pixels;
68         gint width;
69         gint height;
70         gint row;
71         gint col;
72         gint mrow;
73         gint pxs;
74         gint i;
75         guint8 attr;
76         guint8 bright;
77         guint8 ink;
78         guint8 paper;
79         guint8 *ptr;
80
81         if (count != 6144 && count != 6912)
82                 {
83                 log_printf("Error: zxscr reader error\n");
84                 return FALSE;
85                 }
86
87         width = 256;
88         height = 192;
89
90         pixels = static_cast<guint8 *>(g_try_malloc(width * height * 3));
91
92         if (!pixels)
93                 {
94                 log_printf("Error: zxscr reader error\n");
95                 return FALSE;
96                 }
97
98         ld->pixbuf = gdk_pixbuf_new_from_data(pixels, GDK_COLORSPACE_RGB, FALSE, 8, width, height, width * 3, free_buffer, nullptr);
99
100         if (!ld->pixbuf)
101                 {
102                 g_free(pixels);
103                 DEBUG_1("Insufficient memory to open ZXSCR file");
104                 return FALSE;
105                 }
106         //let's decode screen
107         for (row = 0; row < 24; row++)
108                 for (col = 0; col < 32; col++)
109                         {
110                         if (count == 6144)
111                                 {
112                                 //if we have pixels only, make default white ink on black paper
113                                 bright = 0x01;
114                                 ink = 0x07;
115                                 paper = 0x00;
116                                 }
117                         else
118                                 {
119                                 attr = buf[6144 + row * 32 + col];
120                                 bright = (attr >> 6) & 0x01;
121                                 ink = attr & 0x07;
122                                 paper = ((attr >> 3) & 0x07);
123                                 }
124                         ptr = pixels + (row * 256 + col) * 8 * 3;
125
126                         for (mrow = 0; mrow < 8; mrow ++)
127                                 {
128                                 pxs = buf[(row / 8) * 2048 + mrow * 256 + (row % 8) * 32 + col];
129                                 for (i = 0; i < 8; i++)
130                                         {
131                                         if (pxs & 0x80)
132                                                 {
133                                                 *ptr++ = palette[bright][ink][0];       //r
134                                                 *ptr++ = palette[bright][ink][1];       //g
135                                                 *ptr++ = palette[bright][ink][2];       //b
136                                                 }
137                                         else
138                                                 {
139                                                 *ptr++ = palette[bright][paper][0];
140                                                 *ptr++ = palette[bright][paper][1];
141                                                 *ptr++ = palette[bright][paper][2];
142                                                 }
143                                         pxs <<= 1;
144                                         }
145                                 ptr += (31 * 8 * 3);
146                                 }
147                         }
148
149         ld->area_updated_cb(loader, 0, 0, width, height, ld->data);
150
151         return TRUE;
152 }
153
154 static gpointer image_loader_zxscr_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data)
155 {
156         auto loader = g_new0(ImageLoaderZXSCR, 1);
157         loader->area_updated_cb = area_updated_cb;
158         loader->size_cb = size_cb;
159         loader->area_prepared_cb = area_prepared_cb;
160         loader->data = data;
161         return loader;
162 }
163
164 static void image_loader_zxscr_set_size(gpointer loader, int width, int height)
165 {
166         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
167         ld->requested_width = width;
168         ld->requested_height = height;
169 }
170
171 static GdkPixbuf *image_loader_zxscr_get_pixbuf(gpointer loader)
172 {
173         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
174         return ld->pixbuf;
175 }
176
177 static gchar *image_loader_zxscr_get_format_name(gpointer)
178 {
179         return g_strdup("zxscr");
180 }
181
182 static gchar **image_loader_zxscr_get_format_mime_types(gpointer)
183 {
184         static const gchar *mime[] = {"application/octet-stream", nullptr};
185         return g_strdupv(const_cast<gchar **>(mime));
186 }
187
188 static gboolean image_loader_zxscr_close(gpointer, GError **)
189 {
190         return TRUE;
191 }
192
193 static void image_loader_zxscr_abort(gpointer loader)
194 {
195         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
196         ld->abort = TRUE;
197 }
198
199 static void image_loader_zxscr_free(gpointer loader)
200 {
201         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
202         if (ld->pixbuf) g_object_unref(ld->pixbuf);
203         g_free(ld);
204 }
205
206 void image_loader_backend_set_zxscr(ImageLoaderBackend *funcs)
207 {
208         funcs->loader_new = image_loader_zxscr_new;
209         funcs->set_size = image_loader_zxscr_set_size;
210         funcs->load = image_loader_zxscr_load;
211         funcs->write = nullptr;
212         funcs->get_pixbuf = image_loader_zxscr_get_pixbuf;
213         funcs->close = image_loader_zxscr_close;
214         funcs->abort = image_loader_zxscr_abort;
215         funcs->free = image_loader_zxscr_free;
216         funcs->get_format_name = image_loader_zxscr_get_format_name;
217         funcs->get_format_mime_types = image_loader_zxscr_get_format_mime_types;
218 }
219 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */