diff --git a/.gitattributes b/.gitattributes index 98658eaf5d57faf691ccbf511a2e565ccf388c7e..afb85c0601711d5016c8412c0914d6fc605da4ac 100644 --- a/.gitattributes +++ b/.gitattributes @@ -166,6 +166,7 @@ testfont binary /lib/modules/Tools.pmod/X509.pmod foreign_ident /lib/modules/Web.pmod/Crawler.pmod foreign_ident /lib/modules/Yabu.pmod/module.pmod foreign_ident +/lib/modules/_Image.pmod/Dims.pmod foreign_ident /lib/modules/_Image.pmod/module.pmod foreign_ident /lib/modules/error.pmod foreign_ident /lib/modules/system.pmod foreign_ident diff --git a/lib/modules/_Image.pmod/Dims.pmod b/lib/modules/_Image.pmod/Dims.pmod new file mode 100644 index 0000000000000000000000000000000000000000..9447401a8d359a24cb47338fd64289acae1920c4 --- /dev/null +++ b/lib/modules/_Image.pmod/Dims.pmod @@ -0,0 +1,218 @@ +// $Id: Dims.pmod,v 1.1 2002/01/17 20:18:11 nilsson Exp $ +// +// Imagedimensionreadermodule for Pike. +// Created by Johan Sch�n, <js@roxen.com>. +// +// This software is based in part on the work of the Independent JPEG Group. + +//! @appears Image.Dims + +#define M_SOF0 0xC0 /* Start Of Frame N */ +#define M_SOF1 0xC1 /* N indicates which compression process */ +#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ +#define M_EOI 0xD9 /* End Of Image (end of datastream) */ +#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ +#define M_COM 0xFE /* COMment */ + +int(0..255) read_1_byte(Stdio.File f) +{ + return f->read(1)[0]; +} + +int(0..65535) read_2_bytes(Stdio.File f) +{ + int c; + sscanf( f->read(2), "%2c", c ); + return c; +} + +int(0..65535) read_2_bytes_intel(Stdio.File f) +{ + int c; + sscanf( f->read(2), "%-2c", c); + return c; +} + + +/* + * Read the initial marker, which should be SOI. + * For a JFIF file, the first two bytes of the file should be literally + * 0xFF M_SOI. To be more general, we could use next_marker, but if the + * input file weren't actually JPEG at all, next_marker might read the whole + * file and then return a misleading error message... + */ + +int first_marker(Stdio.File f) +{ + int c1, c2; + + c1 = read_1_byte(f); + c2 = read_1_byte(f); + if (c1!=0xFF||c2!=M_SOI) return 0; + return c2; +} + + +/* + * Find the next JPEG marker and return its marker code. + * We expect at least one FF byte, possibly more if the compressor used FFs + * to pad the file. + * There could also be non-FF garbage between markers. The treatment of such + * garbage is unspecified; we choose to skip over it but emit a warning msg. + * NB: this routine must not be used after seeing SOS marker, since it will + * not deal correctly with FF/00 sequences in the compressed image data... + */ + +int next_marker(Stdio.File f) +{ + int c; + int discarded_bytes = 0; + + /* Find 0xFF byte; count and skip any non-FFs. */ + c = read_1_byte(f); + while (c != 0xFF) { + discarded_bytes++; + c = read_1_byte(f); + } + /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs + * are legal as pad bytes, so don't count them in discarded_bytes. + */ + do { + c = read_1_byte(f); + } while (c == 0xFF); + return c; +} + +/* Skip over an unknown or uninteresting variable-length marker */ +int skip_variable(Stdio.File f) +{ + int length = read_2_bytes(f); + if (length < 2) return 0; /* Length includes itself, so must be at least 2 */ + length -= 2; + f->seek(f->tell()+length); + return 1; +} + + +array(int) get_JPEG(Stdio.File f) +{ + int marker; + /* Expect SOI at start of file */ + if (first_marker(f) != M_SOI) + return 0; + + /* Scan miscellaneous markers until we reach SOS. */ + for (;;) + { + marker = next_marker(f); + switch (marker) { + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + case M_SOF2: /* Progressive, Huffman */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_SOF9: /* Extended sequential, arithmetic */ + case M_SOF10: /* Progressive, arithmetic */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + int length = read_2_bytes(f); /* usual parameter length count */ + int data_precision = read_1_byte(f); + int image_height = read_2_bytes(f); + int image_width = read_2_bytes(f); + return ({ image_width,image_height }); + break; + + case M_SOS: /* stop before hitting compressed data */ + return 0; + + case M_EOI: /* in case it's a tables-only JPEG stream */ + return 0; + + default: /* Anything else just gets skipped */ + if(!skip_variable(f)) return 0; /* we assume it has a parameter count... */ + break; + } + } +} + +// GIF-header: +// typedef struct _GifHeader +// { +// // Header +// BYTE Signature[3]; /* Header Signature (always "GIF") */ +// BYTE Version[3]; /* GIF format version("87a" or "89a") */ +// // Logical Screen Descriptor +// WORD ScreenWidth; /* Width of Display Screen in Pixels */ +// WORD ScreenHeight; /* Height of Display Screen in Pixels */ +// BYTE Packed; /* Screen and Color Map Information */ +// BYTE BackgroundColor; /* Background Color Index */ +// BYTE AspectRatio; /* Pixel Aspect Ratio */ +// } GIFHEAD; + +array(int) get_GIF(Stdio.File f) +{ + int marker; + int offs=f->tell(); + if(f->read(3)!="GIF") return 0; + f->seek(offs+6); + int image_width = read_2_bytes_intel(f); + int image_height = read_2_bytes_intel(f); + return ({ image_width, image_height }); +} + +array(int) get_PNG(Stdio.File f) +{ + int marker; + int offs=f->tell(); + f->seek(offs+1); + if(f->read(3)!="PNG") return 0; + f->seek(offs+12); + if(f->read(4)!="IHDR") return 0; + read_2_bytes(f); + int image_width = read_2_bytes(f); + read_2_bytes_intel(f); + int image_height = read_2_bytes(f); + return ({ image_width, image_height }); +} + +//! Read dimensions from a JPEG, GIF or PNG file and return an array with +//! width and height, or if the file isn't a valid image, 0. +array(int) get(string|Stdio.File file) +{ + if(stringp(file)) + file=Stdio.File(file,"r"); + + if(!file->tell) + return 0; // Not a file object + + int offset=file->tell(); + array a; + + if(a=get_JPEG(file)) + return a; + + file->seek(offset); + if(a=get_GIF(file)) + return a; + + file->seek(offset); + if (a=get_PNG(file)) + return a; + + return 0; +}