From 6d2d5307a6b358f3528f53cc6a8c9b2acd50f397 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Fri, 11 Dec 2015 11:25:02 +0100 Subject: use libpng, ... now we just have to make it faster MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- DEPENDENCIES | 1 + Makefile.in | 7 ++- doc/info/chap/invoking.texinfo | 10 ++-- mk/lang-c.mk | 10 ++-- po/sv.po | 16 ++--- src/png.c | 130 +++++++++++++++++++++++++++++++++++++++++ src/png.h | 29 +++++++++ src/scrotty.c | 23 ++++---- 8 files changed, 197 insertions(+), 29 deletions(-) create mode 100644 src/png.c create mode 100644 src/png.h diff --git a/DEPENDENCIES b/DEPENDENCIES index d97fafc..c1b1eb0 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -11,6 +11,7 @@ BUILD DEPENDENCIES: coreutils glibc (any libc with getopt_long) libpng + pkg-config c99 gettext (opt-out, for internationalisation) texinfo (opt-out, for info, pdf, dvi, ps, and html manuals) diff --git a/Makefile.in b/Makefile.in index 939647d..4f812f4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -56,9 +56,12 @@ _VERSION = 2.0 _C_STD = c99 _PEDANTIC = yes _BIN = scrotty -_OBJ_scrotty = scrotty kern-linux info pattern +_OBJ_scrotty = scrotty kern-linux info pattern png _HEADER_DIRLEVELS = 1 _CPPFLAGS = -D'PACKAGE="$(PKGNAME)"' -D'PROGRAM_VERSION="$(_VERSION)"' +_CPPFLAGS += $(shell pkg-config --cflags libpng) +# -I is a CPPFLAG, not a CFLAG +_LDFLAGS += $(shell pkg-config --libs libpng) # Used by mk/i18n.mk _SRC = $(foreach B,$(_BIN),$(foreach F,$(_OBJ_$(B)),$(F).c)) @@ -85,7 +88,7 @@ ___EVERYTHING_INFO = scrotty titlepage-data content hardcopy-copying \ appx/fdl appx/free-software-needs-free-documentation appx/gpl \ chap/invoking chap/overview chap/strftime \ reusable/macros reusable/paper reusable/titlepage -___EVERYTHING_H = common kern info pattern pnm +___EVERYTHING_H = common kern info pattern pnm png _EVERYTHING = $(foreach F,$(___EVERYTHING_INFO),doc/info/$(F).texinfo) \ $(foreach F,$(___EVERYTHING_H),src/$(F).h) \ $(__EVERYTHING_ALL_COMMON) DEPENDENCIES INSTALL NEWS $(__todo) doc/concept diff --git a/doc/info/chap/invoking.texinfo b/doc/info/chap/invoking.texinfo index d418fc2..bb4d8db 100644 --- a/doc/info/chap/invoking.texinfo +++ b/doc/info/chap/invoking.texinfo @@ -26,9 +26,15 @@ bytes in difference.} and can in fact be smaller. @sc{PNM} is a good alternative for anything but storage. (Unless you compress them.) + +This option is also useful, in combination with +@option{--exec} if you want to save the image +in any other format. @item -e @itemx --exec CMD Run a command for each saved image. + +Can only be specified once. @end table In addition to these options, a filename @@ -36,10 +42,6 @@ pattern, that does not start with a dash, can be added. This filename pattern selects with what filename the image should be saved. -Further, it is possible add @option{--} -followed by additional options to add when -@command{scrotty} spawns @command{convert}. - Both the @option{--exec} and filename pattern parameters can take format specifiers that are expanded by @command{scrotty} when encountered. diff --git a/mk/lang-c.mk b/mk/lang-c.mk index 5d952b6..b8076d6 100644 --- a/mk/lang-c.mk +++ b/mk/lang-c.mk @@ -112,11 +112,11 @@ _CPPFLAGS += $(foreach D,$(_ALL_DIRS),-D'$(D)="$($(D))"') # MORE HELP VARIABLES: # Compilation and linking flags, and command. -CPPFLAGS = $(_CPPFLAGS) -CFLAGS = $(OPTIMISE) $(WARN) $(_CFLAGS) -LDFLAGS = $(OPTIMISE) $(WARN) $(_LDFLAGS) -__CC = $(CC) -std=$(_C_STD) -c -__LD = $(CC) -std=$(_C_STD) +CPPFLAGS = +CFLAGS = $(OPTIMISE) $(WARN) +LDFLAGS = $(OPTIMISE) $(WARN) +__CC = $(CC) -std=$(_C_STD) -c $(_CPPFLAGS) $(_CFLAGS) +__LD = $(CC) -std=$(_C_STD) $(_LDFLAGS) __CC_POST = $(CPPFLAGS) $(CFLAGS) $(EXTRA_CPPFLAGS) $(EXTRA_CFLAGS) __LD_POST = $(LDFLAGS) $(EXTRA_LDFLAGS) diff --git a/po/sv.po b/po/sv.po index a048ef0..5671231 100644 --- a/po/sv.po +++ b/po/sv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: scrotty 1.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-12-10 22:45+0100\n" +"POT-Creation-Date: 2015-12-11 11:19+0100\n" "PO-Revision-Date: 2015-12-07 18:50+0100\n" "Last-Translator: Mattias Andrée \n" "Language-Team: none\n" @@ -17,34 +17,34 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: src/scrotty.c:373 +#: src/scrotty.c:376 #, c-format msgid "Saved framebuffer %i to %s.\n" msgstr "Bildrutebuffert %i sparad till %s.\n" -#: src/scrotty.c:468 src/scrotty.c:472 src/scrotty.c:478 +#: src/scrotty.c:471 src/scrotty.c:475 src/scrotty.c:481 #, c-format msgid "%s: %s. Type '%s --help' for help.\n" msgstr "%s: %s. Kör '%s --help' för hjälp.\n" -#: src/scrotty.c:468 +#: src/scrotty.c:471 msgid "--exec is used twice." msgstr "--exec förkommer mer än en gång." -#: src/scrotty.c:472 +#: src/scrotty.c:475 msgid "Invalid input." msgstr "Ogiltig indata." -#: src/scrotty.c:478 +#: src/scrotty.c:481 msgid "FILENAME-PATTERN is used twice." msgstr "FILNAMNSMÖNSTER förekommer mer än en gång" -#: src/scrotty.c:509 +#: src/scrotty.c:512 #, c-format msgid "%s: It looks like you are inside a display server. If this is correct, what you see is probably not what you get.\n" msgstr "%s: Det ser ut som att du är innan för en grafikserver. Om detta är korrect, vad de ser är troligtvis inte vad du får.\n" -#: src/scrotty.c:519 +#: src/scrotty.c:522 #, c-format msgid "%s: %s: %s\n" msgstr "%s: %s: %s\n" diff --git a/src/png.c b/src/png.c new file mode 100644 index 0000000..0944f18 --- /dev/null +++ b/src/png.c @@ -0,0 +1,130 @@ +/** + * scrotty — Screenshot program for Linux's TTY + * + * Copyright © 2014, 2015 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "common.h" +#include "png.h" + +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#include + + +/* + * Rationale: + * + * Users want their files in PNG (most often), not PNM. + * Calling an external program for conversion poses + * potential security risks, and is 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. + * + * @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. + */ +int +convert (int fdin, int fdout) +{ +#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; + png_struct *pngbuf = NULL; + png_info *pnginfo = NULL; + int saved_errno = 0, rc, c; + + /* 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) + 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)); + if (pixbuf == NULL) + goto fail; + pngbuf = png_create_write_struct (png_get_libpng_ver (NULL), NULL, NULL, NULL); + if (pngbuf == NULL) + goto fail; + pnginfo = png_create_info_struct (pngbuf); + if (pnginfo == NULL) + goto fail; + + /* Initialise PNG write, and write head. */ + if (setjmp (png_jmpbuf(pngbuf))) /* Failing libpng calls jump here. */ + goto fail; + png_init_io (pngbuf, out); + 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++) + { + for (x = 0; x < width3; x += 3) + { + 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; + } + png_write_row (pngbuf, pixbuf); + } + png_write_end (pngbuf, pnginfo); + + rc = 0; + goto cleanup; + fail: + saved_errno = errno; + rc = -1; + goto cleanup; + + cleanup: + png_destroy_write_struct (&pngbuf, (pnginfo ? &pnginfo : NULL)); + if (in != NULL) + fclose (in); + if (out != NULL) + fclose (out); + free (pixbuf); + return errno = saved_errno, rc; +} + diff --git a/src/png.h b/src/png.h new file mode 100644 index 0000000..02a6223 --- /dev/null +++ b/src/png.h @@ -0,0 +1,29 @@ +/** + * scrotty — Screenshot program for Linux's TTY + * + * Copyright © 2014, 2015 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +/** + * Convert an image from PNM to PNG. + * + * @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. + */ +int convert (int fdin, int fdout); + diff --git a/src/scrotty.c b/src/scrotty.c index da69cc9..9837a26 100644 --- a/src/scrotty.c +++ b/src/scrotty.c @@ -21,6 +21,7 @@ #include "kern.h" #include "info.h" #include "pnm.h" +#include "png.h" #include "pattern.h" #include @@ -188,6 +189,7 @@ save (const char *fbpath, const char *imgpath, long width, long height, int raw) if (raw) goto no_convert; + /* Create a pipe that for sending data into the conversion process program. */ if (pipe (pipe_rw) < 0) goto fail; @@ -203,17 +205,18 @@ save (const char *fbpath, const char *imgpath, long width, long height, int raw) { /* Close the write-end of the pipe. */ close (pipe_rw[1]); - /* Turn the read-end of the pipe into stdin. */ - if (pipe_rw[0] != STDIN_FILENO) - { - close (STDIN_FILENO); - if (dup2 (pipe_rw[0], STDIN_FILENO) == -1) - goto child_fail; - close (pipe_rw[0]); - } - /* Exec. `convert` to convert the PNM-image we create to a compressed image. */ - execlp ("convert", "convert", DEVDIR "/stdin", imgpath, NULL); + /* Open file descriptor for the output image. */ + fd = open(imgpath, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd == -1) + goto child_fail; + + /* Convert the PNM-image we create to a compressed image, namely in PNG. */ + if (convert (pipe_rw[0], fd) < 0) + goto child_fail; + + _exit(0); child_fail: perror(execname); _exit(1); -- cgit v1.2.3-70-g09d2