summaryrefslogtreecommitdiff
path: root/beryl-plugins/src/jpeg.c
diff options
context:
space:
mode:
authorquinn <quinn@d7aaf104-2d23-0410-ae22-9d23157bf5a3>2007-01-06 18:49:09 +0000
committerquinn <quinn@d7aaf104-2d23-0410-ae22-9d23157bf5a3>2007-01-06 18:49:09 +0000
commitc8a74072cbc99f0940a79510858e642ae771885a (patch)
tree800102c761d00d3af1f2c136219d7d752a567e29 /beryl-plugins/src/jpeg.c
parent807909edaacbe0bb47ed7b9a84a655f68695005a (diff)
downloadmarex-dev-c8a74072cbc99f0940a79510858e642ae771885a.tar.gz
marex-dev-c8a74072cbc99f0940a79510858e642ae771885a.tar.bz2
beryl-plugins:
* add jpeg! (note that configure.ac while having a --disable-jpeg, does not have a test of any sort for finding libjpeg, I doubt this will be an issue on most systems, but it should be remedied) git-svn-id: file:///beryl/trunk@2428 d7aaf104-2d23-0410-ae22-9d23157bf5a3
Diffstat (limited to 'beryl-plugins/src/jpeg.c')
-rw-r--r--beryl-plugins/src/jpeg.c471
1 files changed, 471 insertions, 0 deletions
diff --git a/beryl-plugins/src/jpeg.c b/beryl-plugins/src/jpeg.c
new file mode 100644
index 0000000..5ff45c2
--- /dev/null
+++ b/beryl-plugins/src/jpeg.c
@@ -0,0 +1,471 @@
+/*
+ * beryl-plugins::jpeg.c - adds JPEG image support to beryl.
+ * Copyright: (C) 2006 Nicholas Thomas
+ * Danny Baumann (JPEG writing, option stuff)
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <beryl.h>
+#include <jpeglib.h>
+
+
+#define JPEG_QUALITY_DEFAULT 80
+#define JPEG_QUALITY_MIN 1
+#define JPEG_QUALITY_MAX 100
+
+#define JPEG_DISPLAY_OPTION_QUALITY 0
+#define JPEG_DISPLAY_OPTION_NUM 1
+
+static int displayPrivateIndex;
+
+typedef struct _JPEGDisplay
+{
+ CompOption opt[JPEG_DISPLAY_OPTION_NUM];
+
+ FileToImageProc fileToImage;
+ ImageToFileProc imageToFile;
+} JPEGDisplay;
+
+
+#define GET_JPEG_DISPLAY(d) \
+ ((JPEGDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define JPEG_DISPLAY(d) \
+ JPEGDisplay *jd = GET_JPEG_DISPLAY (d)
+
+#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
+
+static Bool rgbToBGRA(const JSAMPLE *source, void **data, int height, int width, int alpha)
+{
+ int h, w;
+ char *dest;
+
+ dest = malloc(height * width * 4);
+ if (!dest)
+ return FALSE;
+
+ *data = dest;
+
+ for (h = 0; h < height; h++)
+ for (w = 0; w < width; w++)
+ {
+ dest[((h * width + w) * 4) + 0] = source[((h * width + w) * 3) + 2]; //B
+ dest[((h * width + w) * 4) + 1] = source[((h * width + w) * 3) + 1]; //G
+ dest[((h * width + w) * 4) + 2] = source[((h * width + w) * 3) + 0]; //R
+ dest[((h * width + w) * 4) + 3] = alpha;
+ }
+
+ return TRUE;
+}
+
+static Bool rgbaToRGB(char *source, JSAMPLE **dest, int height, int width, int stride)
+{
+ int h, w;
+ int ps = stride / width; /* pixel size */
+ JSAMPLE *d;
+
+ d = malloc(height * width * 3 * sizeof(JSAMPLE));
+ if (!d)
+ return FALSE;
+
+ *dest = d;
+
+ for (h = 0; h < height; h++)
+ for (w = 0; w < width; w++)
+ {
+ d[((h * width + w) * 3) + 0] = source[((h * width + w) * ps) + 0];//R
+ d[((h * width + w) * 3) + 1] = source[((h * width + w) * ps) + 1];//G
+ d[((h * width + w) * 3) + 2] = source[((h * width + w) * ps) + 2];//B
+ }
+
+ return TRUE;
+}
+
+Bool readJPEGFileToImage(FILE *file, int *width, int *height, void **data)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ JSAMPLE *buf;
+ JSAMPROW *rows;
+ int i;
+
+ if (!file)
+ return FALSE;
+
+ cinfo.err = jpeg_std_error(&jerr);
+
+ jpeg_create_decompress(&cinfo);
+
+ jpeg_stdio_src(&cinfo, file);
+ jpeg_read_header(&cinfo, TRUE);
+
+ cinfo.out_color_space = JCS_RGB;
+
+ jpeg_start_decompress(&cinfo);
+
+ *height = cinfo.output_height;
+ *width = cinfo.output_width;
+
+ buf = malloc(cinfo.output_height * cinfo.output_width *
+ cinfo.output_components * sizeof(JSAMPLE));
+ if (!buf)
+ return FALSE;
+
+ rows = malloc(cinfo.output_height * sizeof(JSAMPROW));
+ if (!rows)
+ {
+ free (buf);
+ return FALSE;
+ }
+
+ for(i = 0; i < cinfo.output_height; i++)
+ rows[i] = &buf[i * cinfo.output_width * cinfo.output_components];
+
+ while (cinfo.output_scanline < cinfo.output_height)
+ jpeg_read_scanlines(&cinfo, &rows[cinfo.output_scanline],
+ cinfo.output_height - cinfo.output_scanline);
+
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+
+ // convert the rgb data into BGRA format
+ if (!rgbToBGRA(buf, data, *height, *width, 255))
+ {
+ free(rows);
+ free(buf);
+ return FALSE;
+ }
+
+ free(rows);
+ free(buf);
+ return TRUE;
+}
+
+
+static Bool writeJPEG(CompDisplay *d, void *buffer, FILE *file,
+ int width, int height, int stride)
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ JSAMPROW row_pointer[1];
+ JSAMPLE *data;
+
+ JPEG_DISPLAY(d);
+
+ // convert the rgb data into BGRA format
+ if (!rgbaToRGB(buffer, &data, height, width, stride))
+ return FALSE;
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+
+ jpeg_stdio_dest(&cinfo, file);
+
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo,
+ jd->opt[JPEG_DISPLAY_OPTION_QUALITY].value.i, TRUE);
+ jpeg_start_compress(&cinfo, TRUE);
+
+ while (cinfo.next_scanline < cinfo.image_height) {
+ row_pointer[0] =
+ &data[(cinfo.image_height - cinfo.next_scanline - 1) * width * 3];
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ free(data);
+
+ return TRUE;
+}
+
+// Turns the path & name into a real, absolute path
+// No extensions jiggery-pokery here, as JPEGs can be
+// .jpg or .jpeg - or, indeed, whatever.
+// Deals with the path, regardless of what it's passed.
+static char *createFilename(const char *path, const char *name)
+{
+ int len;
+ char *filename = NULL;
+
+ if (path && !name)
+ len = strlen(path) + 2;
+ else if (!path && name)
+ len = strlen(name) + 2;
+ else if (path && name)
+ len = strlen(path) + strlen(name) + 2;
+ else
+ return NULL;
+
+ filename = malloc(len);
+ if (!filename)
+ return NULL;
+
+ if (path && !name)
+ sprintf(filename, "%s", path);
+ else if (!path && name)
+ sprintf(filename, "%s", name);
+ else
+ sprintf(filename, "%s/%s", path, name);
+
+ return filename;
+
+}
+
+static Bool JPEGImageToFile(CompDisplay *d,
+ const char *path,
+ const char *name,
+ const char *format,
+ int width, int height, int stride, void *data)
+{
+ Bool status = FALSE;
+
+ // Not a JPEG
+ if (strcasecmp(format, "jpeg") != 0 && strcasecmp(format, "jpg") != 0)
+ {
+ JPEG_DISPLAY(d);
+ UNWRAP(jd, d, imageToFile);
+ status = (*d->imageToFile) (d, path, name, format, width, height, stride, data);
+ WRAP(jd, d, imageToFile, JPEGImageToFile);
+ return status;
+ }
+
+ // Is a JPEG
+ char *filename = createFilename(path, name);
+
+ if (!filename)
+ return FALSE;
+
+ FILE *file = fopen(filename, "wb");
+ if (file)
+ {
+ status = writeJPEG(d, data, file, width, height, stride);
+ fclose(file);
+ }
+
+ free(filename);
+ return status;
+}
+
+static Bool JPEGFileToImage(CompDisplay *d,
+ const char *path,
+ const char *name,
+ int *width, int *height, int *stride, void **data)
+{
+ Bool status = FALSE;
+
+ char *filename = createFilename(path, name);
+ if (!filename)
+ return FALSE;
+
+ // Do some testing here to see if it's got a .jpg or .jpeg extension
+ // TODO: fix for mixed & uppercase extensions!
+ char *extension = strrchr(filename, '.');
+ if (extension)
+ {
+ if (strcasecmp(extension, ".jpeg") == 0 ||
+ strcasecmp(extension, ".jpg") == 0)
+ {
+ FILE *file = fopen(filename, "rb");
+ if (file)
+ {
+ status = readJPEGFileToImage(file, width, height, data);
+ fclose(file);
+
+ if (status) // Success!
+ {
+ free(filename);
+ *stride = *width * 4;
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ free(filename);
+
+ // Isn't a JPEG - pass to the next in the chain.
+ JPEG_DISPLAY(d);
+
+ UNWRAP(jd, d, fileToImage);
+ status = (*d->fileToImage) (d, path, name, width, height, stride, data);
+ WRAP(jd, d, fileToImage, JPEGFileToImage);
+
+ return status;
+}
+
+static void JPEGDisplayInitOptions(JPEGDisplay *jd)
+{
+ CompOption *o;
+
+ o = &jd->opt[JPEG_DISPLAY_OPTION_QUALITY];
+ o->advanced = False;
+ o->name = "quality";
+ o->group = N_("Misc. options");
+ o->subGroup = N_("");
+ o->displayHints = "";
+ o->shortDesc = N_("Compression quality");
+ o->longDesc = N_("Quality of compression when saving JPEG images");
+ o->type = CompOptionTypeInt;
+ o->value.i = JPEG_QUALITY_DEFAULT;
+ o->rest.i.min = JPEG_QUALITY_MIN;
+ o->rest.i.max = JPEG_QUALITY_MAX;
+}
+
+static CompOption *JPEGGetDisplayOptions(CompDisplay *display, int *count)
+{
+ if (display)
+ {
+ JPEG_DISPLAY(display);
+
+ *count = NUM_OPTIONS(jd);
+ return jd->opt;
+ } else {
+ JPEGDisplay *jd = malloc(sizeof(JPEGDisplay));
+
+ JPEGDisplayInitOptions(jd);
+ *count = NUM_OPTIONS(jd);
+ return jd->opt;
+ }
+}
+
+static Bool
+JPEGSetDisplayOption(CompDisplay *display, char *name, CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ JPEG_DISPLAY(display);
+
+ o = compFindOption(jd->opt, NUM_OPTIONS(jd), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index)
+ {
+ case JPEG_DISPLAY_OPTION_QUALITY:
+ if (compSetIntOption(o, value))
+ return TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static Bool JPEGInitDisplay(CompPlugin *p, CompDisplay *d)
+{
+ JPEGDisplay *jd;
+ CompScreen *s;
+
+ jd = malloc(sizeof(JPEGDisplay));
+ if (!jd)
+ return FALSE;
+
+ WRAP(jd, d, fileToImage, JPEGFileToImage);
+ WRAP(jd, d, imageToFile, JPEGImageToFile);
+
+ d->privates[displayPrivateIndex].ptr = jd;
+
+ JPEGDisplayInitOptions(jd);
+
+ for (s = d->screens; s; s = s->next)
+ updateDefaultIcon(s);
+
+ return TRUE;
+}
+
+static void JPEGFiniDisplay(CompPlugin *p, CompDisplay *d)
+{
+ CompScreen *s;
+
+ JPEG_DISPLAY(d);
+
+ UNWRAP(jd, d, fileToImage);
+ UNWRAP(jd, d, imageToFile);
+
+ for (s = d->screens; s; s = s->next)
+ updateDefaultIcon(s);
+
+ free(jd);
+}
+
+
+static Bool JPEGInit(CompPlugin *p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void JPEGFini(CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex(displayPrivateIndex);
+}
+
+CompPluginFeature JPEGFeatures[]={
+ {"imageext:jpeg"},
+ {"imageext:jpg"},
+ {"imagemime:image/jpeg"},
+};
+
+CompPluginVTable JPEGVTable = {
+ "jpeg",
+ N_("JPEG"),
+ N_("JPEG image format plugin"),
+ JPEGInit,
+ JPEGFini,
+ JPEGInitDisplay,
+ JPEGFiniDisplay,
+ 0,
+ 0,
+ 0,
+ 0,
+ JPEGGetDisplayOptions,
+ JPEGSetDisplayOption,
+ 0,
+ 0,
+ 0,
+ 0,
+ JPEGFeatures,
+ sizeof(JPEGFeatures)/sizeof(JPEGFeatures[0]),
+ BERYL_ABI_INFO,
+ "beryl-plugins",
+ "imageformat",
+ 0,
+ 0,
+};
+
+CompPluginVTable *getCompPluginInfo(void)
+{
+ return &JPEGVTable;
+}