/* * $Id: meta_image.c,v 1.5 2004/11/12 00:06:11 jasta Exp $ * * Modified from . Original * license follows: * * image_size - figure out the image size of GIF, JPEG, XBM, or PNG files * * Copyright (C)1997,1998 by Jef Poskanzer . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "giftd.h" #include "plugin/share.h" #include "meta.h" #include "meta_image.h" /*****************************************************************************/ /* Define a few JPEG markers. */ #define M_SOF0 0xc0 #define M_SOF3 0xc3 #define M_SOI 0xd8 #define M_EOI 0xd9 #define M_SOS 0xda /* Forwards. */ static BOOL image_size (FILE* f, int* widthP, int* heightP); static BOOL gif (FILE* f, int* widthP, int* heightP); static BOOL jpeg (FILE* f, int* widthP, int* heightP); static BOOL png (FILE* f, int* widthP, int* heightP); static BOOL get (FILE* f, unsigned char* chP); static BOOL mustbe (FILE* f, unsigned char ch); BOOL image_size (FILE* f, int* widthP, int* heightP) { unsigned char ch1, ch2; if (!get (f, &ch1)) return FALSE; if (!get (f, &ch2)) return FALSE; if (ch1 == 'G' && ch2 == 'I') return gif (f, widthP, heightP); else if (ch1 == 0xff && ch2 == M_SOI) return jpeg (f, widthP, heightP); else if (ch1 == 137 && ch2 == 80) return png (f, widthP, heightP); else return FALSE; } static BOOL gif (FILE* f, int* widthP, int* heightP) { unsigned char ch, w1, w2, h1, h2; /* Read rest of signature. */ if (!mustbe(f, 'F')) return FALSE; if (!mustbe(f, '8')) return FALSE; if (!get(f, &ch)) return FALSE; if (ch != '7' && ch != '9') return FALSE; if (!mustbe(f, 'a')) return FALSE; /* Width and height are the next things in the file. */ if (!get(f, &w1)) return FALSE; if (!get(f, &w2)) return FALSE; if (!get(f, &h1)) return FALSE; if (!get(f, &h2)) return FALSE; *widthP = (int) w2 * 256 + (int) w1; *heightP = (int) h2 * 256 + (int) h1; return TRUE; } static BOOL jpeg (FILE* f, int* widthP, int* heightP) { unsigned char ch, l1, l2, w1, w2, h1, h2; int l, i; /* JPEG blocks consist of a 0xff, a marker byte, a block size * (two bytes, big-endian), and the rest of the block. The * block size includes itself - i.e. is the block size was 2 then * there would be no additional bytes in the block. * * So, what we do here is read blocks until we get an SOF0-SOF3 marker, * and then extract the width and height from that. */ for (;;) { if (!mustbe(f, 0xff)) return FALSE; if (!get(f, &ch)) return FALSE; if (!get(f, &l1)) return FALSE; if (!get(f, &l2)) return FALSE; l = (int) l1 * 256 + (int) l2; /* Is it the block we're looking for? */ if (ch >= M_SOF0 && ch <= M_SOF3) { /* Toss the sample precision. */ if (!get(f, &ch)) return FALSE; /* Read the height and width. */ if (!get(f, &h1)) return FALSE; if (!get(f, &h2)) return FALSE; if (!get(f, &w1)) return FALSE; if (!get(f, &w2)) return FALSE; *widthP = (int) w1 * 256 + (int) w2; *heightP = (int) h1 * 256 + (int) h2; return TRUE; } if (ch == M_SOS || ch == M_EOI) return FALSE; /* Not the block we want. Read and toss. */ for (i = 2; i < l; ++i) if (!get(f, &ch)) return FALSE; } } static BOOL png (FILE* f, int* widthP, int* heightP) { unsigned char ch1, ch2, ch3, ch4, l1, l2, l3, l4, w1, w2, w3, w4, h1, h2, h3, h4; long l, i; /* Read rest of signature. */ if (!mustbe(f, 78)) return FALSE; if (!mustbe(f, 71)) return FALSE; if (!mustbe(f, 13)) return FALSE; if (!mustbe(f, 10)) return FALSE; if (!mustbe(f, 26)) return FALSE; if (!mustbe(f, 10)) return FALSE; /* PNG chunks consist of a length, a chunk type, chunk data, and * a CRC. We read chunks until we get an IHDR chunk, and then * extract the width and height from that. Actually, the IHDR chunk * is required to come first, but we might as well allow for * broken encoders that don't obey that. */ for (;;) { if (!get(f, &l1)) return FALSE; if (!get(f, &l2)) return FALSE; if (!get(f, &l3)) return FALSE; if (!get(f, &l4)) return FALSE; l = (long) l1 * 16777216 + (long) l2 * 65536 + (long) l3 * 256 + (long) l4; if (!get(f, &ch1)) return FALSE; if (!get(f, &ch2)) return FALSE; if (!get(f, &ch3)) return FALSE; if (!get(f, &ch4)) return FALSE; /* Is it the chunk we're looking for? */ if (ch1 == 'I' && ch2 == 'H' && ch3 == 'D' && ch4 == 'R') { /* Read the height and width. */ if (!get(f, &w1)) return FALSE; if (!get(f, &w2)) return FALSE; if (!get(f, &w3)) return FALSE; if (!get(f, &w4)) return FALSE; if (!get(f, &h1)) return FALSE; if (!get(f, &h2)) return FALSE; if (!get(f, &h3)) return FALSE; if (!get(f, &h4)) return FALSE; *widthP = (long) w1 * 16777216 + (long) w2 * 65536 + (long) w3 * 256 + (long) w4; *heightP = (long) h1 * 16777216 + (long) h2 * 65536 + (long) h3 * 256 + (long) h4; return TRUE; } /* Not the block we want. Read and toss. */ for (i = 0; i < l + 4; ++i) if (!get (f, &ch1)) return FALSE; } return FALSE; } static BOOL get (FILE* f, unsigned char* chP) { int ich = getc (f); if (ich == EOF) return FALSE; *chP = (unsigned char) ich; return TRUE; } static BOOL mustbe (FILE* f, unsigned char ch) { unsigned char ch2; if (!get (f, &ch2)) return FALSE; if (ch2 != ch) return FALSE; return TRUE; } /*****************************************************************************/ BOOL meta_image_run (Share *share, const char *path) { int width, height; BOOL ret; FILE *f = fopen (path, "rb"); if (!f) return FALSE; if ((ret = image_size (f, &width, &height))) { share_set_meta (share, "width", stringf ("%d", width)); share_set_meta (share, "height", stringf ("%d", height)); } fclose (f); return ret; }