diff options
Diffstat (limited to 'src/png.c')
-rw-r--r-- | src/png.c | 106 |
1 files changed, 54 insertions, 52 deletions
@@ -18,11 +18,7 @@ */ #include "common.h" #include "png.h" - -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wpadded" -#endif -#include <png.h> +#include "kern.h" /* @@ -30,50 +26,37 @@ * * Users want their files in PNG (most often), not PNM. * Calling an external program for conversion poses - * potential security risks, and is slower. + * potential security risks, and is significantly slower. */ /** - * Convert an image from PNM to PNG. - * - * This is a very limited conversion implementation. - * It is not generally reusable. It makes assumptions - * that are true only necessarily for this program. + * Create an PNG file. * - * @param fdin The file descriptor for the image to convert (PNM). - * @param fdout The file descriptor for the output image (PNG). - * @return Zero on success, -1 on error. + * @param fbfd The file descriptor connected to framebuffer device. + * @param width The width of the image. + * @param height The height of the image. + * @param imgfd The file descriptor connected to conversion process's stdin. + * @return Zero on success, -1 on error. */ int -convert (int fdin, int fdout) +save_png (int fbfd, long width, long height, int imgfd) { -#define SCAN(...) do { if (fscanf(in, __VA_ARGS__) != 1) goto fail; } while (0) - - FILE *in = NULL; - FILE *out = NULL; - long height, width, width3; - long y, x, r, g, b; - png_byte *pixbuf = 0; + char buf[8 << 10]; + FILE *file = NULL; + ssize_t got, off; + size_t adjustment; + png_byte *restrict pixbuf = NULL; png_struct *pngbuf = NULL; png_info *pnginfo = NULL; - int saved_errno = 0, rc, c; + long width3, state = 0; + int rc, saved_errno; - /* Get a FILE * for the input, we want to use fscanf, there is no dscanf. */ - in = fdopen (fdin, "r"); - if (in == NULL) - goto fail; /* Get a FILE * for the output, libpng wants a FILE *, not a file descriptor. */ - out = fdopen (fdout, "w"); - if (out == NULL) + file = fdopen (imgfd, "w"); + if (file == NULL) goto fail; - /* Read head. */ - do c = fgetc(in); while ((c != '\n') && (c != EOF)); - SCAN ("%li ", &width); - SCAN ("%li\n", &height); - do c = fgetc(in); while ((c != '\n') && (c != EOF)); - /* Allocte structures for the PNG. */ width3 = width * 3; pixbuf = malloc ((size_t)width3 * sizeof (png_byte)); @@ -89,28 +72,45 @@ convert (int fdin, int fdout) /* Initialise PNG write, and write head. */ if (setjmp (png_jmpbuf(pngbuf))) /* Failing libpng calls jump here. */ goto fail; - png_init_io (pngbuf, out); + png_init_io (pngbuf, file); png_set_IHDR (pngbuf, pnginfo, (png_uint_32)width, (png_uint_32)height, 8 /* bit depth */, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info (pngbuf, pnginfo); - /* Read and convert body. */ - for (y = 0; y < height; y++) + /* TODO (maybe) The image shall be packed. That is, if 24 bits per pixel is + * unnecessary, less shall be used. 6 bits is often sufficient. */ + + /* Convert raw framebuffer data into a PNG image (body). */ + for (off = 0;;) { - for (x = 0; x < width3; x += 3) + /* Read data from the framebuffer, we may have up to 3 bytes buffered. */ + got = read (fbfd, buf + off, sizeof (buf) - (size_t)off * sizeof (char)); + if (got < 0) + goto fail; + if (got == 0) + break; + got += off; + + /* Convert read pixels. */ + if (convert_fb_to_png (pngbuf, pixbuf, buf, (size_t)got, + width3, &adjustment, &state) < 0) + goto fail; + + /* If we read a whole number of pixels, reset the buffer, otherwise, + move the unconverted bytes to the beginning of the buffer. */ + if (adjustment) { - SCAN ("%li\n", &r); - SCAN ("%li\n", &g); - SCAN ("%li\n", &b); - pixbuf[x + 0] = (png_byte)r; - pixbuf[x + 1] = (png_byte)g; - pixbuf[x + 2] = (png_byte)b; + off -= (ssize_t)adjustment; + memcpy (buf, buf + off, (size_t)(got - off) * sizeof (char)); + off = got - off; } - png_write_row (pngbuf, pixbuf); + else + off = 0; } - png_write_end (pngbuf, pnginfo); + /* Done! */ + png_write_end (pngbuf, pnginfo); rc = 0; goto cleanup; fail: @@ -120,11 +120,13 @@ convert (int fdin, int fdout) cleanup: png_destroy_write_struct (&pngbuf, (pnginfo ? &pnginfo : NULL)); - if (in != NULL) - fclose (in); - if (out != NULL) - fclose (out); + if (file != NULL) + { + fflush (file); + fclose (file); + } free (pixbuf); - return errno = saved_errno, rc; + errno = saved_errno; + return rc; } |