metapixel-1.0.2/0000755000127400012740000000000010537045432013003 5ustar schanischanimetapixel-1.0.2/README0000644000127400012740000003463310537045432013674 0ustar schanischaniMetapixel 1.0.2 =============== Metapixel is a program for generating photomosaics. It can generate classical photomosaics, in which the source image is viewed as a matrix of equally sized rectangles for each of which a matching image is substitued, as well as collage-style photomosaics, in which rectangular parts of the source image at arbitrary positions (i.e. not aligned to a matrix) are substituted by matching images. Installation ------------ To compile Metapixel, you need, in addition to a C compiler, libpng, libjpeg, and giflib. To run the script for preparing constituent images, you will additionally need Perl. Most Linux distributions contain these software packages. On MacOS X, you can get them with Fink (http://fink.sourceforge.net/). Edit the first line of Makefile if you want to install Metapixel somewhere else than /usr/local. Then, type make If everything compiled fine, become root and type make install Configuring Metapixel --------------------- You can optionally create a file ".metapixelrc" in your home directory to store some settings which makes it easier to use Metapixel, since you won't have to use that many switches on the command line. A sample configuration file is included in the Metapixel distribution under the name "metapixelrc". See the section "The Configuration File" below for details. It is advisable to at least set the options "prepare-directory" and "library-directory". Preparing images ---------------- Before (non-anti-mosaic) mosaics can be created, the constituent images need to be preprocessed. Preparing an image does two things. Firstly, it computes various coefficients by which the image can be matched against a part of a source image. Secondly, the image is scaled to a smaller size. Usually this will be the size you intend to use for it in the target image, but it can be any arbitrary size. It makes sense to scale your images to the maximum size that you will use for constituent images. That way, no information gets lost. The default size is 128x128 pixels. The matching data and the scaled images are stored in a directory which is then called a "library". You can use more than one library in the creation of a mosaic. To simplify the task of creating a library, the Perl script 'metapixel-prepare' is included in the distribution. It must be called with the name of the directory where your original images are stored in. As a second argument you must give the directory of the library to which the images are to be added. If you have set a default directory for preparing images in your configuration file, the second argument is optional. If the script is called with the option "--recurse", it searches the directory with the original images recursively, i.e., it searches all its direct and indirect subdirectories as well. It also accepts parameters specifying the size of the scaled down images. Just call it - it prints out usage information. If the script constantly complains that an error occurred when running 'metapixel', that probably means that metapixel is not in your path. The other possibility is that all your images are in a format that Metapixel doesn't like (it only supports JPEG, PNG, and GIF). Creating photomosaics --------------------- Input images for mosaics can have arbitrary sizes. Should you want the created mosaic to be of a different size than the input image, use the --scale option. It scales the input image uniformly in both directions (i.e. obeying the aspect ratio). If the width or height of the input image after scaling are not multiples of the width and height of the constituent images, the input image is further scaled up to the smallest size (larger than the input image) that obeys this constraint, possibly changing the aspect ratio a bit. This does not apply to collages, however. The sizes of their source images after scaling are always left untouched. Metapixel produces output images in the PNG or JPEG formats, depending on the extension of the output file name. In order to create a classic photomosaic for the image input.jpg and write the output to output.png with constituent images stored in the directory "images", use the following command line: metapixel --library images --metapixel input.jpg output.png To create a collage use metapixel --library images --collage --metapixel input.jpg output.png Using the -y, -i and -q options you can change the weights for each of the color channels. For example, to match only luminance, completely disregarding chrominance, use metapixel --library images -i0 -q0 --metapixel input.jpg output.png The default weight for each of the channels is 1. Using the --cheat option you can specify the percentage by which the resulting photomosaic should be overlayed by the original image. The default is 0, i.e., the photomosaic is not overlayed at all. A percentage of 100 yields, not surprisingly, the original image. A percentage of 30 makes the photomosaic appear noticably better but is yet small enough to go unnoticed without close inspection in most circumstances. As of version 0.6, Metapixel implements two different matching algorithms. The new metric, which is a trivial distance function, seems to give better results while not being slower than the old wavelet metric. The metric can be chosen using the --metric option. The default is the new subpixel metric. You can use the --library option more than once to let Metapixel use more than one library for a mosaic. Classic Mosaics --------------- Metapixel allows you to choose between two algorithms for finding matching images, via the --search option. The old algorithm called "local" simply selects the best matching image for each location, possibly disregarding images selected in locations nearby (see below). The new algorithm called "global" repeats the following step until all locations have been assigned to: Find the best match for any location among all small images that have not already been used. This guarantees that no small image is used twice. Obviously, it also means that you must have at least as many small images as there are locations in the image. Note that "global" is much slower and uses more memory than "local". The "--distance" option lets you specify the minimal distance between two occurences of the same constituent image in the target image for the "local" algorithm. Distance 0 means that it is allowed for the same image to occur in adjacent positions in the matrix. The default distance is 5, which means that there must be at least 5 images "between" two occurences of the same image in the matrix. Note that Metapixel is forced to select non-optimal matches for distances greater 0. Antimosaics ----------- Antimosaics are classic mosaics for which the small images are the parts of a single image, possibly the input image itself, and can be created using the --antimosaic option. Metapixel subdivides the antimosaic file as if it were doing a mosaic of that file, but then uses the resulting subimages as the small images for a classic mosaic. In case the antimosaic image and the input image are the same, Metapixel will simply reconstruct the input image from the subimages, because they will always match best in their original locations. To tell Metapixel to do otherwise, you can use the --forbid-reconstruction option, which allows you to specify a minimum distance between the original location of a subimage and the location it has in the resulting mosaic. Here's how you create an antimosaic with a minimum reconstruction distance of 2: metapixel --library images -x input.jpg -f 2 --metapixel input.jpg output.png The Configuration File ---------------------- The first thing Metapixel does is try to read the file ".metapixelrc" in your home directory. From this file, it reads default values for its settings, so that you don't have to give them on the command line each time you use Metapixel. In this configuration file, you can use the following directives: (prepare-directory ) The library directory which metapixel-prepare should use by default. metapixel-prepare does not automatically create the directory if it doesn't exist, so make sure it does. (prepare-dimensions ) The size metapixel-prepare should use for the small images. (library-directory ) A library directory which Metapixel should use when creating mosaics. You can use this directive more than once. (small-image-dimensions ) The dimensions of the small images Metapixel should use in mosaics. (yiq-weights ) The weights for the channels to be used in matching images. (metric ) The metric Metapixel should use for matching images. This can either be "subpixel" or "wavelet". (search-method ) The search method for creating classic mosaics. This can either be "local" or "global". (minimum-classic-distance ) The minimum distance between two occurences of the same image in classic mosaics with the local search method. (minimum-collage-distance ) The minimum distance (in pixels) between two occurences of the same image in collage mosaics. (cheat-amount ) The cheat amount in percent. (forbid-reconstruction-distance ) The minimum distance between the position of subimage in the original image and its position in the output image in an antimosaic. Take a look at the file "metapixelrc" in the distribution. It gives examples for each of the directives discussed here. Collages -------- To create a collage, you have to use the "--collage" option in addition to "--metapixel". You can also specify a minimum distance between two occurences of the same image, which is measured in pixels. The default value is 256. Use the "--distance" option to change it. Note that the distance is measured between the centers of the images, not their edges, i.e., a minimum distance of 10 means that the centers of two occurences of the same image must be at least 10 pixels apart. This will usually mean that they are allowed to overlap, unless you use very tiny small images. Note that Metapixel uses ridiculous amounts of memory for collage mosaics. To create a collage photomosaics of size 2048x2048 your machine should at least have 64MBytes RAM. Protocols --------- Metapixel can, in addition to producing a classical mosaic, write a file specifying which small images it put in each of the locations. This protocol file can then be used to reproduce the mosaic without doing the matching again, for example to experiment with different cheat amounts. The protocol also contains information on how good each small image matches the original location, so you can find out where the matches are good and where they aren't. You can also modify the protocol and let metapixel generate a mosaic which it wouldn't have matched itself, for whatever reason you might want to do this. Use the --out option to create a protocol and the --in option to reproduce a mosaic from a protocol. The protocol file is a LISP list with the following syntax: (mosaic (size ) (metapixels . )) and are the number of small images in the mosaic across the width and height of the mosaic, respectively. is a list containing lists with the following syntax: ( ) and are the position of the small image. The upper left small image has coordinates (0,0), the lower right (-1,-1). and must both be 1 in this version of Metapixel. is the name of the small image file. A typical line in the protocol file looks like this: (30 23 1 1 "semiharmless.new/wallpaper07.jpg.png") ; 4792.000000 The number at the end of the line is the matching score. The lower the score, the better the match. Note that the semicolon ';' introduces a comment which lasts ends with the end of the line, so the matching score is not part of the protocol syntax. The matching algorithms ----------------------- The algorithm that does the image matching via wavelets is described in the paper 'Fast Multiresolution Image Querying' by Charles E. Jacobs, Adam Finkelstein and David H. Salesin. The new subpixel metric is very trivial. I suggest you consult the source if you are interested in it. The matching function is subpixel_compare(). Sorting Images by Size or Aspect Ratio -------------------------------------- Metapixel comes with a tool called `metapixel-sizesort' which sorts images by size or aspect ratio by moving them to directories containing only files with similar size or aspect ratio. An example: Let's say you have thousands of images in /my/images, and you want them sorted by aspect ratio and placed in /my/sorted/images. You can do this with this command: metapixel-sizesort --ratio=2 /my/images /my/sorted/images The option `2' to ratio tells metapixel-sizesort to put all those images together whose aspect ratios are the same with an accuracy of two places behind the comma. You might now have (among others) a directory called /my/sorted/images/ratio_0.79 which contains all images whose ratio between width and height is about 0.79. Upgrading from versions 0.8/0.9/0.10 ------------------------------------ Starting from release 0.11, Metapixel requires that the tables file is in the same directory as the small images described in that file. If your configuration is different, all you need to do is to make sure that all these files are in the same directory. You don't need to remove the paths in the tables file, as Metapixel does that automatically. Upgrading from versions 0.6/0.7 ------------------------------- The tables file format has changed in Metapixel 0.8, but you don't need to run 'metapixel-prepare' again. There's a program called 'convert' included in the distribution that does the job. Just tell it which size your small images are, give it the old tables file on stdin and it writes the new one on stdout. For example, if your small images are 128 pixels wide and 96 pixels high, go to the directory with the tables file (usually the directory where the small images are) and do convert --width=128 --height=96 tables.mxt Licence and Availability ------------------------ Metapixel is free software distributed under the terms of the GPL. The file `COPYING' contains the text of the license. The source of Metapixel is available at the Metapixel homepage at http://www.complang.tuwien.ac.at/schani/metapixel/ --- Mark Probst schani@complang.tuwien.ac.at metapixel-1.0.2/metapixel-sizesort0000755000127400012740000000635310537045432016610 0ustar schanischani#!/usr/bin/perl # sizesort --- sort images to directories according to size. # Copyright (C) 2003-2006 Mark Probst, 2005 Christoph Weiss-Schaber # Copyright (C) 2005 Christoph Weiss-Schaber # Authors: Mark Probst # Christoph Weiss-Schaber # Maintainer: Mark Probst # 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, 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, you can either send email to this # program's maintainer or write to: The Free Software Foundation, # Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA. use strict; use Getopt::Long; sub usage { print STDERR "Usage: $0 [OPTION]... Moves all images in to subdirectories of (which are created on the fly) bearing the name of the respective image's size or aspect ratio. -h, --help display this help and exit -d, --delete automatically deletes images which would normally be ignored because they are corrupted -s, --size sort by size -r, --ratio=ACCURACY sort by aspect ratio to ACCURACY decimal places -l, --symlink symlink instead of move "; exit(1); } my $delete_images; my $sort_size; my $sort_ratio; my $symlink; if (!GetOptions("help|h", \&usage, "delete|d", \$delete_images, "size|s", \$sort_size, "ratio|r=i", \$sort_ratio, "symlink|l", \$symlink)) { usage(); } if ($#ARGV != 1) { usage(); } if (!$sort_size && !$sort_ratio) { print STDERR "$0: you must specify a sorting criterion\n"; exit(1); } if ($sort_size && $sort_ratio) { print STDERR "$0: you can only specify one sorting criterion\n"; exit(1); } my ($srcdir, $destdir) = @ARGV; if (! -d $srcdir || ! -r $srcdir) { print "$0: directory $srcdir does not exist or is unreadable\n"; exit(1); } if (! -d $destdir ) { print "$0: directory $destdir does not exist\n"; exit(1); } foreach my $filename (glob("$srcdir/*")) { if (-f $filename && -r $filename) { my ($w, $h) = split /\s+/, `metapixel-imagesize "$filename" 2>/dev/null`; if ($? != 0 || $w==0 || $h==0) { if ($delete_images) { `rm "$filename"`; print "warning: metapixel-imagesize failed for for $filename - deleted\n"; } else { print "warning: metapixel-imagesize failed for for $filename - ignored\n"; } } else { my $dir; if ($sort_size) { $dir = sprintf "$destdir/size_%dx%d", $w, $h; print "$filename $w $h\n"; } else { my $ratio = sprintf "%.${sort_ratio}f", ($w / $h); print "$filename $w $h $ratio\n"; $dir = sprintf "$destdir/ratio_%s", $ratio; } `mkdir "$dir"` if (!-d $dir); if ($symlink) { `ln -s "$filename" "$dir/"`; } else { `mv "$filename" "$dir/"`; } } } } metapixel-1.0.2/pools.h0000644000127400012740000000243410537045432014313 0ustar schanischani/* * pools.h * * MathMap * * Copyright (C) 2002-2004 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __POOLS_H__ #define __POOLS_H__ #include /* these settings allow a pools to grow to up to 16 GB (last pool 8GB) */ #define GRANULARITY sizeof(long) #define FIRST_POOL_SIZE ((size_t)2048) #define NUM_POOLS 20 typedef struct { int active_pool; size_t fill_ptr; long *pools[NUM_POOLS]; } pools_t; void init_pools (pools_t *pools); void reset_pools (pools_t *pools); void free_pools (pools_t *pools); void* pools_alloc (pools_t *pools, size_t size); #endif metapixel-1.0.2/metapixel-prepare0000755000127400012740000000733610537045432016366 0ustar schanischani#!/usr/bin/perl # metapixel-prepare --- prepare images for metapixeling. # Copyright (C) 1999-2004 Mark Probst # Copyright (C) 2004 Jake Di Toro # Copyright (C) 2006 Stefan Soeffing # Maintainer: Mark Probst # 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, 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, you can either send email to this # program's maintainer or write to: The Free Software Foundation, # Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA. use strict; use Getopt::Long; use File::Basename; use IO::Handle; sub disambiguate_filename { my $filename = shift; my $suffix = shift; return "$filename$suffix" if !-e "$filename$suffix"; my $ctr = 1; while (-e "$filename.$ctr$suffix") { ++$ctr; } return "$filename.$ctr$suffix"; } sub usage { print STDERR "Usage: $0 [OPTION]... Prepares all images in for use as small images in photomosaics. The scaled versions and the table file are stored in . --help display this help and exit --width=WIDTH specify width of small images --height=HEIGHT specify height of small images -r, --recurse recurse through directories --debug print out debugging info "; exit(1); } my ($width, $height, $destdir) = split /\s+/, `metapixel --print-prepare-settings`; my $do_recurse; my $DEBUG; if (!GetOptions("help", \&usage, "width=i", \$width, "height=i", \$height, "recurse|r", \$do_recurse, "debug", \$DEBUG)) { usage(); } if (!$width || $width <= 0 || !$height || $height <= 0) { print "$0: Width and height of the prepared images must be specified.\n"; exit(1); } my $opts = "--width=$width --height=$height"; if ($#ARGV != 0 && $#ARGV != 1) { usage(); } my $srcdir = $ARGV[0]; $destdir = $ARGV[1] if $#ARGV > 0; if (! -d $srcdir || ! -r $srcdir) { print "$0: Source directory $srcdir does not exist or is unreadable.\n"; exit(1); } unless ($destdir) { print "$0: A destination directory must be specified.\n"; exit(1); } if (! -d $destdir) { print "$0: Destination directory $destdir does not exist.\n"; exit(1); } STDOUT->autoflush(1); sub process_dir { my $pdir = shift; my $do_recurse = shift; print "Processing dir: $pdir\n" if $DEBUG; if (opendir DIR, $pdir) { my @files = grep !/^\.\.?$/, readdir DIR; closedir DIR; foreach my $filename (@files) { my $fullname = "$pdir/$filename"; print "Testing file: $fullname\n" if $DEBUG; while (-l $fullname) { print "Following symlink: $fullname\n" if $DEBUG; $fullname = readlink($fullname); } if (-f $fullname && -r $fullname) { my ($name, $path, $suffix) = fileparse($fullname); print "Processing: $fullname\n" if $DEBUG; my $thumbname = disambiguate_filename("$destdir/$name$suffix", ".png"); `metapixel $opts --prepare "$fullname" "$thumbname" "$destdir/tables.mxt"`; if ($? != 0) { print "Error running metapixel - skipping file $fullname\n" } else { print "." if !$DEBUG; } } elsif (-d $fullname && -r $fullname && $do_recurse) { process_dir($fullname, $do_recurse); } } } else { print "Error: cannot open directory $pdir\n"; } } process_dir($srcdir, $do_recurse); metapixel-1.0.2/allocator.c0000644000127400012740000000322110537045432015125 0ustar schanischani/* * allocator.c * * lispreader * * Copyright (C) 2004 Mark Probst * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include static void* malloc_allocator_alloc (void *allocator_data, size_t size) { return malloc(size); } static void malloc_allocator_free (void *allocator_data, void *chunk) { free(chunk); } allocator_t malloc_allocator = { malloc_allocator_alloc, malloc_allocator_free, 0 }; static void pools_allocator_free (void *allocator_data, void *chunk) { } void init_pools_allocator (allocator_t *allocator, pools_t *pools) { allocator->alloc = (void* (*) (void*, size_t))pools_alloc; allocator->free = pools_allocator_free; allocator->allocator_data = pools; } char* allocator_strdup (allocator_t *allocator, const char *str) { size_t len = strlen(str) + 1; char *copy = (char*)allocator_alloc(allocator, len); if (copy != 0) memcpy(copy, str, len); return copy; } metapixel-1.0.2/zoom.c0000644000127400012740000002102410537045432014132 0ustar schanischani/* -*- c -*- */ /* * zoom.c * * metapixel * * Copyright (C) 2004 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include "zoom.h" #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #endif #define MAX_FILTER FILTER_MITCHELL typedef struct { int index; float weight; int iweight; } sample_t; typedef struct { int num_samples; sample_t samples[0]; } sample_window_t; static float filter_box (float x) { if (x < -0.5) return 0.0; if (x <= 0.5) return 1.0; return 0.0; } static float filter_triangle (float x) { if (x < -1.0) return 0.0; if (x < 0.0) return 1.0 + x; if (x < 1.0) return 1.0 - x; return 0.0; } /* * see Mitchell&Netravali, "Reconstruction Filters in Computer * Graphics", Proceedings of the 15th annual conference on Computer * graphics and interactive techniques, ACM Press 1988 */ static float filter_mitchell (float x) { #define B (1.0 / 3.0) #define C (1.0 / 3.0) static float a0 = ( 6.0 - 2.0 * B ) / 6.0; static float a2 = (-18.0 + 12.0 * B + 6.0 * C) / 6.0; static float a3 = ( 12.0 - 9.0 * B - 6.0 * C) / 6.0; static float b0 = ( 8.0 * B + 24.0 * C) / 6.0; static float b1 = ( - 12.0 * B - 48.0 * C) / 6.0; static float b2 = ( 6.0 * B + 30.0 * C) / 6.0; static float b3 = ( - B - 6.0 * C) / 6.0; x = fabsf(x); if (x < 1.0) return a0 + (x * x) * (a2 + x * a3); if (x < 2.0) return b0 + x * (b1 + x * (b2 + x * b3)); return 0.0; #undef b #undef c } static filter_t filters[] = { { &filter_box, 0.5 }, { &filter_triangle, 1.0 }, { &filter_mitchell, 2.0 } }; filter_t* get_filter (int index) { if (index < 0 || index > MAX_FILTER) return 0; return &filters[index]; } #define NUM_ACCURACY_BITS 12 static sample_window_t* make_sample_window (float center, float scale, float support_radius, filter_func_t filter_func, int num_indexes) { float lower_bound = center - support_radius; float upper_bound = center + support_radius; int lower_index = floor(lower_bound + 0.5); int upper_index = floor(upper_bound - 0.5); int num_samples; sample_window_t *window; int i; float weight_sum; lower_index = MAX(0, lower_index); upper_index = MIN(num_indexes - 1, upper_index); if (upper_index < lower_index) upper_index = lower_index = floor(center); num_samples = upper_index - lower_index + 1; assert(num_samples > 0); window = (sample_window_t*)malloc(sizeof(sample_window_t) + num_samples * sizeof(sample_t)); assert(window != 0); window->num_samples = num_samples; weight_sum = 0.0; for (i = 0; i < num_samples; ++i) { int index = lower_index + i; float sample_center = (float)index + 0.5; window->samples[i].index = index; window->samples[i].weight = filter_func((sample_center - center) / scale); weight_sum += window->samples[i].weight; } assert(weight_sum > 0.0); for (i = 0; i < num_samples; ++i) { window->samples[i].weight /= weight_sum; window->samples[i].iweight = (1 << NUM_ACCURACY_BITS) * window->samples[i].weight; } return window; } static sample_window_t** make_sample_windows (float filter_scale, float filter_support_radius, filter_func_t filter_func, int dest_size, int src_size, float scale) { sample_window_t **sample_windows; int i; sample_windows = (sample_window_t**)malloc(dest_size * sizeof(sample_window_t*)); assert(sample_windows != 0); for (i = 0; i < dest_size; ++i) { float dest_center = (float)i + 0.5; float src_center = dest_center / scale; sample_windows[i] = make_sample_window(src_center, filter_scale, filter_support_radius, filter_func, src_size); assert(sample_windows[i] != 0); } return sample_windows; } static void free_sample_windows (sample_window_t **sample_windows, int size) { int i; for (i = 0; i < size; ++i) free(sample_windows[i]); free(sample_windows); } static void zoom_unidirectional (unsigned char *dest, unsigned char *src, int num_channels, sample_window_t **sample_windows, int num_pixels_in_entity, int num_entities, int dest_pixel_advance, int src_pixel_advance, int dest_entity_advance, int src_entity_advance) { int i; unsigned char *dest_entity, *src_entity; int channels[num_channels]; dest_entity = dest; src_entity = src; for (i = 0; i < num_entities; ++i) { int j; unsigned char *dest_pixel; dest_pixel = dest_entity; for (j = 0; j < num_pixels_in_entity; ++j) { int k; for (k = 0; k < num_channels; ++k) channels[k] = 0; for (k = 0; k < sample_windows[j]->num_samples; ++k) { int l; sample_t *sample = &sample_windows[j]->samples[k]; unsigned char *src_pixel = &src_entity[sample->index * src_pixel_advance]; for (l = 0; l < num_channels; ++l) channels[l] += (int)src_pixel[l] * sample->iweight; /* ((((int)src_pixel[l]) << CHANNEL_SHIFT) + (1 << (CHANNEL_SHIFT - 1))) * sample->weight; */ } for (k = 0; k < num_channels; ++k) { int value = channels[k] >> NUM_ACCURACY_BITS; dest_pixel[k] = MAX(0, MIN(255, value)); } dest_pixel += dest_pixel_advance; } dest_entity += dest_entity_advance; src_entity += src_entity_advance; } } void zoom_image (unsigned char *dest, unsigned char *src, filter_t *filter, int num_channels, int dest_width, int dest_height, int dest_row_stride, int src_width, int src_height, int src_row_stride) { float x_scale, y_scale; float filter_x_scale, filter_y_scale; float filter_x_support_radius, filter_y_support_radius; sample_window_t **x_sample_windows, **y_sample_windows; unsigned char *temp_image; assert(dest != 0 && src != 0 && filter != 0); assert(dest_width > 0 && dest_height > 0); x_scale = (float)dest_width / (float)src_width; y_scale = (float)dest_height / (float)src_height; filter_x_scale = MAX(1.0, 1.0 / x_scale); filter_y_scale = MAX(1.0, 1.0 / y_scale); filter_x_support_radius = filter->support_radius * filter_x_scale; filter_y_support_radius = filter->support_radius * filter_y_scale; x_sample_windows = make_sample_windows(filter_x_scale, filter_x_support_radius, filter->func, dest_width, src_width, x_scale); y_sample_windows = make_sample_windows(filter_y_scale, filter_y_support_radius, filter->func, dest_height, src_height, y_scale); temp_image = (unsigned char*)malloc(num_channels * dest_width * src_height); zoom_unidirectional(temp_image, src, num_channels, x_sample_windows, dest_width, src_height, num_channels, num_channels, dest_row_stride, src_row_stride); zoom_unidirectional(dest, temp_image, num_channels, y_sample_windows, dest_height, dest_width, dest_row_stride, dest_row_stride, num_channels, num_channels); free(temp_image); free_sample_windows(x_sample_windows, dest_width); free_sample_windows(y_sample_windows, dest_height); } #ifdef TEST_ZOOM #include #include "readimage.h" #include "writeimage.h" int main (int argc, char *argv[]) { unsigned char *src, *dst; int src_width, src_height; int dst_width, dst_height; void *png_write_data; if (argc != 5) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } src = read_image(argv[1], &src_width, &src_height); assert(src != 0); dst_width = atoi(argv[2]); dst_height = atoi(argv[3]); dst = (unsigned char*)malloc(3 * dst_width * dst_height); zoom_image(dst, src, get_filter(FILTER_TRIANGLE), 3, dst_width, dst_height, dst_width * 3, src_width, src_height, src_width * 3); write_image(argv[4], dst_width, dst_height, dst, IMAGE_FORMAT_PNG); return 0; } #endif metapixel-1.0.2/COPYING0000644000127400012740000004321710537045432014045 0ustar schanischani GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. metapixel-1.0.2/pools.c0000644000127400012740000000440710537045432014310 0ustar schanischani/* * pools.c * * MathMap * * Copyright (C) 2002-2004 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include "pools.h" void init_pools (pools_t *pools) { int i; pools->active_pool = -1; pools->fill_ptr = 0; for (i = 0; i < NUM_POOLS; ++i) pools->pools[i] = 0; } void reset_pools (pools_t *pools) { pools->active_pool = -1; pools->fill_ptr = 0; } void free_pools (pools_t *pools) { int i; /* printf("alloced %d pools\n", active_pool + 1); */ for (i = 0; i < NUM_POOLS; ++i) if (pools->pools[i] != 0) free(pools->pools[i]); init_pools(pools); } void* pools_alloc (pools_t *pools, size_t size) { size_t pool_size; void *p; if (pools->active_pool < 0) { pools->active_pool = 0; if (pools->pools[0] == 0) pools->pools[0] = (long*)malloc(GRANULARITY * FIRST_POOL_SIZE); pools->fill_ptr = 0; memset(pools->pools[0], 0, GRANULARITY * FIRST_POOL_SIZE); } pool_size = FIRST_POOL_SIZE << pools->active_pool; size = (size + GRANULARITY - 1) / GRANULARITY; if (pools->fill_ptr + size >= pool_size) { ++pools->active_pool; assert(pools->active_pool < NUM_POOLS); if (pools->pools[pools->active_pool] == 0) pools->pools[pools->active_pool] = (long*)malloc(GRANULARITY * (FIRST_POOL_SIZE << pools->active_pool)); pools->fill_ptr = 0; memset(pools->pools[pools->active_pool], 0, GRANULARITY * (FIRST_POOL_SIZE << pools->active_pool)); } assert(pools->fill_ptr + size < pool_size); p = pools->pools[pools->active_pool] + pools->fill_ptr; pools->fill_ptr += size; return p; } metapixel-1.0.2/lispscan.h0000644000127400012740000000477210537045432015002 0ustar schanischanistatic int SCAN_FUNC_NAME (lisp_stream_t *stream) { static char *delims = "\"();"; SCAN_DECLS int c; do { c = NEXT_CHAR; if (c == EOF) RETURN(TOKEN_EOF); else if (c == ';') /* comment start */ while (1) { c = NEXT_CHAR; if (c == EOF) RETURN(TOKEN_EOF); else if (c == '\n') break; } } while (isspace(c)); switch (c) { case '(' : RETURN(TOKEN_OPEN_PAREN); case ')' : RETURN(TOKEN_CLOSE_PAREN); case '"' : _token_clear(); while (1) { c = NEXT_CHAR; if (c == EOF) RETURN(TOKEN_ERROR); if (c == '"') break; if (c == '\\') { c = NEXT_CHAR; switch (c) { case EOF : RETURN(TOKEN_ERROR); case 'n' : c = '\n'; break; case 't' : c = '\t'; break; } } _token_append(c); } RETURN(TOKEN_STRING); case '#' : c = NEXT_CHAR; if (c == EOF) RETURN(TOKEN_ERROR); switch (c) { case 't' : RETURN(TOKEN_TRUE); case 'f' : RETURN(TOKEN_FALSE); case '?' : c = NEXT_CHAR; if (c == EOF) RETURN(TOKEN_ERROR); if (c == '(') RETURN(TOKEN_PATTERN_OPEN_PAREN); else RETURN(TOKEN_ERROR); } RETURN(TOKEN_ERROR); default : if (isdigit(c) || c == '-') { int have_nondigits = 0; int have_digits = 0; int have_floating_point = 0; TOKEN_START(1); do { if (isdigit(c)) have_digits = 1; else if (c == '.') have_floating_point++; TOKEN_APPEND(c); c = NEXT_CHAR; if (c != EOF && !isdigit(c) && !isspace(c) && c != '.' && !strchr(delims, c)) have_nondigits = 1; } while (c != EOF && !isspace(c) && !strchr(delims, c)); if (c != EOF) UNGET_CHAR(c); TOKEN_STOP; if (have_nondigits || !have_digits || have_floating_point > 1) RETURN(TOKEN_SYMBOL); else if (have_floating_point == 1) RETURN(TOKEN_REAL); else RETURN(TOKEN_INTEGER); } else { if (c == '.') { c = NEXT_CHAR; if (c != EOF && !isspace(c) && !strchr(delims, c)) { TOKEN_START(2); TOKEN_APPEND('.'); } else { UNGET_CHAR(c); RETURN(TOKEN_DOT); } } else { TOKEN_START(1); } do { TOKEN_APPEND(c); c = NEXT_CHAR; } while (c != EOF && !isspace(c) && !strchr(delims, c)); if (c != EOF) UNGET_CHAR(c); TOKEN_STOP; RETURN(TOKEN_SYMBOL); } } assert(0); RETURN(TOKEN_ERROR); } metapixel-1.0.2/getopt1.c0000644000127400012740000001025710537045432014537 0ustar schanischani/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994 Free Software Foundation, Inc. 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, 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "getopt.h" #if !defined (__STDC__) || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #else char *getenv (); #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == EOF) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ metapixel-1.0.2/allocator.h0000644000127400012740000000257710537045432015147 0ustar schanischani/* * allocator.h * * lispreader * * Copyright (C) 2004 Mark Probst * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __ALLOCATOR_H__ #define __ALLOCATOR_H__ #include #include typedef struct { void* (*alloc) (void *allocator_data, size_t size); void (*free) (void *allocator_data, void *chunk); void *allocator_data; } allocator_t; extern allocator_t malloc_allocator; void init_pools_allocator (allocator_t *allocator, pools_t *pools); #define allocator_alloc(a,s) ((a)->alloc((a)->allocator_data, (s))) #define allocator_free(a,c) ((a)->free((a)->allocator_data, (c))) char* allocator_strdup (allocator_t *allocator, const char *str); #endif metapixel-1.0.2/metapixel.10000644000127400012740000000607510537045432015065 0ustar schanischani.\"Generated by db2man.xsl. Don't modify this, modify the source. .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "METAPIXEL" 1 "May 5, 2004" "" "" .SH NAME metapixel \- generator for photomosaics .SH "SYNOPSIS" .ad l .hy 0 .HP 18 \fBmetapixel\-prepare\fR [\fB\fIoptions\fR\fR] [\fIsrcdir\fR] [\fIdestdir\fR] .ad .hy prepares the pictures in \fIsrcdir\fR by creating resized images and a table file in \fIdestdir\fR .sp .ad l .hy 0 .HP 10 \fBmetapixel\fR [\fB\fIoptions\fR\fR] [\-\-metapixel\ \fIinput\&.jpg\fR\ \fIoutput\&.png\fR\ \-\-library\ \fIdestdir\fR] .ad .hy creates a photomosaic \fIoutput\&.png\fR using \fIinput\&.jpg\fR as the input image and \fIdestdir/tables\&.mxt\fR as table file .sp .SH "DESCRIPTION" .PP This manual page documents briefly the \fBmetapixel\fR and \fBmetapixel\-prepare\fR commands\&. For more information check the README file included in the distribution\&. .PP \fBmetapixel\fR is a program for generating photomosaics\&. It can generate classical photomosaics, in which the source image is viewed as a matrix of equally sized rectangles for each of which a matching image is substitued, as well as collage\-style photomosaics, in which rectangular parts of the source image at arbitrary positions (i\&.e\&. not aligned to a matrix) are substituted by matching images\&. .PP \fBmetapixel\-prepare\fR is a utility that needs to be run before metapixel can be used\&. It prepares your source images so that they can be used by \fBmetapixel\fR to create the actual photomosaic\&. .SH "USAGE" .PP \fBmetapixel\-prepare \fIsrcdir\fR \fIdestdir\fR\fR has to be run first\&. \fIsrcdir\fR is the path to the directory containing the source images, e\&.g\&. \fI~/Pictures/Holidays\fR\&. \fIdestdir\fR, e\&.g\&. \fI~/\&.metapixel\fR, is the path to the directory where you want to store the rescaled images and the \fItables\&.mxt\fR index file\&. This directory should be created manually before running \fBmetapixel\-prepare\fR\&. .PP \fBmetapixel \-\-metapixel \fIinput\&.jpg\fR \fIoutput\&.png\fR \-\-library \fIdestdir\fR\fR is then used to transform an image (\fIinput\&.jpg\fR) into a mosaic (\fIoutput\&.png\fR) using the source images (described by \fIdestdir/tables\&.mxt\fR)\&. .SH "OPTIONS" .PP The options are described in the README file or by running \fBmetapixel\fR or \fBmetapixel\-prepare\fR with the \-\-help option\&. .SH "SEE ALSO" .PP The README file is included in the Metapixel distribution\&. .SH "AUTHOR" .PP This manual page was written by Chris Vanden Berghe for the Debian system (but may be used by others)\&. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation\&. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL\&. .SH AUTHOR Chris Vanden Berghe. metapixel-1.0.2/metapixel.c0000644000127400012740000017774310537045432015162 0ustar schanischani/* * metapixel.c * * metapixel * * Copyright (C) 1997-2006 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include "getopt.h" #include "vector.h" #include "zoom.h" #include "readimage.h" #include "writeimage.h" #include "lispreader.h" #include "metapixel.h" #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #endif static int index_order[IMAGE_SIZE * IMAGE_SIZE]; static metapixel_t *first_pixel = 0; static int num_metapixels = 0; static float sqrt_of_two, sqrt_of_image_size; static float index_weights[NUM_INDEXES]; static index_t weight_ordered_index_to_index[NUM_INDEXES]; static index_t index_to_weight_ordered_index[NUM_INDEXES]; /* default settings */ static char *default_prepare_directory = 0; static int default_prepare_width = DEFAULT_PREPARE_WIDTH, default_prepare_height = DEFAULT_PREPARE_HEIGHT; static string_list_t *default_library_directories = 0; static int default_small_width = DEFAULT_WIDTH, default_small_height = DEFAULT_HEIGHT; static float default_weight_factors[NUM_CHANNELS] = { 1.0, 1.0, 1.0 }; static int default_metric = METRIC_SUBPIXEL; static int default_search = SEARCH_LOCAL; static int default_classic_min_distance = DEFAULT_CLASSIC_MIN_DISTANCE; static int default_collage_min_distance = DEFAULT_COLLAGE_MIN_DISTANCE; static int default_cheat_amount = 0; static int default_forbid_reconstruction_radius = 0; /* actual settings */ static int small_width, small_height; static float weight_factors[NUM_CHANNELS]; static int forbid_reconstruction_radius; static int benchmark_rendering = 0; static string_list_t* string_list_prepend_copy (string_list_t *lst, const char *str) { string_list_t *new = (string_list_t*)malloc(sizeof(string_list_t)); new->str = strdup(str); new->next = lst; return new; } static char* strip_path (char *name) { char *p = strrchr(name, '/'); if (p == 0) return name; return p + 1; } static metapixel_t* new_metapixel (void) { metapixel_t *pixel = (metapixel_t*)malloc(sizeof(metapixel_t)); assert(pixel != 0); memset(pixel, 0, sizeof(metapixel_t)); return pixel; } static unsigned char* scale_image (unsigned char *image, int image_width, int image_height, int x, int y, int width, int height, int new_width, int new_height) { unsigned char *new_image = (unsigned char*)malloc(new_width * new_height * NUM_CHANNELS); unsigned char *image_start = image + (x + y * image_width) * NUM_CHANNELS; zoom_image(new_image, image_start, get_filter(FILTER_MITCHELL), NUM_CHANNELS, new_width, new_height, new_width * NUM_CHANNELS, width, height, image_width * NUM_CHANNELS); return new_image; } void alpha_compose (unsigned char *dst, int width, int height, unsigned char *src, int perc) { int i; for (i = 0; i < width * height * NUM_CHANNELS; ++i) dst[i] = dst[i] * (100 - perc) / 100 + src[i] * perc / 100; } void generate_index_order (void) { int index = 0, begin = 0, row = 0, col = 0, first_half = 1; do { index_order[index++] = col + IMAGE_SIZE * row; if (first_half) { if (row == 0) { if (begin == IMAGE_SIZE - 1) { first_half = 0; col = begin = 1; row = IMAGE_SIZE - 1; } else { ++begin; row = begin; col = 0; } } else { ++col; --row; } } else { if (col == IMAGE_SIZE - 1) { ++begin; col = begin; row = IMAGE_SIZE - 1; } else { ++col; --row; } } } while (index < IMAGE_SIZE * IMAGE_SIZE); } static int compute_index (int real_index, int channel, int sign) { return real_index + (channel + (sign > 0 ? 1 : 0) * NUM_CHANNELS) * IMAGE_SIZE * IMAGE_SIZE; } static void uncompute_index (int index, int *real_index, int *channel, int *sign) { *real_index = index % (IMAGE_SIZE * IMAGE_SIZE); *channel = (index / (IMAGE_SIZE * IMAGE_SIZE)) % NUM_CHANNELS; *sign = (index / (NUM_CHANNELS * IMAGE_SIZE * IMAGE_SIZE)) ? 1 : -1; } void cut_last_coefficients (float *image, int channel, int howmany) { int i; for (i = IMAGE_SIZE * IMAGE_SIZE - howmany; i < IMAGE_SIZE * IMAGE_SIZE; ++i) image[index_order[i] * NUM_CHANNELS + channel] = 0.0; } void transform_rgb_to_yiq (float *image, int num_pixels) { const static Matrix3D conversion_matrix = { { 0.299, 0.587, 0.114 }, { 0.596, -0.275, -0.321 }, { 0.212, -0.528, 0.311 } }; int i; for (i = 0; i < num_pixels; ++i) { Vector3D rgb_vec, yiq_vec; InitVector3D(&rgb_vec, image[NUM_CHANNELS * i + 0], image[NUM_CHANNELS * i + 1], image[NUM_CHANNELS * i + 2]); MultMatrixVector3D(&yiq_vec, &conversion_matrix, &rgb_vec); image[NUM_CHANNELS * i + 0] = yiq_vec.x; image[NUM_CHANNELS * i + 1] = yiq_vec.y / 1.192 + 127.5; image[NUM_CHANNELS * i + 2] = yiq_vec.z / 1.051 + 128.106565176; } } void transform_yiq_to_rgb (float *image) { const static Matrix3D conversion_matrix = { { 1.00308929854, 0.954849063112, 0.61785970812 }, { 0.996776058337, -0.270706233074, -0.644788332692 }, { 1.00849783766, -1.1104851847, 1.69956753125 } }; int i; for (i = 0; i < IMAGE_SIZE * IMAGE_SIZE; ++i) { Vector3D rgb_vec, yiq_vec; InitVector3D(&yiq_vec, image[NUM_CHANNELS * i + 0], image[NUM_CHANNELS * i + 1] - 127.5, image[NUM_CHANNELS * i + 2] - 127.5); MultMatrixVector3D(&rgb_vec, &conversion_matrix, &yiq_vec); image[NUM_CHANNELS * i + 0] = rgb_vec.x; image[NUM_CHANNELS * i + 1] = rgb_vec.y; image[NUM_CHANNELS * i + 2] = rgb_vec.z; } } void transpose_image (float *old_image, float *new_image) { int i, j, channel; for (i = 0; i < IMAGE_SIZE; ++i) for (j = 0; j < IMAGE_SIZE; ++j) for (channel = 0; channel < NUM_CHANNELS; ++channel) new_image[channel + (i + j * IMAGE_SIZE) * NUM_CHANNELS] = old_image[channel + (j + i * IMAGE_SIZE) * NUM_CHANNELS]; } void decompose_row (float *row) { int h = IMAGE_SIZE, i; float new_row[NUM_CHANNELS * IMAGE_SIZE]; for (i = 0; i < NUM_CHANNELS * IMAGE_SIZE; ++i) row[i] = row[i] / sqrt_of_image_size; while (h > 1) { h = h / 2; for (i = 0; i < h; ++i) { int channel; for (channel = 0; channel < NUM_CHANNELS; ++channel) { float val1 = row[channel + 2 * i * NUM_CHANNELS], val2 = row[channel + (2 * i + 1) * NUM_CHANNELS]; new_row[channel + i * NUM_CHANNELS] = (val1 + val2) / sqrt_of_two; new_row[channel + (h + i) * NUM_CHANNELS] = (val1 - val2) / sqrt_of_two; } } memcpy(row, new_row, sizeof(float) * NUM_CHANNELS * h * 2); } } void decompose_column (float *column) { int h = IMAGE_SIZE, i, channel; float new_column[ROW_LENGTH]; for (i = 0; i < IMAGE_SIZE; ++i) for (channel = 0; channel < NUM_CHANNELS; ++channel) column[channel + i * ROW_LENGTH] = column[channel + i * ROW_LENGTH] / sqrt_of_image_size; while (h > 1) { h = h / 2; for (i = 0; i < h; ++i) { for (channel = 0; channel < NUM_CHANNELS; ++channel) { float val1 = column[channel + (2 * i) * ROW_LENGTH], val2 = column[channel + (2 * i + 1) * ROW_LENGTH]; new_column[channel + i * NUM_CHANNELS] = (val1 + val2) / sqrt_of_two; new_column[channel + (h + i) * NUM_CHANNELS] = (val1 - val2) / sqrt_of_two; } } for (i = 0; i < h * 2; ++i) for (channel = 0; channel < NUM_CHANNELS; ++channel) column[channel + i * ROW_LENGTH] = new_column[channel + i * NUM_CHANNELS]; } } void decompose_image (float *image) { int row; for (row = 0; row < IMAGE_SIZE; ++row) decompose_row(image + NUM_CHANNELS * IMAGE_SIZE * row); for (row = 0; row < IMAGE_SIZE; ++row) decompose_column(image + NUM_CHANNELS * row); } void compose_row (float *row) { int h = 1, i; float new_row[NUM_CHANNELS * IMAGE_SIZE]; memcpy(new_row, row, sizeof(float) * NUM_CHANNELS * IMAGE_SIZE); while (h < IMAGE_SIZE) { for (i = 0; i < h; ++i) { int channel; for (channel = 0; channel < NUM_CHANNELS; ++channel) { float val1 = row[channel + i * NUM_CHANNELS], val2 = row[channel + (h + i) * NUM_CHANNELS]; new_row[channel + 2 * i * NUM_CHANNELS] = (val1 + val2) / sqrt_of_two; new_row[channel + (2 * i + 1) * NUM_CHANNELS] = (val1 - val2) / sqrt_of_two; } } memcpy(row, new_row, sizeof(float) * NUM_CHANNELS * IMAGE_SIZE); h = h * 2; } for (i = 0; i < NUM_CHANNELS * IMAGE_SIZE; ++i) row[i] = row[i] * sqrt_of_image_size; } void compose_image (float *image) { int row; float *transposed_image = (float*)malloc(sizeof(float) * 3 * IMAGE_SIZE * IMAGE_SIZE); transpose_image(image, transposed_image); for (row = 0; row < IMAGE_SIZE; ++row) compose_row(transposed_image + NUM_CHANNELS * IMAGE_SIZE * row); transpose_image(transposed_image, image); for (row = 0; row < IMAGE_SIZE; ++row) compose_row(image + NUM_CHANNELS * IMAGE_SIZE * row); free(transposed_image); } int compare_coeffs_with_index (const void *p1, const void *p2) { const coefficient_with_index_t *coeff1 = (const coefficient_with_index_t*)p1; const coefficient_with_index_t *coeff2 = (const coefficient_with_index_t*)p2; if (fabs(coeff1->coeff) < fabs(coeff2->coeff)) return 1; else if (fabs(coeff1->coeff) == fabs(coeff2->coeff)) return 0; return -1; } void find_highest_coefficients (float *image, coefficient_with_index_t highest_coeffs[NUM_COEFFS]) { int index, channel; for (channel = 0; channel < NUM_CHANNELS; ++channel) { for (index = 1; index < SIGNIFICANT_COEFFS + 1; ++index) { float coeff = image[channel + NUM_CHANNELS * index]; int sign = coeff > 0.0 ? 1 : -1; highest_coeffs[index - 1 + channel * SIGNIFICANT_COEFFS].index = compute_index(index, channel, sign); highest_coeffs[index - 1 + channel * SIGNIFICANT_COEFFS].coeff = coeff; } qsort(highest_coeffs + channel * SIGNIFICANT_COEFFS, SIGNIFICANT_COEFFS, sizeof(coefficient_with_index_t), compare_coeffs_with_index); } for (index = SIGNIFICANT_COEFFS + 1; index < IMAGE_SIZE * IMAGE_SIZE; ++index) { for (channel = 0; channel < NUM_CHANNELS; ++channel) { float coeff = image[channel + NUM_CHANNELS * index]; if (fabs(coeff) > fabs(highest_coeffs[(channel + 1) * SIGNIFICANT_COEFFS - 1].coeff)) { int significance; int sign = coeff > 0.0 ? 1 : -1; for (significance = (channel + 1) * SIGNIFICANT_COEFFS - 2; significance >= channel * SIGNIFICANT_COEFFS; --significance) if (fabs(coeff) <= fabs(highest_coeffs[significance].coeff)) break; ++significance; memmove(highest_coeffs + significance + 1, highest_coeffs + significance, sizeof(coefficient_with_index_t) * ((channel + 1) * SIGNIFICANT_COEFFS - 1 - significance)); highest_coeffs[significance].index = compute_index(index, channel, sign); highest_coeffs[significance].coeff = coeff; } } } } static float weight_function (int index) { static float weight_table[NUM_CHANNELS][6] = { { 5.00, 0.83, 1.01, 0.52, 0.47, 0.30 }, { 19.21, 1.26, 0.44, 0.53, 0.28, 0.14 }, { 34, 0.36, 0.45, 0.14, 0.18, 0.27 } }; int real_index, channel, sign; int i, j, bin; uncompute_index(index, &real_index, &channel, &sign); i = real_index % IMAGE_SIZE; j = real_index / IMAGE_SIZE; bin = MIN(MAX(i, j), 5); return weight_table[channel][bin] * weight_factors[channel]; } static int compare_indexes_by_weight_descending (const void *p1, const void *p2) { const index_t *i1 = (const index_t*)p1, *i2 = (const index_t*)p2; if (index_weights[*i1] < index_weights[*i2]) return 1; else if (index_weights[*i1] == index_weights[*i2]) return 0; return -1; } static void compute_index_weights (void) { int i; for (i = 0; i < NUM_INDEXES; ++i) index_weights[i] = weight_function(i); for (i = 0; i < NUM_INDEXES; ++i) weight_ordered_index_to_index[i] = i; qsort(weight_ordered_index_to_index, NUM_INDEXES, sizeof(index_t), compare_indexes_by_weight_descending); for (i = 0; i < NUM_INDEXES; ++i) index_to_weight_ordered_index[weight_ordered_index_to_index[i]] = i; } static float wavelet_compare (coeffs_t *coeffs, metapixel_t *pixel, float best_score) { search_coefficients_t *query = &coeffs->wavelet.coeffs; float *query_means = coeffs->wavelet.means; float *sums = coeffs->wavelet.sums; search_coefficients_t *target = &pixel->coeffs; float *target_means = pixel->means; float score = 0.0; int i; int j; int channel; for (channel = 0; channel < NUM_CHANNELS; ++channel) score += index_weights[compute_index(0, channel, 0)] * fabs(query_means[channel] - target_means[channel]) * 0.05; j = 0; for (i = 0; i < NUM_COEFFS; ++i) { if (score - sums[i] > best_score) return FLT_MAX; while (target->coeffs[j] < query->coeffs[i] && j < NUM_COEFFS) ++j; if (j >= NUM_COEFFS) break; if (target->coeffs[j] > query->coeffs[i]) continue; score -= index_weights[weight_ordered_index_to_index[target->coeffs[j]]]; } return score; } static float subpixel_compare (coeffs_t *coeffs, metapixel_t *pixel, float best_score) { int channel; float score = 0.0; for (channel = 0; channel < NUM_CHANNELS; ++channel) { int i; for (i = 0; i < NUM_SUBPIXELS; ++i) { float dist = (int)coeffs->subpixel.subpixels[channel * NUM_SUBPIXELS + i] - (int)pixel->subpixels[channel * NUM_SUBPIXELS + i]; score += dist * dist * weight_factors[channel]; if (score >= best_score) return FLT_MAX; } } return score; } void add_metapixel (metapixel_t *pixel) { pixel->next = first_pixel; first_pixel = pixel; ++num_metapixels; } static int compare_indexes (const void *p1, const void *p2) { index_t *i1 = (index_t*)p1; index_t *i2 = (index_t*)p2; return *i1 - *i2; } void generate_search_coeffs (search_coefficients_t *search_coeffs, float sums[NUM_COEFFS], coefficient_with_index_t raw_coeffs[NUM_COEFFS]) { int i; float sum; for (i = 0; i < NUM_COEFFS; ++i) search_coeffs->coeffs[i] = index_to_weight_ordered_index[raw_coeffs[i].index]; qsort(search_coeffs->coeffs, NUM_COEFFS, sizeof(index_t), compare_indexes); sum = 0.0; for (i = NUM_COEFFS - 1; i >= 0; --i) { sum += index_weights[weight_ordered_index_to_index[search_coeffs->coeffs[i]]]; sums[i] = sum; } } void generate_search_coeffs_for_subimage (coeffs_t *coeffs, unsigned char *image_data, int image_width, int image_height, int x, int y, int width, int height, int metric) { static float *float_image = 0; if (metric == METRIC_WAVELET) { coefficient_with_index_t raw_coeffs[NUM_COEFFS]; int i; if (float_image == 0) float_image = (float*)malloc(sizeof(float) * IMAGE_SIZE * IMAGE_SIZE * NUM_CHANNELS); if (width != IMAGE_SIZE || height != IMAGE_SIZE) { unsigned char *scaled_data; scaled_data = scale_image(image_data, image_width, image_height, x, y, width, height, IMAGE_SIZE, IMAGE_SIZE); assert(scaled_data != 0); for (i = 0; i < IMAGE_SIZE * IMAGE_SIZE * NUM_CHANNELS; ++i) float_image[i] = scaled_data[i]; free(scaled_data); } else { int j, channel; for (j = 0; j < IMAGE_SIZE; ++j) for (i = 0; i < IMAGE_SIZE; ++i) for (channel = 0; channel < NUM_CHANNELS; ++channel) float_image[(j * IMAGE_SIZE + i) * NUM_CHANNELS + channel] = image_data[((y + j) * image_width + (x + i)) * NUM_CHANNELS + channel]; } transform_rgb_to_yiq(float_image, IMAGE_SIZE * IMAGE_SIZE); decompose_image(float_image); find_highest_coefficients(float_image, raw_coeffs); generate_search_coeffs(&coeffs->wavelet.coeffs, coeffs->wavelet.sums, raw_coeffs); for (i = 0; i < NUM_CHANNELS; ++i) coeffs->wavelet.means[i] = float_image[i]; } else if (metric == METRIC_SUBPIXEL) { unsigned char *scaled_data; int i; int channel; if (float_image == 0) float_image = (float*)malloc(sizeof(float) * NUM_SUBPIXELS * NUM_CHANNELS); scaled_data = scale_image(image_data, image_width, image_height, x, y, width, height, NUM_SUBPIXEL_ROWS_COLS, NUM_SUBPIXEL_ROWS_COLS); for (i = 0; i < NUM_SUBPIXELS * NUM_CHANNELS; ++i) float_image[i] = scaled_data[i]; free(scaled_data); transform_rgb_to_yiq(float_image, NUM_SUBPIXELS); for (channel = 0; channel < NUM_CHANNELS; ++channel) for (i = 0; i < NUM_SUBPIXELS; ++i) coeffs->subpixel.subpixels[channel * NUM_SUBPIXELS + i] = float_image[i * NUM_CHANNELS + channel]; } else assert(0); } static void generate_metapixel_coefficients (metapixel_t *pixel, unsigned char *image_data, coefficient_with_index_t raw_coeffs[NUM_COEFFS]) { static float float_image[NUM_CHANNELS * IMAGE_SIZE * IMAGE_SIZE]; static float sums[NUM_COEFFS]; unsigned char *scaled_data; int i, channel; /* generate wavelet coefficients */ if (small_width != IMAGE_SIZE || small_height != IMAGE_SIZE) { scaled_data = scale_image(image_data, small_width, small_height, 0, 0, small_width, small_height, IMAGE_SIZE, IMAGE_SIZE); assert(scaled_data != 0); } else scaled_data = image_data; for (i = 0; i < IMAGE_SIZE * IMAGE_SIZE * NUM_CHANNELS; ++i) float_image[i] = scaled_data[i]; if (scaled_data != image_data) free(scaled_data); transform_rgb_to_yiq(float_image, IMAGE_SIZE * IMAGE_SIZE); decompose_image(float_image); find_highest_coefficients(float_image, raw_coeffs); generate_search_coeffs(&pixel->coeffs, sums, raw_coeffs); for (i = 0; i < NUM_CHANNELS; ++i) pixel->means[i] = float_image[i]; /* generate subpixel coefficients */ if (small_width != NUM_SUBPIXEL_ROWS_COLS || small_height != NUM_SUBPIXEL_ROWS_COLS) { scaled_data = scale_image(image_data, small_width, small_height, 0, 0, small_width, small_height, NUM_SUBPIXEL_ROWS_COLS, NUM_SUBPIXEL_ROWS_COLS); assert(scaled_data != 0); } else scaled_data = image_data; assert(NUM_SUBPIXELS <= IMAGE_SIZE * IMAGE_SIZE); for (i = 0; i < NUM_SUBPIXELS * NUM_CHANNELS; ++i) float_image[i] = scaled_data[i]; transform_rgb_to_yiq(float_image, NUM_SUBPIXELS); for (channel = 0; channel < NUM_CHANNELS; ++channel) for (i = 0; i < NUM_SUBPIXELS; ++i) pixel->subpixels[channel * NUM_SUBPIXELS + i] = (int)float_image[i * NUM_CHANNELS + channel]; if (scaled_data != image_data) free(scaled_data); } static int metapixel_in_array (metapixel_t *pixel, metapixel_t **array, int size) { int i; for (i = 0; i < size; ++i) if (array[i] == pixel) return 1; return 0; } compare_func_t compare_func_for_metric (int metric) { if (metric == METRIC_WAVELET) return wavelet_compare; else if (metric == METRIC_SUBPIXEL) return subpixel_compare; else assert(0); return 0; } static int manhattan_distance (int x1, int y1, int x2, int y2) { return abs(x1 - x2) + abs(y1 - y2); } static match_t metapixel_nearest_to (coeffs_t *coeffs, int metric, int x, int y, metapixel_t **forbidden, int num_forbidden, int (*validity_func) (void*, metapixel_t*, int, int), void *validity_func_data) { float best_score = FLT_MAX; metapixel_t *best_fit = 0, *pixel; compare_func_t compare_func = compare_func_for_metric(metric); match_t match; for (pixel = first_pixel; pixel != 0; pixel = pixel->next) { float score; if (manhattan_distance(x, y, pixel->anti_x, pixel->anti_y) < forbid_reconstruction_radius) continue; score = compare_func(coeffs, pixel, best_score); if (score < best_score && !metapixel_in_array(pixel, forbidden, num_forbidden) && (validity_func == 0 || validity_func(validity_func_data, pixel, x, y))) { best_score = score; best_fit = pixel; } } match.pixel = best_fit; match.score = best_score; return match; } static void get_n_metapixel_nearest_to (int n, global_match_t *matches, coeffs_t *coeffs, int metric) { compare_func_t compare_func = compare_func_for_metric(metric); int i; metapixel_t *pixel; assert(num_metapixels >= n); i = 0; for (pixel = first_pixel; pixel != 0; pixel = pixel->next) { float score = compare_func(coeffs, pixel, (i < n) ? FLT_MAX : matches[n - 1].score); if (i < n || score < matches[n - 1].score) { int j, m; m = MIN(i, n); for (j = 0; j < m; ++j) if (matches[j].score > score) break; assert(j <= m && j < n); memmove(matches + j + 1, matches + j, sizeof(global_match_t) * (MIN(n, m + 1) - (j + 1))); matches[j].pixel = pixel; matches[j].score = score; } ++i; } assert(i >= n); } static void paste_metapixel (metapixel_t *pixel, unsigned char *data, int width, int height, int x, int y) { int i; int pixel_width, pixel_height; unsigned char *pixel_data; if (pixel->data != 0) { pixel_data = pixel->data; pixel_width = pixel->width; pixel_height = pixel->height; } else { pixel_data = read_image(pixel->filename, &pixel_width, &pixel_height); if (pixel_data == 0) { fprintf(stderr, "Error: cannot read metapixel file `%s'\n", pixel->filename); exit(1); } } if (pixel_width != small_width || pixel_height != small_height) { unsigned char *scaled_data = scale_image(pixel_data, pixel_width, pixel_height, 0, 0, pixel_width, pixel_height, small_width, small_height); if (pixel->data == 0) free(pixel_data); pixel_data = scaled_data; } for (i = 0; i < small_height; ++i) memcpy(data + NUM_CHANNELS * (x + (y + i) * width), pixel_data + NUM_CHANNELS * i * small_width, NUM_CHANNELS * small_width); if (pixel_data != pixel->data) free(pixel_data); } static classic_reader_t* init_classic_reader (char *input_name, float scale) { classic_reader_t *reader = (classic_reader_t*)malloc(sizeof(classic_reader_t)); assert(reader != 0); reader->image_reader = open_image_reading(input_name); if (reader->image_reader == 0) { fprintf(stderr, "cannot read image `%s'\n", input_name); exit(1); } reader->in_image_width = reader->image_reader->width; reader->in_image_height = reader->image_reader->height; reader->out_image_width = (((int)((float)reader->in_image_width * scale) - 1) / small_width + 1) * small_width; reader->out_image_height = (((int)((float)reader->in_image_height * scale) - 1) / small_height + 1) * small_height; assert(reader->out_image_width % small_width == 0); assert(reader->out_image_height % small_height == 0); reader->metawidth = reader->out_image_width / small_width; reader->metaheight = reader->out_image_height / small_height; reader->in_image_data = 0; reader->y = 0; return reader; } static void read_classic_row (classic_reader_t *reader) { if (reader->in_image_data != 0) { assert(reader->y > 0); free(reader->in_image_data); } else assert(reader->y == 0); reader->num_lines = (reader->y + 1) * reader->in_image_height / reader->metaheight - reader->y * reader->in_image_height / reader->metaheight; reader->in_image_data = (unsigned char*)malloc(reader->num_lines * reader->in_image_width * NUM_CHANNELS); assert(reader->in_image_data != 0); read_lines(reader->image_reader, reader->in_image_data, reader->num_lines); ++reader->y; } static void compute_classic_column_coords (classic_reader_t *reader, int x, int *left_x, int *width) { *left_x = x * reader->in_image_width / reader->metawidth; *width = (x + 1) * reader->in_image_width / reader->metawidth - *left_x; } static void generate_search_coeffs_for_classic_subimage (classic_reader_t *reader, int x, coeffs_t *coeffs, int metric) { int left_x, width; compute_classic_column_coords(reader, x, &left_x, &width); generate_search_coeffs_for_subimage(coeffs, reader->in_image_data, reader->in_image_width, reader->num_lines, left_x, 0, width, reader->num_lines, metric); } static void free_classic_reader (classic_reader_t *reader) { if (reader->in_image_data != 0) free(reader->in_image_data); free_image_reader(reader->image_reader); free(reader); } static mosaic_t* init_mosaic_from_reader (classic_reader_t *reader) { mosaic_t *mosaic = (mosaic_t*)malloc(sizeof(mosaic_t)); int metawidth = reader->metawidth, metaheight = reader->metaheight; int i; assert(mosaic != 0); mosaic->metawidth = metawidth; mosaic->metaheight = metaheight; mosaic->matches = (match_t*)malloc(sizeof(match_t) * metawidth * metaheight); for (i = 0; i < metawidth * metaheight; ++i) mosaic->matches[i].pixel = 0; return mosaic; } static mosaic_t* generate_local_classic (classic_reader_t *reader, int min_distance, int metric) { mosaic_t *mosaic = init_mosaic_from_reader(reader); int metawidth = reader->metawidth, metaheight = reader->metaheight; int x, y; metapixel_t **neighborhood = 0; int neighborhood_diameter = min_distance * 2 + 1; int neighborhood_size = (neighborhood_diameter * neighborhood_diameter - 1) / 2; if (min_distance > 0) neighborhood = (metapixel_t**)malloc(sizeof(metapixel_t*) * neighborhood_size); for (y = 0; y < metaheight; ++y) { read_classic_row(reader); for (x = 0; x < metawidth; ++x) { match_t match; int i; coeffs_t coeffs; for (i = 0; i < neighborhood_size; ++i) { int nx = x + i % neighborhood_diameter - min_distance; int ny = y + i / neighborhood_diameter - min_distance; if (nx < 0 || nx >= metawidth || ny < 0 || ny >= metaheight) neighborhood[i] = 0; else neighborhood[i] = mosaic->matches[ny * metawidth + nx].pixel; } generate_search_coeffs_for_classic_subimage(reader, x, &coeffs, metric); match = metapixel_nearest_to(&coeffs, metric, x, y, neighborhood, neighborhood_size, 0, 0); if (match.pixel == 0) { fprintf(stderr, "Error: cannot find a matching image - try using a shorter minimum distance.\n"); exit(1); } mosaic->matches[y * metawidth + x] = match; printf("."); fflush(stdout); } } free(neighborhood); printf("\n"); return mosaic; } static int compare_global_matches (const void *_m1, const void *_m2) { global_match_t *m1 = (global_match_t*)_m1; global_match_t *m2 = (global_match_t*)_m2; if (m1->score < m2->score) return -1; if (m1->score > m2->score) return 1; return 0; } static mosaic_t* generate_global_classic (classic_reader_t *reader, int metric) { mosaic_t *mosaic = init_mosaic_from_reader(reader); int metawidth = reader->metawidth, metaheight = reader->metaheight; int x, y; global_match_t *matches, *m; /* FIXME: this will overflow if metawidth and/or metaheight are large! */ int num_matches = (metawidth * metaheight) * (metawidth * metaheight); int i, ignore_forbidden; int num_locations_filled; metapixel_t *pixel; if (num_metapixels < metawidth * metaheight) { fprintf(stderr, "global search method needs at least as much\n" "metapixels as there are locations\n"); exit(1); } matches = (global_match_t*)malloc(sizeof(global_match_t) * num_matches); assert(matches != 0); m = matches; for (y = 0; y < metaheight; ++y) { read_classic_row(reader); for (x = 0; x < metawidth; ++x) { coeffs_t coeffs; generate_search_coeffs_for_classic_subimage(reader, x, &coeffs, metric); get_n_metapixel_nearest_to(metawidth * metaheight, m, &coeffs, metric); for (i = 0; i < metawidth * metaheight; ++i) { int j; for (j = i + 1; j < metawidth * metaheight; ++j) assert(m[i].pixel != m[j].pixel); m[i].x = x; m[i].y = y; } m += metawidth * metaheight; printf("."); fflush(stdout); } } qsort(matches, num_matches, sizeof(global_match_t), compare_global_matches); for (pixel = first_pixel; pixel != 0; pixel = pixel->next) pixel->flag = 0; num_locations_filled = 0; for (ignore_forbidden = 0; ignore_forbidden < 2; ++ignore_forbidden) { for (i = 0; i < num_matches; ++i) { int index = matches[i].y * metawidth + matches[i].x; if (!ignore_forbidden && manhattan_distance(matches[i].x, matches[i].y, matches[i].pixel->anti_x, matches[i].pixel->anti_y) < forbid_reconstruction_radius) continue; if (matches[i].pixel->flag) continue; if (num_locations_filled >= metawidth * metaheight) break; if (mosaic->matches[index].pixel == 0) { if (forbid_reconstruction_radius > 0 && ignore_forbidden) { printf("!"); fflush(stdout); } mosaic->matches[index].pixel = matches[i].pixel; mosaic->matches[index].score = matches[i].score; matches[i].pixel->flag = 1; ++num_locations_filled; } } if (forbid_reconstruction_radius == 0) break; } assert(num_locations_filled == metawidth * metaheight); free(matches); printf("\n"); return mosaic; } static void print_current_time (void) { struct timeval tv; gettimeofday(&tv, 0); printf("time: %lu %lu\n", (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec); } static void paste_classic (mosaic_t *mosaic, char *input_name, char *output_name, int cheat) { image_reader_t *reader; image_writer_t *writer = 0; int out_image_width, out_image_height; int x, y; unsigned char *out_image_data; int in_image_width, in_image_height; int metawidth = mosaic->metawidth, metaheight = mosaic->metaheight; if (cheat > 0) { reader = open_image_reading(input_name); if (reader == 0) { fprintf(stderr, "cannot read image `%s'\n", input_name); exit(1); } in_image_width = reader->width; in_image_height = reader->height; } else { reader = 0; in_image_width = in_image_height = 0; } out_image_width = mosaic->metawidth * small_width; out_image_height = mosaic->metaheight * small_height; if (!benchmark_rendering) { writer = open_image_writing(output_name, out_image_width, out_image_height, 3, out_image_width * 3, IMAGE_FORMAT_AUTO); if (writer == 0) { fprintf(stderr, "Error: cannot write image `%s'\n", output_name); exit(1); } } out_image_data = (unsigned char*)malloc(out_image_width * small_height * NUM_CHANNELS); if (benchmark_rendering) print_current_time(); for (y = 0; y < metaheight; ++y) { for (x = 0; x < metawidth; ++x) { if (benchmark_rendering) assert(mosaic->matches[y * metawidth + x].pixel->data != 0); paste_metapixel(mosaic->matches[y * metawidth + x].pixel, out_image_data, out_image_width, small_height, x * small_width, 0); if (!benchmark_rendering) { printf("X"); fflush(stdout); } } if (cheat > 0) { int num_lines = (y + 1) * in_image_height / metaheight - y * in_image_height / metaheight; unsigned char *in_image_data = (unsigned char*)malloc(num_lines * in_image_width * NUM_CHANNELS); unsigned char *source_data; assert(in_image_data != 0); read_lines(reader, in_image_data, num_lines); if (in_image_width != out_image_width || num_lines != small_height) source_data = scale_image(in_image_data, in_image_width, num_lines, 0, 0, in_image_width, num_lines, out_image_width, small_height); else source_data = in_image_data; alpha_compose(out_image_data, out_image_width, small_height, source_data, cheat); if (source_data != in_image_data) free(source_data); free(in_image_data); } if (!benchmark_rendering) write_lines(writer, out_image_data, small_height); } if (benchmark_rendering) print_current_time(); free(out_image_data); if (!benchmark_rendering) free_image_writer(writer); if (cheat > 0) free_image_reader(reader); printf("\n"); } static void pixel_add_collage_position (metapixel_t *pixel, int x, int y) { position_t *position = (position_t*)malloc(sizeof(position_t)); assert(position != 0); position->x = x; position->y = y; position->next = pixel->collage_positions; pixel->collage_positions = position; } static int pixel_valid_for_collage_position (void *data, metapixel_t *pixel, int x, int y) { int min_distance = (int)(unsigned long)data; position_t *position; if (min_distance <= 0) return 1; for (position = pixel->collage_positions; position != 0; position = position->next) if (manhattan_distance(x, y, position->x, position->y) < min_distance) return 0; return 1; } static void generate_collage (char *input_name, char *output_name, float scale, int min_distance, int metric, int cheat) { unsigned char *in_image_data, *out_image_data; int in_image_width, in_image_height; char *bitmap; int num_pixels_done = 0; in_image_data = read_image(input_name, &in_image_width, &in_image_height); if (in_image_data == 0) { fprintf(stderr, "could not read image `%s'\n", input_name); exit(1); } if (scale != 1.0) { int new_width = (float)in_image_width * scale; int new_height = (float)in_image_height * scale; unsigned char *scaled_data; if (new_width < small_width || new_height < small_height) { fprintf(stderr, "source image or scaling factor too small\n"); exit(1); } printf("scaling source image to %dx%d\n", new_width, new_height); scaled_data = scale_image(in_image_data, in_image_width, in_image_height, 0, 0, in_image_width, in_image_height, new_width, new_height); in_image_width = new_width; in_image_height = new_height; free(in_image_data); in_image_data = scaled_data; } out_image_data = (unsigned char*)malloc(in_image_width * in_image_height * NUM_CHANNELS); bitmap = (char*)malloc(in_image_width * in_image_height); memset(bitmap, 0, in_image_width * in_image_height); while (num_pixels_done < in_image_width * in_image_height) { int i, j; int x, y; coeffs_t coeffs; match_t match; while (1) { x = random() % in_image_width - small_width / 2; y = random() % in_image_height - small_height / 2; if (x < 0) x = 0; if (x + small_width > in_image_width) x = in_image_width - small_width; if (y < 0) y = 0; if (y + small_height > in_image_height) y = in_image_height - small_height; for (j = 0; j < small_height; ++j) for (i = 0; i < small_width; ++i) if (!bitmap[(y + j) * in_image_width + x + i]) goto out; } out: generate_search_coeffs_for_subimage(&coeffs, in_image_data, in_image_width, in_image_height, x, y, small_width, small_height, metric); match = metapixel_nearest_to(&coeffs, metric, x, y, 0, 0, pixel_valid_for_collage_position, (void*)(unsigned long)min_distance); if (match.pixel == 0) { fprintf(stderr, "Error: cannot find a matching image - try using a shorter minimum distance.\n"); exit(1); } paste_metapixel(match.pixel, out_image_data, in_image_width, in_image_height, x, y); if (min_distance > 0) pixel_add_collage_position(match.pixel, x, y); for (j = 0; j < small_height; ++j) for (i = 0; i < small_width; ++i) if (!bitmap[(y + j) * in_image_width + x + i]) { bitmap[(y + j) * in_image_width + x + i] = 1; ++num_pixels_done; } printf("."); fflush(stdout); } write_image(output_name, in_image_width, in_image_height, out_image_data, 3, in_image_width * 3, IMAGE_FORMAT_PNG); free(bitmap); free(out_image_data); free(in_image_data); } static int read_tables (const char *library_dir) { lisp_object_t *pattern; lisp_object_t *obj; lisp_stream_t stream; int num_subs; pools_t pools; allocator_t allocator; int dir_strlen = strlen(library_dir); char tables_name[dir_strlen + 1 + strlen(TABLES_FILENAME) + 1]; strcpy(tables_name, library_dir); strcat(tables_name, "/"); strcat(tables_name, TABLES_FILENAME); if (lisp_stream_init_path(&stream, tables_name) == 0) return 0; pattern = lisp_read_from_string("(small-image #?(string) (size #?(integer) #?(integer))" " (wavelet (means #?(real) #?(real) #?(real)) (coeffs . #?(list)))" " (subpixel (y . #?(list)) (i . #?(list)) (q . #?(list))))"); assert(pattern != 0 && lisp_type(pattern) != LISP_TYPE_EOF && lisp_type(pattern) != LISP_TYPE_PARSE_ERROR); assert(lisp_compile_pattern(&pattern, &num_subs)); assert(num_subs == 10); init_pools(&pools); init_pools_allocator(&allocator, &pools); for (;;) { int type; reset_pools(&pools); obj = lisp_read_with_allocator(&allocator, &stream); type = lisp_type(obj); if (type != LISP_TYPE_EOF && type != LISP_TYPE_PARSE_ERROR) { lisp_object_t *vars[10]; if (lisp_match_pattern(pattern, obj, vars, num_subs)) { metapixel_t *pixel = new_metapixel(); coefficient_with_index_t coeffs[NUM_COEFFS]; lisp_object_t *lst; int channel, i; char *filename = strip_path(lisp_string(vars[0])); pixel->filename = (char*)malloc(dir_strlen + 1 + strlen(filename) + 1); strcpy(pixel->filename, library_dir); strcat(pixel->filename, "/"); strcat(pixel->filename, filename); for (channel = 0; channel < NUM_CHANNELS; ++channel) pixel->means[channel] = lisp_real(vars[3 + channel]); if (lisp_list_length(vars[6]) != NUM_COEFFS) fprintf(stderr, "wrong number of wavelet coefficients in `%s'\n", pixel->filename); else { static float sums[NUM_COEFFS]; lst = vars[6]; for (i = 0; i < NUM_COEFFS; ++i) { coeffs[i].index = lisp_integer(lisp_car(lst)); lst = lisp_cdr(lst); } generate_search_coeffs(&pixel->coeffs, sums, coeffs); } for (channel = 0; channel < NUM_CHANNELS; ++channel) { lst = vars[7 + channel]; if (lisp_list_length(lst) != NUM_SUBPIXELS) fprintf(stderr, "wrong number of subpixels in `%s'\n", pixel->filename); else for (i = 0; i < NUM_SUBPIXELS; ++i) { pixel->subpixels[channel * NUM_SUBPIXELS + i] = lisp_integer(lisp_car(lst)); lst = lisp_cdr(lst); } } pixel->data = 0; pixel->collage_positions = 0; add_metapixel(pixel); } else { fprintf(stderr, "unknown expression "); lisp_dump(obj, stderr); fprintf(stderr, "\n"); } } else if (type == LISP_TYPE_PARSE_ERROR) fprintf(stderr, "Error: parse error in tables file.\n"); if (type == LISP_TYPE_EOF) break; } lisp_stream_free_path(&stream); free_pools(&pools); return 1; } static metapixel_t* find_metapixel (char *filename) { metapixel_t *pixel; for (pixel = first_pixel; pixel != 0; pixel = pixel->next) if (strcmp(pixel->filename, filename) == 0) return pixel; return 0; } static mosaic_t* read_protocol (FILE *in) { lisp_object_t *obj; lisp_stream_t stream; mosaic_t *mosaic = (mosaic_t*)malloc(sizeof(mosaic_t)); int type; lisp_stream_init_file(&stream, in); obj = lisp_read(&stream); type = lisp_type(obj); if (type != LISP_TYPE_EOF && type != LISP_TYPE_PARSE_ERROR) { lisp_object_t *vars[3]; if (lisp_match_string("(mosaic (size #?(integer) #?(integer)) (metapixels . #?(list)))", obj, vars)) { int i; int num_pixels; lisp_object_t *lst; mosaic->metawidth = lisp_integer(vars[0]); mosaic->metaheight = lisp_integer(vars[1]); num_pixels = mosaic->metawidth * mosaic->metaheight; mosaic->matches = (match_t*)malloc(sizeof(match_t) * num_pixels); for (i = 0; i < num_pixels; ++i) mosaic->matches[i].pixel = 0; if (lisp_list_length(vars[2]) != num_pixels) { fprintf(stderr, "mosaic should have %d metapixels, not %d\n", num_pixels, lisp_list_length(vars[2])); exit(1); } lst = vars[2]; for (i = 0; i < num_pixels; ++i) { lisp_object_t *vars[5]; if (lisp_match_string("(#?(integer) #?(integer) #?(integer) #?(integer) #?(string))", lisp_car(lst), vars)) { int x = lisp_integer(vars[0]); int y = lisp_integer(vars[1]); int width = lisp_integer(vars[2]); int height = lisp_integer(vars[3]); metapixel_t *pixel; if (width != 1 || height != 1) { fprintf(stderr, "width and height in metapixel must both be 1\n"); exit(1); } if (mosaic->matches[y * mosaic->metawidth + x].pixel != 0) { fprintf(stderr, "location (%d,%d) is assigned to twice\n", x, y); exit(1); } pixel = find_metapixel(lisp_string(vars[4])); if (pixel == 0) { fprintf(stderr, "could not find metapixel `%s'\n", lisp_string(vars[4])); exit(1); } mosaic->matches[y * mosaic->metawidth + x].pixel = pixel; } else { fprintf(stderr, "metapixel "); lisp_dump(lisp_car(lst), stderr); fprintf(stderr, " has wrong format\n"); exit(1); } lst = lisp_cdr(lst); } } else { fprintf(stderr, "malformed expression in protocol file\n"); exit(1); } } else { fprintf(stderr, "error in protocol file\n"); exit(1); } lisp_free(obj); return mosaic; } void free_mosaic (mosaic_t *mosaic) { free(mosaic->matches); free(mosaic); } int make_classic_mosaic (char *in_image_name, char *out_image_name, int metric, float scale, int search, int min_distance, int cheat, char *in_protocol_name, char *out_protocol_name) { mosaic_t *mosaic; int x, y; if (in_protocol_name != 0) { FILE *protocol_in = fopen(in_protocol_name, "rb"); if (protocol_in == 0) { fprintf(stderr, "cannot open protocol file for reading `%s': %s\n", in_protocol_name, strerror(errno)); return 0; } mosaic = read_protocol(protocol_in); fclose(protocol_in); } else { classic_reader_t *reader = init_classic_reader(in_image_name, scale); if (search == SEARCH_LOCAL) mosaic = generate_local_classic(reader, min_distance, metric); else if (search == SEARCH_GLOBAL) mosaic = generate_global_classic(reader, metric); else assert(0); free_classic_reader(reader); } assert(mosaic != 0); if (benchmark_rendering) { int i; for (i = 0; i < mosaic->metawidth * mosaic->metaheight; ++i) { metapixel_t *pixel = mosaic->matches[i].pixel; if (pixel->data == 0) { pixel->data = read_image(pixel->filename, &pixel->width, &pixel->height); assert(pixel->data != 0); } } } if (out_protocol_name != 0) { FILE *protocol_out = fopen(out_protocol_name, "wb"); if (protocol_out == 0) { fprintf(stderr, "cannot open protocol file `%s' for writing: %s\n", out_protocol_name, strerror(errno)); /* FIXME: free stuff */ return 0; } else { fprintf(protocol_out, "(mosaic (size %d %d)\n(metapixels\n", mosaic->metawidth, mosaic->metaheight); for (y = 0; y < mosaic->metaheight; ++y) { for (x = 0; x < mosaic->metawidth; ++x) { match_t *match = &mosaic->matches[y * mosaic->metawidth + x]; lisp_object_t *obj = lisp_make_string(match->pixel->filename); fprintf(protocol_out, "(%d %d 1 1 ", x, y); lisp_dump(obj, protocol_out); fprintf(protocol_out, ") ; %f\n", match->score); lisp_free(obj); } } fprintf(protocol_out, "))\n"); } fclose(protocol_out); } paste_classic(mosaic, in_image_name, out_image_name, cheat); free_mosaic(mosaic); return 1; } #define RC_FILE_NAME ".metapixelrc" static void read_rc_file (void) { lisp_stream_t stream; char *homedir; char *filename; homedir = getenv("HOME"); if (homedir == 0) { fprintf(stderr, "Warning: HOME is not in environment - cannot find rc file.\n"); return; } filename = (char*)malloc(strlen(homedir) + 1 + strlen(RC_FILE_NAME) + 1); strcpy(filename, homedir); strcat(filename, "/"); strcat(filename, RC_FILE_NAME); if (access(filename, R_OK) == 0) { if (lisp_stream_init_path(&stream, filename) == 0) fprintf(stderr, "Warning: could not open rc file `%s'.", filename); else { for (;;) { lisp_object_t *obj; int type; obj = lisp_read(&stream); type = lisp_type(obj); if (type != LISP_TYPE_EOF && type != LISP_TYPE_PARSE_ERROR) { lisp_object_t *vars[3]; if (lisp_match_string("(prepare-directory #?(string))", obj, vars)) default_prepare_directory = strdup(lisp_string(vars[0])); else if (lisp_match_string("(prepare-dimensions #?(integer) #?(integer))", obj, vars)) { default_prepare_width = lisp_integer(vars[0]); default_prepare_height = lisp_integer(vars[1]); } else if (lisp_match_string("(library-directory #?(string))", obj, vars)) default_library_directories = string_list_prepend_copy(default_library_directories, lisp_string(vars[0])); else if (lisp_match_string("(small-image-dimensions #?(integer) #?(integer))", obj, vars)) { default_small_width = lisp_integer(vars[0]); default_small_height = lisp_integer(vars[1]); } else if (lisp_match_string("(yiq-weights #?(number) #?(number) #?(number))", obj, vars)) { int i; for (i = 0; i < 3; ++i) default_weight_factors[i] = lisp_real(vars[i]); } else if (lisp_match_string("(metric #?(or wavelet subpixel))", obj, vars)) { if (strcmp(lisp_symbol(vars[0]), "wavelet") == 0) default_metric = METRIC_WAVELET; else default_metric = METRIC_SUBPIXEL; } else if (lisp_match_string("(search-method #?(or local global))", obj, vars)) { if (strcmp(lisp_symbol(vars[0]), "local") == 0) default_search = SEARCH_LOCAL; else default_search = SEARCH_GLOBAL; } else if (lisp_match_string("(minimum-classic-distance #?(integer))", obj, vars)) default_classic_min_distance = lisp_integer(vars[0]); else if (lisp_match_string("(minimum-collage-distance #?(integer))", obj, vars)) default_collage_min_distance = lisp_integer(vars[0]); else if (lisp_match_string("(cheat-amount #?(integer))", obj, vars)) default_cheat_amount = lisp_integer(vars[0]); else if (lisp_match_string("(forbid-reconstruction-distance #?(integer))", obj, vars)) default_forbid_reconstruction_radius = lisp_integer(vars[0]); else { fprintf(stderr, "Warning: unknown rc file option "); lisp_dump(obj, stderr); fprintf(stderr, "\n"); } } else if (type == LISP_TYPE_PARSE_ERROR) fprintf(stderr, "Error: parse error in rc file.\n"); lisp_free(obj); if (type == LISP_TYPE_EOF || type == LISP_TYPE_PARSE_ERROR) break; } lisp_stream_free_path(&stream); } } free(filename); } static void usage (void) { printf("Usage:\n" " metapixel --version\n" " print out version number\n" " metapixel --help\n" " print this help text\n" " metapixel [option ...] --prepare \n" " calculate and output tables for \n" " metapixel [option ...] --metapixel \n" " transform to \n" " metapixel [option ...] --batch \n" " perform all the tasks in \n" "Options:\n" " -l, --library=DIR add the library in DIR\n" " -x, --antimosaic=PIC use PIC as an antimosaic\n" " -w, --width=WIDTH set width for small images\n" " -h, --height=HEIGHT set height for small images\n" " -y, --y-weight=WEIGHT assign relative weight for the Y-channel\n" " -i, --i-weight=WEIGHT assign relative weight for the I-channel\n" " -q, --q-weight=WEIGHT assign relative weight for the Q-channel\n" " -s --scale=SCALE scale input image by specified factor\n" " -m, --metric=METRIC choose metric (subpixel or wavelet)\n" " -e, --search=SEARCH choose search method (local or global)\n" " -c, --collage collage mode\n" " -d, --distance=DIST minimum distance between two instances of\n" " the same constituent image\n" " -a, --cheat=PERC cheat with specified percentage\n" " -f, --forbid-reconstruction=DIST\n" " forbid placing antimosaic images on their\n" " original locations or locations around it\n" " --out=FILE write protocol to file\n" " --in=FILE read protocol from file and use it\n" "\n" "Report bugs and suggestions to schani@complang.tuwien.ac.at\n"); } #define OPT_VERSION 256 #define OPT_HELP 257 #define OPT_PREPARE 258 #define OPT_METAPIXEL 259 #define OPT_BATCH 260 #define OPT_OUT 261 #define OPT_IN 262 #define OPT_BENCHMARK_RENDERING 263 #define OPT_PRINT_PREPARE_SETTINGS 264 #define MODE_NONE 0 #define MODE_PREPARE 1 #define MODE_METAPIXEL 2 #define MODE_BATCH 3 int main (int argc, char *argv[]) { int mode = MODE_NONE; int metric; int search; int collage = 0; int classic_min_distance, collage_min_distance; int cheat = 0; float scale = 1.0; char *out_filename = 0; char *in_filename = 0; char *antimosaic_filename = 0; string_list_t *library_directories = 0; int prepare_width = 0, prepare_height = 0; read_rc_file(); small_width = default_small_width; small_height = default_small_height; prepare_width = default_prepare_width; prepare_height = default_prepare_height; memcpy(weight_factors, default_weight_factors, sizeof(weight_factors)); metric = default_metric; search = default_search; classic_min_distance = default_classic_min_distance; collage_min_distance = default_collage_min_distance; cheat = default_cheat_amount; forbid_reconstruction_radius = default_forbid_reconstruction_radius + 1; while (1) { static struct option long_options[] = { { "version", no_argument, 0, OPT_VERSION }, { "help", no_argument, 0, OPT_HELP }, { "prepare", no_argument, 0, OPT_PREPARE }, { "metapixel", no_argument, 0, OPT_METAPIXEL }, { "batch", no_argument, 0, OPT_BATCH }, { "out", required_argument, 0, OPT_OUT }, { "in", required_argument, 0, OPT_IN }, { "benchmark-rendering", no_argument, 0, OPT_BENCHMARK_RENDERING }, { "print-prepare-settings", no_argument, 0, OPT_PRINT_PREPARE_SETTINGS }, { "library", required_argument, 0, 'l' }, { "width", required_argument, 0, 'w' }, { "height", required_argument, 0, 'h' }, { "y-weight", required_argument, 0, 'y' }, { "i-weight", required_argument, 0, 'i' }, { "q-weight", required_argument, 0, 'q' }, { "scale", required_argument, 0, 's' }, { "collage", no_argument, 0, 'c' }, { "distance", required_argument, 0, 'd' }, { "cheat", required_argument, 0, 'a' }, { "metric", required_argument, 0, 'm' }, { "search", required_argument, 0, 'e' }, { "antimosaic", required_argument, 0, 'x' }, { "forbid-reconstruction", required_argument, 0, 'f' }, { 0, 0, 0, 0 } }; int option, option_index; option = getopt_long(argc, argv, "l:m:e:w:h:y:i:q:s:cd:a:x:f:", long_options, &option_index); if (option == -1) break; switch (option) { case OPT_PREPARE : mode = MODE_PREPARE; break; case OPT_METAPIXEL : mode = MODE_METAPIXEL; break; case OPT_BATCH : mode = MODE_BATCH; break; case OPT_OUT : if (out_filename != 0) { fprintf(stderr, "the --out option can be used at most once\n"); return 1; } out_filename = strdup(optarg); assert(out_filename != 0); break; case OPT_IN : if (in_filename != 0) { fprintf(stderr, "the --in option can be used at most once\n"); return 1; } in_filename = strdup(optarg); assert(in_filename != 0); break; case OPT_BENCHMARK_RENDERING : benchmark_rendering = 1; break; case OPT_PRINT_PREPARE_SETTINGS : printf("%d %d %s\n", default_prepare_width, default_prepare_height, default_prepare_directory != 0 ? default_prepare_directory : ""); exit(0); break; case 'm' : if (strcmp(optarg, "wavelet") == 0) metric = METRIC_WAVELET; else if (strcmp(optarg, "subpixel") == 0) metric = METRIC_SUBPIXEL; else { fprintf(stderr, "metric must either be subpixel or wavelet\n"); return 1; } break; case 'e' : if (strcmp(optarg, "local") == 0) search = SEARCH_LOCAL; else if (strcmp(optarg, "global") == 0) search = SEARCH_GLOBAL; else { fprintf(stderr, "search method must either be local or global\n"); return 1; } break; case 'w' : small_width = prepare_width = atoi(optarg); break; case 'h' : small_height = prepare_height = atoi(optarg); break; case 'y' : weight_factors[0] = atof(optarg); break; case 'i' : weight_factors[1] = atof(optarg); break; case 'q' : weight_factors[2] = atof(optarg); break; case 's': scale = atof(optarg); break; case 'c' : collage = 1; break; case 'd' : classic_min_distance = collage_min_distance = atoi(optarg); break; case 'a' : cheat = atoi(optarg); break; case 'l' : if (antimosaic_filename != 0) { fprintf(stderr, "Error: --library and --antimosaic cannot be used together.\n"); return 1; } library_directories = string_list_prepend_copy(library_directories, optarg); break; case 'x' : if (antimosaic_filename != 0) { fprintf(stderr, "Error: at most one antimosaic picture can be specified.\n"); return 1; } else if (library_directories != 0) { fprintf(stderr, "Error: --library and --antimosaic cannot be used together.\n"); return 1; } antimosaic_filename = strdup(optarg); break; case 'f' : forbid_reconstruction_radius = atoi(optarg) + 1; break; case OPT_VERSION : printf("metapixel " METAPIXEL_VERSION "\n" "\n" "Copyright (C) 1997-2006 Mark Probst\n" "\n" "This program is free software; you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 2 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program; if not, write to the Free Software\n" "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"); exit(0); case OPT_HELP : usage(); return 0; default : assert(0); } } /* check settings for soundness */ if (small_height <= 0) { fprintf(stderr, "Error: height of small images must be positive.\n"); return 1; } if (small_width <= 0) { fprintf(stderr, "Error: width of small images must be positive.\n"); return 1; } if (scale <= 0.0) { fprintf(stderr, "Error: scale factor must be positive.\n"); return 1; } if (classic_min_distance < 0) { fprintf(stderr, "Error: classic minimum distance must be non-negative.\n"); return 1; } if (collage_min_distance < 0) { fprintf(stderr, "Error: collage minimum distance must be non-negative.\n"); return 1; } if (cheat < 0 || cheat > 100) { fprintf(stderr, "Error: cheat amount must be in the range from 0 to 100.\n"); return 1; } /* the value in forbid_reconstruction_radius is always one more than the user specified */ if (forbid_reconstruction_radius <= 0) { fprintf(stderr, "Error: forbid reconstruction distance must be non-negative.\n"); return 1; } if (in_filename != 0 || out_filename != 0) { if (mode != MODE_METAPIXEL) { fprintf(stderr, "the --in and --out options can only be used in metapixel mode\n"); return 1; } if (collage) { fprintf(stderr, "the --in and --out options can only be used for classic mosaics\n"); return 1; } } sqrt_of_two = sqrt(2); sqrt_of_image_size = sqrt(IMAGE_SIZE); compute_index_weights(); if (mode == MODE_PREPARE) { static coefficient_with_index_t highest_coeffs[NUM_COEFFS]; int i, channel; unsigned char *image_data; unsigned char *scaled_data; char *inimage_name, *outimage_name, *tables_name; FILE *tables_file; int in_width, in_height; metapixel_t pixel; lisp_object_t *obj; if (argc - optind != 3) { usage(); return 1; } assert(prepare_width > 0 && prepare_height > 0); inimage_name = argv[optind + 0]; outimage_name = argv[optind + 1]; tables_name = argv[optind + 2]; image_data = read_image(inimage_name, &in_width, &in_height); if (image_data == 0) { fprintf(stderr, "could not read image `%s'\n", inimage_name); return 1; } tables_file = fopen(tables_name, "ab"); if (tables_file == 0) { fprintf(stderr, "could not open file `%s' for writing\n", tables_name); return 1; } /* generate small image */ scaled_data = scale_image(image_data, in_width, in_height, 0, 0, in_width, in_height, prepare_width, prepare_height); assert(scaled_data != 0); write_image(outimage_name, prepare_width, prepare_height, scaled_data, 3, prepare_width * 3, IMAGE_FORMAT_PNG); generate_metapixel_coefficients(&pixel, scaled_data, highest_coeffs); free(scaled_data); fprintf(tables_file, "(small-image "); obj = lisp_make_string(strip_path(outimage_name)); lisp_dump(obj, tables_file); lisp_free(obj); fprintf(tables_file, " (size %d %d) (wavelet (means %f %f %f) (coeffs", prepare_width, prepare_height, pixel.means[0], pixel.means[1], pixel.means[2]); for (i = 0; i < NUM_COEFFS; ++i) fprintf(tables_file, " %d", highest_coeffs[i].index); fprintf(tables_file, ")) (subpixel"); for (channel = 0; channel < NUM_CHANNELS; ++channel) { static char *channel_names[] = { "y", "i", "q" }; fprintf(tables_file, " (%s", channel_names[channel]); for (i = 0; i < NUM_SUBPIXELS; ++i) fprintf(tables_file, " %d", (int)pixel.subpixels[channel * NUM_SUBPIXELS + i]); fprintf(tables_file, ")"); } fprintf(tables_file, "))\n"); fclose(tables_file); } else if (mode == MODE_METAPIXEL || mode == MODE_BATCH) { if ((mode == MODE_METAPIXEL && argc - optind != 2) || (mode == MODE_BATCH && argc - optind != 1)) { usage(); return 1; } if (antimosaic_filename == 0 && library_directories == 0) library_directories = default_library_directories; if (antimosaic_filename != 0) { classic_reader_t *reader = init_classic_reader(antimosaic_filename, scale); int x, y; for (y = 0; y < reader->metaheight; ++y) { read_classic_row(reader); for (x = 0; x < reader->metawidth; ++x) { static coefficient_with_index_t highest_coeffs[NUM_COEFFS]; unsigned char *scaled_data; metapixel_t *pixel = new_metapixel(); int left_x, width; compute_classic_column_coords(reader, x, &left_x, &width); scaled_data = scale_image(reader->in_image_data, reader->in_image_width, reader->num_lines, left_x, 0, width, reader->num_lines, small_width, small_height); assert(scaled_data != 0); generate_metapixel_coefficients(pixel, scaled_data, highest_coeffs); pixel->data = scaled_data; pixel->width = small_width; pixel->height = small_height; pixel->anti_x = x; pixel->anti_y = y; pixel->collage_positions = 0; pixel->filename = (char*)malloc(64); sprintf(pixel->filename, "(%d,%d)", x, y); add_metapixel(pixel); printf(":"); fflush(stdout); } } printf("\n"); free_classic_reader(reader); } else if (library_directories != 0) { string_list_t *lst; for (lst = library_directories; lst != 0; lst = lst->next) if (!read_tables(lst->str)) { fprintf(stderr, "Error: cannot read library table `%s/%s'.\n", lst->str, TABLES_FILENAME); return 1; } forbid_reconstruction_radius = 0; } else { fprintf(stderr, "Error: you must give one of the option --library and --antimosaic.\n"); return 1; } if (mode == MODE_METAPIXEL) { if (collage) generate_collage(argv[optind], argv[optind + 1], scale, collage_min_distance, metric, cheat); else make_classic_mosaic(argv[optind], argv[optind + 1], metric, scale, search, classic_min_distance, cheat, in_filename, out_filename); } else if (mode == MODE_BATCH) { FILE *in = fopen(argv[optind], "rb"); lisp_stream_t stream; if (in == 0) { fprintf(stderr, "cannot open batch file `%s': %s\n", argv[optind], strerror(errno)); return 1; } lisp_stream_init_file(&stream, in); for (;;) { lisp_object_t *obj = lisp_read(&stream); int type = lisp_type(obj); if (type != LISP_TYPE_EOF && type != LISP_TYPE_PARSE_ERROR) { lisp_object_t *vars[4]; if (lisp_match_string("(classic (#?(or image protocol) #?(string)) #?(string) . #?(list))", obj, vars)) { float this_scale = scale; int this_search = search; int this_min_distance = classic_min_distance; int this_cheat = cheat; int this_metric = metric; char *this_prot_in_filename = in_filename; char *this_prot_out_filename = out_filename; char *this_image_out_filename = lisp_string(vars[2]); char *this_image_in_filename = 0; lisp_object_t *lst; lisp_object_t *var; if (strcmp(lisp_symbol(vars[0]), "image") == 0) this_image_in_filename = lisp_string(vars[1]); else this_prot_in_filename = lisp_string(vars[1]); for (lst = vars[3]; lisp_type(lst) != LISP_TYPE_NIL; lst = lisp_cdr(lst)) { if (lisp_match_string("(scale #?(real))", lisp_car(lst), &var)) { float val = lisp_real(var); if (val <= 0.0) fprintf(stderr, "scale must be larger than 0\n"); else this_scale = val; } else if (lisp_match_string("(search #?(or local global))", lisp_car(lst), &var)) { if (strcmp(lisp_symbol(var), "local") == 0) this_search = SEARCH_LOCAL; else this_search = SEARCH_GLOBAL; } else if (lisp_match_string("(min-distance #?(integer))", lisp_car(lst), &var)) { int val = lisp_integer(var); if (val < 0) fprintf(stderr, "min-distance cannot be negative\n"); else this_min_distance = val; } else if (lisp_match_string("(cheat #?(integer))", lisp_car(lst), &var)) { int val = lisp_integer(var); if (val < 0 || val > 100) fprintf(stderr, "cheat must be between 0 and 100, inclusively\n"); else this_cheat = val; } else if (lisp_match_string("(metric #?(or subpixel wavelet))", lisp_car(lst), &var)) { if (strcmp(lisp_symbol(var), "subpixel") == 0) this_metric = METRIC_SUBPIXEL; else this_metric = METRIC_WAVELET; } else if (lisp_match_string("(protocol #?(string))", lisp_car(lst), &var)) this_prot_out_filename = lisp_string(var); else { fprintf(stderr, "unknown expression "); lisp_dump(lisp_car(lst), stderr); fprintf(stderr, "\n"); } } make_classic_mosaic(this_image_in_filename, this_image_out_filename, this_metric, this_scale, this_search, this_min_distance, this_cheat, this_prot_in_filename, this_prot_out_filename); } else { fprintf(stderr, "unknown expression "); lisp_dump(obj, stderr); fprintf(stderr, "\n"); } } else if (type == LISP_TYPE_PARSE_ERROR) fprintf(stderr, "parse error in batch file\n"); lisp_free(obj); if (type == LISP_TYPE_EOF) break; } } else assert(0); } else { usage(); return 1; } return 0; } metapixel-1.0.2/zoom.h0000644000127400012740000000241610537045432014143 0ustar schanischani/* -*- c -*- */ /* * zoom.h * * metapixel * * Copyright (C) 2004 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __ZOOM_H__ #define __ZOOM_H__ typedef float (*filter_func_t) (float); typedef struct { filter_func_t func; float support_radius; } filter_t; #define FILTER_BOX 0 #define FILTER_TRIANGLE 1 #define FILTER_MITCHELL 2 filter_t* get_filter (int index); void zoom_image (unsigned char *dest, unsigned char *src, filter_t *filter, int num_channels, int dest_width, int dest_height, int dest_row_stride, int src_width, int src_height, int src_row_stride); #endif metapixel-1.0.2/metapixel.h0000644000127400012740000000644510537045432015155 0ustar schanischani/* * metapixel.h * * metapixel * * Copyright (C) 1997-2004 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __METAPIXEL_H__ #define __METAPIXEL_H__ #include "readimage.h" #define DEFAULT_WIDTH 64 #define DEFAULT_HEIGHT 64 #define DEFAULT_PREPARE_WIDTH 128 #define DEFAULT_PREPARE_HEIGHT 128 #define DEFAULT_CLASSIC_MIN_DISTANCE 5 #define DEFAULT_COLLAGE_MIN_DISTANCE 256 #define NUM_CHANNELS 3 #define IMAGE_SIZE 64 #define ROW_LENGTH (IMAGE_SIZE * NUM_CHANNELS) #define SIGNIFICANT_COEFFS 40 #define NUM_COEFFS (NUM_CHANNELS * SIGNIFICANT_COEFFS) #define NUM_INDEXES (IMAGE_SIZE * IMAGE_SIZE * NUM_CHANNELS * 2) #define NUM_SUBPIXEL_ROWS_COLS 5 #define NUM_SUBPIXELS (NUM_SUBPIXEL_ROWS_COLS * NUM_SUBPIXEL_ROWS_COLS) #define METRIC_WAVELET 1 #define METRIC_SUBPIXEL 2 #define SEARCH_LOCAL 1 #define SEARCH_GLOBAL 2 #define TABLES_FILENAME "tables.mxt" typedef struct { int index; float coeff; } coefficient_with_index_t; typedef unsigned short index_t; typedef struct { index_t coeffs[NUM_COEFFS]; } search_coefficients_t; typedef struct _position_t { int x, y; struct _position_t *next; } position_t; typedef struct _metapixel_t { char *filename; search_coefficients_t coeffs; float means[NUM_CHANNELS]; unsigned char subpixels[NUM_SUBPIXELS * NUM_CHANNELS]; int flag; unsigned char *data; /* only used if from an antimosaic or if benchmarking rendering */ int width, height; /* only valid if data != 0 */ int anti_x, anti_y; /* only used if from an antimosaic */ position_t *collage_positions; /* only used in collages */ struct _metapixel_t *next; } metapixel_t; typedef struct { metapixel_t *pixel; float score; } match_t; typedef struct { int metawidth; int metaheight; match_t *matches; } mosaic_t; typedef struct { image_reader_t *image_reader; int in_image_width; int in_image_height; int out_image_width; int out_image_height; int metawidth; int metaheight; int y; int num_lines; unsigned char *in_image_data; } classic_reader_t; typedef union { struct { search_coefficients_t coeffs; float means[NUM_CHANNELS]; float sums[NUM_COEFFS]; } wavelet; struct { unsigned char subpixels[NUM_SUBPIXELS * NUM_CHANNELS]; } subpixel; } coeffs_t; typedef struct { metapixel_t *pixel; float score; int x; int y; } global_match_t; typedef struct _string_list_t { char *str; struct _string_list_t *next; } string_list_t; typedef float(*compare_func_t)(coeffs_t*, metapixel_t*, float); #endif metapixel-1.0.2/metapixelrc0000644000127400012740000000155610537045432015252 0ustar schanischani; comments start with semicolons ; if we prepare images, they go into this directory by default: (prepare-directory "/home/hoschi/metapixels") ; and we want them to be prepared at this size: (prepare-dimensions 80 80) ; of course we want Metapixel to always use the images in our prepare ; directory: (library-directory "/home/hoschi/metapixels") ; by default we want our mosaic images a bit smaller: (small-image-dimensions 64 64) ; we use the default weights, so the following line is commented out ;(yiq-weights 1.0 1.0 1.0) ; also we use the subpixel metric, which is the default ;(metric subpixel) ; we want the global search method, though (search-method global) ; for all the other options, we use default values, so everything else ; is commented out: ;(minimum-classic-distance 5) ;(minimum-collage-distance 256) ;(cheat-amount 0) ;(forbid-reconstruction-distance 0) metapixel-1.0.2/NEWS0000644000127400012740000000401310537045432013500 0ustar schanischaniChanges in version 1.0.1: * Bugfixes * sizesort renamed to metapixel-sizesort. * Improvements to metapixel-sizesort. * RPM SPEC file added. Changes in version 1.0.0: * Bugfixes Changes since version 0.11: * The tables files must now always be in the directory where the small images reside, and that directory is now called a "library". * Metapixel can now take default values for its settings from a configuration file in the user's home directory (".metapixelrc"). * Bugfixes Changes since version 0.10: * Metapixel can now enforce a minimum image distance for collages. * metapixel-prepare can now traverse the image directory recursively (courtesy of Jake Di Toro). * The tables file must now no longer be redirected to stdin but it's name must be given to the option '--tables'. This option can be used several times, so more than one tables file can be read. * The default minimum distance for classical mosaics is now 5 instead of 0. * A rudimentary man page is now included (courtesy of Debian's Chris Vanden Berghe). * Reading the tables file is now more than twice as fast. * Bugfixes Changes since version 0.9: * Fixed a bug that prevented global search from working on non-square images * Got rid of libzoom, so now Metapixel is standard GPL * Added the sizesort utility for sorting images by size Changes since version 0.8: * Global search mode * Protocol writing and reading * Antimosaic Changes since version 0.7: * Scaling of input image added * Tremendous memory usage improvement for classical mosaics Changes since version 0.6: * Introduces the subpixel image comparison metric Changes since version 0.5: * Cheat option Changes since version 0.4: * Bugfixes * Minimum distance between two instances of the same constituent image can be specified Changes since version 0.3: * Bugfixes * Speed improvements * Got rid of ImageMagick Changes since version 0.2: * Bugfixes * Speed improvements metapixel-1.0.2/vector.h0000644000127400012740000001006010537045432014453 0ustar schanischani/* -*- c -*- */ /* * vector.h * * metapixel * * Copyright (C) 1997-1999 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ typedef struct _Vector2D { double x; double y; } Vector2D; typedef struct _Vector3D { double x; double y; double z; } Vector3D; typedef double Vector4D[4]; typedef double Matrix3D[3][3]; typedef double Matrix4D[4][4]; typedef double Matrix4x3[4][3]; Vector2D MakeVector2D (double x, double y); Vector2D* InitVector2D (Vector2D *vec, double x, double y); Vector2D* CopyVector2D (Vector2D *dest, const Vector2D *src); double Abs2D (const Vector2D *vec); Vector2D* AddVectors2D (Vector2D *dest, const Vector2D *vec1, const Vector2D *vec2); Vector2D* SubVectors2D (Vector2D *dest, const Vector2D *vec1, const Vector2D *vec2); Vector2D* MultScalar2D (Vector2D *dest, double d, const Vector2D *vec); Vector2D* MultVectors2D (Vector2D *vec, const Vector2D *vec1, const Vector2D *vec2); Vector2D* Unity2D (Vector2D *dest, Vector2D *vec); Vector2D* Rectangular2DToPolar (Vector2D *dest, const Vector2D *src); Vector2D* Polar2DToRectangular (Vector2D *dest, const Vector2D *src); Vector3D MakeVector3D (double x, double y, double z); Vector3D* InitVector3D (Vector3D *vec, double x, double y, double z); Vector3D* CopyVector3D (Vector3D *dest, const Vector3D *src); double Abs3D (const Vector3D *vec); Vector3D* AddVectors3D (Vector3D *dest, const Vector3D *vec1, const Vector3D *vec2); Vector3D* SubVectors3D (Vector3D *dest, const Vector3D *vec1, const Vector3D *vec2); Vector3D* MultScalar3D (Vector3D *dest, double d, const Vector3D *vec); Vector3D* MultVectors3D (Vector3D *vec, const Vector3D *vec1, const Vector3D *vec2); double DotProduct3D (const Vector3D *vec1, const Vector3D *vec2); Vector3D* CrossProduct3D (Vector3D *vec, const Vector3D *vec1, const Vector3D *vec2); Vector3D* Unity3D (Vector3D *dest, const Vector3D *vec); Matrix3D* InitMatrix3D (Matrix3D *mat); Matrix3D* CopyMatrix3D (Matrix3D *dest, const Matrix3D *src); Vector3D* MultMatrixVector3D (Vector3D *dest, const Matrix3D *mat, const Vector3D *vec); Matrix4D* InitMatrix4D (Matrix4D *mat); Matrix4D* CopyMatrix4D (Matrix4D *dest, const Matrix4D *src); Matrix4D* MultMatrix4D (Matrix4D *dest, const Matrix4D *mat1, const Matrix4D *mat2); Vector3D* ApplyTransformation (Vector3D *dest, const Matrix4D *mat, const Vector3D *vec); Matrix4D* InitTranslationMatrix (Matrix4D *mat, double x, double y, double z); Matrix4D* InitXRotationMatrix (Matrix4D *mat, double theta); Matrix4D* InitYRotationMatrix (Matrix4D *mat, double theta); Matrix4D* InitZRotationMatrix (Matrix4D *mat, double theta); Matrix4x3* InitMatrix4x3 (Matrix4x3 *mat); Matrix4x3* MakeMatrix4x3 (Matrix4x3 *dest, const Vector3D *vec1, const Vector3D *vec2, const Vector3D *vec3, const Vector3D *vec4); Matrix4x3* CopyMatrix4x3 (Matrix4x3 *dest, const Matrix4x3 *src); Matrix4x3* MultMatrix4x3 (Matrix4x3 *dest, const Matrix4D *mat1, const Matrix4x3 *mat2); Vector3D* MultVector4DMatrix4x3 (Vector3D *dest, const Vector4D *vec, const Matrix4x3 *mat); Vector3D* CatmullRom (Vector3D *dest, const Vector3D *vec1, const Vector3D *vec2, const Vector3D *vec3, const Vector3D *vec4, double t); Matrix4x3* PrecompileCatmullRom (Matrix4x3 *dest, const Vector3D *vec1, const Vector3D *vec2, const Vector3D *vec3, const Vector3D *vec4); Vector3D* QuickCatmullRom (Vector3D *dest, Matrix4x3 *matC, double t); metapixel-1.0.2/getopt.h0000644000127400012740000001055510537045432014464 0ustar schanischani/* Declarations for getopt. Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if defined (__STDC__) && __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if defined (__STDC__) && __STDC__ #ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* not __GNU_LIBRARY__ */ extern int getopt (); #endif /* __GNU_LIBRARY__ */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* __STDC__ */ #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ metapixel-1.0.2/Makefile0000644000127400012740000000442110537045432014444 0ustar schanischaniPREFIX = /usr/local INSTALL = install MANPAGE_XSL = /sw/share/xml/xsl/docbook-xsl/manpages/docbook.xsl BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man VERSION = 1.0.2 #DEBUG = -g OPTIMIZE = -O2 #PROFILE = -pg MACOS_LDOPTS = -L/sw/lib MACOS_CCOPTS = -I/sw/include FORMATDEFS = -DRWIMG_JPEG -DRWIMG_PNG -DRWIMG_GIF LDOPTS = $(MACOS_LDOPTS) -L/usr/X11R6/lib $(PROFILE) $(DEBUG) CCOPTS = $(MACOS_CCOPTS) -I/usr/X11R6/include -I/usr/X11R6/include/X11 -I. -Irwimg -Wall $(OPTIMIZE) $(DEBUG) $(PROFILE) -DMETAPIXEL_VERSION=\"$(VERSION)\" CC = gcc #LIBFFM = -lffm export CCOPTS CC FORMATDEFS LISPREADER_OBJS = lispreader.o pools.o allocator.o OBJS = metapixel.o vector.o zoom.o $(LISPREADER_OBJS) getopt.o getopt1.o CONVERT_OBJS = convert.o $(LISPREADER_OBJS) getopt.o getopt1.o IMAGESIZE_OBJS = imagesize.o all : metapixel metapixel.1 convert metapixel-imagesize metapixel : $(OBJS) librwimg $(CC) $(LDOPTS) -o metapixel $(OBJS) rwimg/librwimg.a -lpng -ljpeg -lgif $(LIBFFM) -lm -lz metapixel.1 : metapixel.xml xsltproc --nonet $(MANPAGE_XSL) metapixel.xml convert : $(CONVERT_OBJS) $(CC) $(LDOPTS) -o convert $(CONVERT_OBJS) metapixel-imagesize : $(IMAGESIZE_OBJS) librwimg $(CC) $(LDOPTS) -o metapixel-imagesize $(IMAGESIZE_OBJS) rwimg/librwimg.a -lpng -ljpeg -lgif -lm -lz zoom : zoom.c librwimg $(CC) -o zoom $(OPTIMIZE) $(PROFILE) $(MACOS_CCOPTS) -DTEST_ZOOM zoom.c $(MACOS_LDOPTS) rwimg/librwimg.a -lpng -ljpeg -lgif -lm -lz %.o : %.c $(CC) $(CCOPTS) $(FORMATDEFS) -c $< librwimg : $(MAKE) -C rwimg install : metapixel metapixel.1 $(INSTALL) -d $(BINDIR) $(INSTALL) metapixel $(BINDIR) $(INSTALL) metapixel-prepare $(BINDIR) $(INSTALL) metapixel.1 $(MANDIR)/man1 $(INSTALL) metapixel-imagesize $(BINDIR) $(INSTALL) metapixel-sizesort $(BINDIR) clean : rm -f *.o metapixel convert metapixel-imagesize *~ $(MAKE) -C rwimg clean realclean : clean rm -f metapixel.1 dist : metapixel.1 rm -rf metapixel-$(VERSION) mkdir metapixel-$(VERSION) mkdir metapixel-$(VERSION)/rwimg cp Makefile README NEWS COPYING *.[ch] metapixel-prepare metapixel-sizesort \ metapixel.xml metapixel.1 metapixelrc metapixel.spec \ metapixel-$(VERSION)/ cp rwimg/Makefile rwimg/*.[ch] metapixel-$(VERSION)/rwimg/ tar -zcvf metapixel-$(VERSION).tar.gz metapixel-$(VERSION) rm -rf metapixel-$(VERSION) metapixel-1.0.2/metapixel.xml0000644000127400012740000001203610537045432015517 0ustar schanischani Chris"> Vanden Berghe"> May 5, 2004"> 1"> Chris@VandenBerghe.org"> METAPIXEL"> Debian"> GNU"> GPL"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2004 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; generator for photomosaics metapixel-prepare srcdir destdir prepares the pictures in srcdir by creating resized images and a table file in destdir &dhpackage; --metapixel input.jpg output.png --library destdir creates a photomosaic output.png using input.jpg as the input image and destdir/tables.mxt as table file DESCRIPTION This manual page documents briefly the &dhpackage; and &dhpackage;-prepare commands. For more information check the README file included in the distribution. &dhpackage; is a program for generating photomosaics. It can generate classical photomosaics, in which the source image is viewed as a matrix of equally sized rectangles for each of which a matching image is substitued, as well as collage-style photomosaics, in which rectangular parts of the source image at arbitrary positions (i.e. not aligned to a matrix) are substituted by matching images. &dhpackage;-prepare is a utility that needs to be run before metapixel can be used. It prepares your source images so that they can be used by &dhpackage; to create the actual photomosaic. USAGE &dhpackage;-prepare srcdir destdir has to be run first. srcdir is the path to the directory containing the source images, e.g. ~/Pictures/Holidays. destdir, e.g. ~/.metapixel, is the path to the directory where you want to store the rescaled images and the tables.mxt index file. This directory should be created manually before running &dhpackage;-prepare. &dhpackage; --metapixel input.jpg output.png --library destdir is then used to transform an image (input.jpg) into a mosaic (output.png) using the source images (described by destdir/tables.mxt). OPTIONS The options are described in the README file or by running &dhpackage; or &dhpackage;-prepare with the --help option. SEE ALSO The README file is included in the Metapixel distribution. AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
metapixel-1.0.2/rwimg/0000755000127400012740000000000010537045432014130 5ustar schanischanimetapixel-1.0.2/rwimg/readimage.c0000644000127400012740000000622610537045432016220 0ustar schanischani/* -*- c -*- */ /* * readimage.c * * rwimg * * Copyright (C) 2000-2006 Mark Probst * Copyright (C) 2006 Xavier Martin * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include "readimage.h" #ifdef RWIMG_JPEG #include "rwjpeg.h" #endif #ifdef RWIMG_PNG #include "rwpng.h" #endif #ifdef RWIMG_GIF #include "rwgif.h" #endif image_reader_t* open_image_reading (const char *filename) { unsigned char magic[4]; FILE *file; void *data; int width, height; image_reader_t *reader; image_read_func_t read_func; image_reader_free_func_t free_func; file = fopen(filename, "r"); if (file == 0) return 0; if (fread(magic, 4, 1, file) != 1) { fclose(file); return 0; } fclose(file); if (memcmp(magic, "\xff\xd8", 2) == 0) { #ifdef RWIMG_JPEG data = open_jpeg_file_reading(filename, &width, &height); read_func = jpeg_read_lines; free_func = jpeg_free_reader_data; #else return 0; #endif } else if (memcmp(magic, "\x89PNG", 4) == 0) { #ifdef RWIMG_PNG data = open_png_file_reading(filename, &width, &height); read_func = png_read_lines; free_func = png_free_reader_data; #else return 0; #endif } else if (memcmp(magic, "GIF8", 4) == 0) { #ifdef RWIMG_GIF data = open_gif_file(filename, &width, &height); read_func = gif_read_lines; free_func = gif_free_data; #else return 0; #endif } else return 0; if (data == 0) return 0; reader = (image_reader_t*)malloc(sizeof(image_reader_t)); assert(reader != 0); reader->width = width; reader->height = height; reader->num_lines_read = 0; reader->data = data; reader->read_func = read_func; reader->free_func = free_func; return reader; } void read_lines (image_reader_t *reader, unsigned char *lines, int num_lines) { assert(reader->num_lines_read + num_lines <= reader->height); reader->read_func(reader->data, lines, num_lines); reader->num_lines_read += num_lines; } void free_image_reader (image_reader_t *reader) { reader->free_func(reader->data); free(reader); } unsigned char* read_image (const char *filename, int *width, int *height) { image_reader_t *reader = open_image_reading(filename); unsigned char *data; if (reader == 0) return 0; *width = reader->width; *height = reader->height; data = (unsigned char*)malloc(*width * *height * 3); read_lines(reader, data, *height); free_image_reader(reader); return data; } metapixel-1.0.2/rwimg/rwpng.c0000644000127400012740000001202010537045432015424 0ustar schanischani/* -*- c -*- */ /* * rwpng.c * * rwimg * * Copyright (C) 1997-2004 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include "rwpng.h" typedef struct { FILE *file; png_structp png_ptr; png_infop info_ptr, end_info; int row_stride; int have_read; } png_data_t; void* open_png_file_reading (const char *filename, int *width, int *height) { png_data_t *data = (png_data_t*)malloc(sizeof(png_data_t)); assert(data != 0); data->file = fopen(filename, "r"); assert(data->file != 0); data->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); assert(data->png_ptr != 0); data->info_ptr = png_create_info_struct(data->png_ptr); assert(data->info_ptr != 0); data->end_info = png_create_info_struct(data->png_ptr); assert(data->end_info != 0); if (setjmp(data->png_ptr->jmpbuf)) assert(0); png_init_io(data->png_ptr, data->file); png_read_info(data->png_ptr, data->info_ptr); *width = data->info_ptr->width; *height = data->info_ptr->height; assert(data->info_ptr->bit_depth == 8 || data->info_ptr->bit_depth == 16); assert(data->info_ptr->color_type == PNG_COLOR_TYPE_RGB || data->info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA); assert(data->info_ptr->interlace_type == PNG_INTERLACE_NONE); data->have_read = 0; return data; } void png_read_lines (void *_data, unsigned char *lines, int num_lines) { png_data_t *data = (png_data_t*)_data; int i; int bps, spp; unsigned char *row; if (setjmp(data->png_ptr->jmpbuf)) assert(0); if (data->info_ptr->color_type == PNG_COLOR_TYPE_RGB) spp = 3; else spp = 4; if (data->info_ptr->bit_depth == 16) bps = 2; else bps = 1; row = (unsigned char*)malloc(data->info_ptr->width * spp * bps); for (i = 0; i < num_lines; ++i) { int j, channel; png_read_row(data->png_ptr, (png_bytep)row, 0); for (j = 0; j < data->info_ptr->width; ++j) for (channel = 0; channel < 3; ++channel) lines[i * data->info_ptr->width * 3 + j * 3 + channel] = row[j * spp * bps + channel * bps]; } free(row); data->have_read = 1; } void png_free_reader_data (void *_data) { png_data_t *data = (png_data_t*)_data; if (setjmp(data->png_ptr->jmpbuf)) assert(0); if (data->have_read) png_read_end(data->png_ptr, data->end_info); png_destroy_read_struct(&data->png_ptr, &data->info_ptr, &data->end_info); fclose(data->file); free(data); } void* open_png_file_writing (const char *filename, int width, int height, int pixel_stride, int row_stride) { png_data_t *data = (png_data_t*)malloc(sizeof(png_data_t)); assert(data != 0); assert(pixel_stride == 3 || pixel_stride == 4); data->file = fopen(filename, "w"); assert(data->file != 0); data->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); assert(data->png_ptr != 0); data->info_ptr = png_create_info_struct(data->png_ptr); assert(data->info_ptr != 0); if (setjmp(data->png_ptr->jmpbuf)) assert(0); if (pixel_stride == 4) png_set_filler(data->png_ptr, 0, PNG_FILLER_AFTER); png_init_io(data->png_ptr, data->file); data->info_ptr->width = width; data->info_ptr->height = height; data->info_ptr->valid = 0; data->info_ptr->rowbytes = width * 3; data->info_ptr->palette = 0; data->info_ptr->num_palette = 0; data->info_ptr->num_trans = 0; data->info_ptr->bit_depth = 8; data->info_ptr->color_type = PNG_COLOR_TYPE_RGB; data->info_ptr->compression_type = PNG_COMPRESSION_TYPE_DEFAULT; data->info_ptr->filter_type = PNG_FILTER_TYPE_DEFAULT; data->info_ptr->interlace_type = PNG_INTERLACE_NONE; png_write_info(data->png_ptr, data->info_ptr); data->row_stride = row_stride; return data; } void png_write_lines (void *_data, unsigned char *lines, int num_lines) { png_data_t *data = (png_data_t*)_data; int i; if (setjmp(data->png_ptr->jmpbuf)) assert(0); for (i = 0; i < num_lines; ++i) png_write_row(data->png_ptr, (png_bytep)(lines + i * data->row_stride)); } void png_free_writer_data (void *_data) { png_data_t *data = (png_data_t*)_data; if (setjmp(data->png_ptr->jmpbuf)) assert(0); png_write_end(data->png_ptr, data->info_ptr); png_destroy_write_struct(&data->png_ptr, &data->info_ptr); fclose(data->file); free(data); } metapixel-1.0.2/rwimg/writeimage.c0000644000127400012740000000724710537045432016443 0ustar schanischani/* -*- c -*- */ /* * writeimage.c * * rwimg * * Copyright (C) 2000-2006 Mark Probst * Copyright (C) 2006 Xavier Martin * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #ifdef RWIMG_PNG #include "rwpng.h" #endif #ifdef RWIMG_JPEG #include "rwjpeg.h" #endif #include "writeimage.h" static int discover_format (const char *filename) { static struct { const char *suffix; int format; } formats[] = { #ifdef RWIMG_PNG { ".png", IMAGE_FORMAT_PNG }, #endif #ifdef RWIMG_JPEG { ".jpg", IMAGE_FORMAT_JPEG }, { ".jpeg", IMAGE_FORMAT_JPEG }, #endif { 0, 0 } }; int filename_len = strlen(filename); int i; for (i = 0; formats[i].suffix != 0; ++i) { int suffix_len = strlen(formats[i].suffix); if (filename_len >= suffix_len && strcasecmp(formats[i].suffix, filename + filename_len - suffix_len) == 0) return formats[i].format; } /* no format found - using default (PNG if possible, otherwise JPEG) */ #if defined(RWIMG_PNG) return IMAGE_FORMAT_PNG; #elif defined(RWIMG_JPEG) return IMAGE_FORMAT_JPEG; #else return 0; /* error: no such format available */ #endif } image_writer_t* open_image_writing (const char *filename, int width, int height, int pixel_stride, int row_stride, int format) { image_writer_t *writer; void *data = 0; image_write_func_t write_func = 0; image_writer_free_func_t free_func = 0; if (format == IMAGE_FORMAT_AUTO) { format = discover_format(filename); if (format == 0) return 0; } if (0) assert(0); #ifdef RWIMG_PNG else if (format == IMAGE_FORMAT_PNG) { data = open_png_file_writing(filename, width, height, pixel_stride, row_stride); write_func = png_write_lines; free_func = png_free_writer_data; } #endif #ifdef RWIMG_JPEG else if(format == IMAGE_FORMAT_JPEG) { data = open_jpeg_file_writing(filename, width, height); write_func = jpeg_write_lines; free_func = jpeg_free_writer_data; } #endif else assert(0); if (data == 0) return 0; writer = (image_writer_t*)malloc(sizeof(image_writer_t)); writer->width = width; writer->height = height; writer->num_lines_written = 0; writer->data = data; writer->write_func = write_func; writer->free_func = free_func; return writer; } void write_lines (image_writer_t *writer, unsigned char *lines, int num_lines) { assert(writer->num_lines_written + num_lines <= writer->height); writer->write_func(writer->data, lines, num_lines); } void free_image_writer (image_writer_t *writer) { writer->free_func(writer->data); free(writer); } void write_image (const char *filename, int width, int height, unsigned char *lines, int pixel_stride, int row_stride, int format) { image_writer_t *writer = open_image_writing(filename, width, height, pixel_stride, row_stride, format); assert(writer != 0); write_lines(writer, lines, height); free_image_writer(writer); } metapixel-1.0.2/rwimg/rwgif.h0000644000127400012740000000176110537045432015424 0ustar schanischani/* -*- c -*- */ /* * rwgif.h * * rwimg * * Copyright (C) 2006 Xavier Martin * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __RWGIF_H__ #define __RWGIF_H__ void* open_gif_file (const char *filename, int *width, int *height); void gif_read_lines (void *data, unsigned char *lines, int num_lines); void gif_free_data (void *data); #endif metapixel-1.0.2/rwimg/writeimage.h0000644000127400012740000000327310537045432016443 0ustar schanischani/* -*- c -*- */ /* * writeimage.h * * rwimg * * Copyright (C) 2000-2006 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __WRITEIMAGE_H__ #define __WRITEIMAGE_H__ typedef void (*image_write_func_t) (void *data, unsigned char *lines, int num_lines); typedef void (*image_writer_free_func_t) (void *data); typedef struct { int width; int height; int num_lines_written; void *data; image_write_func_t write_func; image_writer_free_func_t free_func; } image_writer_t; #define IMAGE_FORMAT_AUTO 0 #ifdef RWIMG_PNG #define IMAGE_FORMAT_PNG 1 #endif #ifdef RWIMG_JPEG #define IMAGE_FORMAT_JPEG 2 #endif image_writer_t* open_image_writing (const char *filename, int width, int height, int pixel_stride, int row_stride, int format); void write_lines (image_writer_t *writer, unsigned char *lines, int num_lines); void free_image_writer (image_writer_t *writer); void write_image (const char *filename, int width, int height, unsigned char *lines, int pixel_stride, int row_stride, int format); #endif metapixel-1.0.2/rwimg/readimage.h0000644000127400012740000000263310537045432016223 0ustar schanischani/* -*- c -*- */ /* * readimage.h * * rwimg * * Copyright (C) 2000-2004 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __READIMAGE_H__ #define __READIMAGE_H__ typedef void (*image_read_func_t) (void *data, unsigned char *lines, int num_lines); typedef void (*image_reader_free_func_t) (void *data); typedef struct { int width; int height; int num_lines_read; void *data; image_read_func_t read_func; image_reader_free_func_t free_func; } image_reader_t; image_reader_t* open_image_reading (const char *filename); void read_lines (image_reader_t *reader, unsigned char *lines, int num_lines); void free_image_reader (image_reader_t *reader); unsigned char* read_image (const char *filename, int *width, int *height); #endif metapixel-1.0.2/rwimg/rwgif.c0000644000127400012740000001043510537045432015415 0ustar schanischani/* -*- c -*- */ /* * rwgif.c * * rwimg * * Copyright (C) 2006 Xavier Martin * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include typedef struct { GifFileType *file; int width; int height; unsigned char *rgb; } gif_data_t; void* open_gif_file (const char *filename, int *width, int *height) { int interlace_offset[] = { 0, 4, 2, 1 }; int interlace_jump[] = { 8, 8, 4, 2 }; GifColorType *colormap; GifRecordType record_type; GifRowType *buffer = NULL; int i, j; int color_index; unsigned char *ptr = NULL; gif_data_t *data = (gif_data_t*)malloc(sizeof(gif_data_t)); assert(data != 0); data->file = DGifOpenFileName(filename); assert(data->file !=0); do { assert(DGifGetRecordType(data->file, &record_type) != GIF_ERROR) ; switch (record_type) { case IMAGE_DESC_RECORD_TYPE: assert(DGifGetImageDesc(data->file) != GIF_ERROR); *width = data->file->Image.Width; *height = data->file->Image.Height; data->width = *width; data->height = *height; buffer = malloc(*height * sizeof(GifRowType *)); assert(buffer != NULL); for (i = 0; i < *height; i++) { buffer[i] = malloc(*width * sizeof(GifPixelType)); assert(buffer[i] != NULL); } if (data->file->Image.Interlace) { for (i = 0; i < 4; i++) for (j = interlace_offset[i]; j < *height; j += interlace_jump[i]) DGifGetLine(data->file, buffer[j], *width); } else { for (i = 0; i < *height; i++) DGifGetLine(data->file, buffer[i], *width); } break; case EXTENSION_RECORD_TYPE: { /* Skip extension blocks */ int ext_code; GifByteType *ext; assert(DGifGetExtension(data->file, &ext_code, &ext) != GIF_ERROR); while (ext != NULL) { assert(DGifGetExtensionNext(data->file, &ext) != GIF_ERROR); } } break; case TERMINATE_RECORD_TYPE: break; default: fprintf(stderr, "unknown record type in GIF file\n"); break; } } while (record_type != TERMINATE_RECORD_TYPE); colormap = (data->file->Image.ColorMap ? data->file->Image.ColorMap->Colors : data->file->SColorMap->Colors); data->rgb = (unsigned char*)malloc( (data->width* data->height * 3) ); assert(data->rgb != NULL); ptr = data->rgb; for (j = 0; j < *height; j++) { for (i = 0; i < *width; i++) { color_index = (int) buffer[j][i]; *ptr++ = (unsigned char) colormap[color_index].Red; *ptr++ = (unsigned char) colormap[color_index].Green; *ptr++ = (unsigned char) colormap[color_index].Blue; } free(buffer[j]); } free(buffer); assert(DGifCloseFile(data->file) == GIF_OK); return data; } void gif_read_lines (void *_data, unsigned char *lines, int num_lines) { gif_data_t *data = (gif_data_t*)_data; memcpy(lines, data->rgb, data->width * num_lines * 3); } void gif_free_data (void *_data) { gif_data_t *data = (gif_data_t*)_data; free(data->rgb); free(data); } metapixel-1.0.2/rwimg/rwpng.h0000644000127400012740000000234110537045432015436 0ustar schanischani/* -*- c -*- */ /* * rwpng.h * * rwimg * * Copyright (C) 1997-2004 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __RWPNG_H__ #define __RWPNG_H__ void* open_png_file_reading (const char *filename, int *width, int *height); void png_read_lines (void *data, unsigned char *lines, int num_lines); void png_free_reader_data (void *data); void* open_png_file_writing (const char *filename, int width, int height, int pixel_stride, int row_stride); void png_write_lines (void *data, unsigned char *lines, int num_lines); void png_free_writer_data (void *data); #endif metapixel-1.0.2/rwimg/Makefile0000644000127400012740000000041010537045432015563 0ustar schanischaniOBJS = readimage.o writeimage.o rwpng.o rwjpeg.o rwgif.o FORMATDEFS = -DRWIMG_PNG -DRWIMG_JPEG -DRWIMG_GIF all : librwimg.a librwimg.a : $(OBJS) ar rcu librwimg.a $(OBJS) %.o : %.c $(CC) $(CCOPTS) $(FORMATDEFS) -g -c $< clean : rm -f *~ $(OBJS) librwimg.a metapixel-1.0.2/rwimg/rwjpeg.h0000644000127400012740000000235410537045432015603 0ustar schanischani/* -*- c -*- */ /* * rwjpeg.h * * rwimg * * Copyright (C) 2000-2004 Mark Probst * Copyright (C) 2006 Xavier Martin * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __RWJPEG_H__ #define __RWJPEG_H__ void* open_jpeg_file_reading (const char *filename, int *width, int *height); void jpeg_read_lines (void *data, unsigned char *lines, int num_lines); void jpeg_free_reader_data (void *data); void* open_jpeg_file_writing (const char *filename, int width, int height); void jpeg_write_lines (void *data, unsigned char *lines, int num_lines); void jpeg_free_writer_data (void *data); #endif metapixel-1.0.2/rwimg/rwjpeg.c0000644000127400012740000000765410537045432015606 0ustar schanischani/* -*- c -*- */ /* * rwjpeg.c * * rwimg * * Copyright (C) 2000-2006 Mark Probst * Copyright (C) 2006 Xavier Martin * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include typedef struct { FILE *file; int decompress_started; struct jpeg_decompress_struct cinfo; struct jpeg_compress_struct cinfo2; struct jpeg_error_mgr jerr; } jpeg_data_t; void* open_jpeg_file_reading (const char *filename, int *width, int *height) { jpeg_data_t *data = (jpeg_data_t*)malloc(sizeof(jpeg_data_t)); assert(data != 0); data->file = fopen(filename, "rb"); assert(data->file != 0); data->cinfo.err = jpeg_std_error(&data->jerr); jpeg_create_decompress(&data->cinfo); jpeg_stdio_src(&data->cinfo, data->file); jpeg_read_header(&data->cinfo, TRUE); if (data->cinfo.num_components == 1) data->cinfo.out_color_space = JCS_GRAYSCALE; else if (data->cinfo.num_components == 3) data->cinfo.out_color_space = JCS_RGB; else assert(0); *width = data->cinfo.image_width; *height = data->cinfo.image_height; data->decompress_started = 0; return data; } void jpeg_read_lines (void *_data, unsigned char *lines, int num_lines) { jpeg_data_t *data = (jpeg_data_t*)_data; int row_stride, i; if (!data->decompress_started) { jpeg_start_decompress(&data->cinfo); data->decompress_started = 1; } row_stride = data->cinfo.image_width * 3; for (i = 0; i < num_lines; ++i) { unsigned char *scanline = lines + i * row_stride; jpeg_read_scanlines(&data->cinfo, &scanline, 1); if (data->cinfo.num_components == 1) { int j; for (j = data->cinfo.image_width - 1; j >= 0; --j) { unsigned char value = scanline[j]; int k; for (k = 0; k < 3; ++k) scanline[j * 3 + k] = value; } } } } void jpeg_free_reader_data (void *_data) { jpeg_data_t *data = (jpeg_data_t*)_data; if (data->decompress_started) jpeg_finish_decompress(&data->cinfo); jpeg_destroy_decompress(&data->cinfo); fclose(data->file); free(data); } void* open_jpeg_file_writing (const char *filename, int width, int height) { jpeg_data_t *data = (jpeg_data_t*)malloc(sizeof(jpeg_data_t)); assert(data != 0); data->file = fopen(filename, "wb"); assert(data->file != 0); data->cinfo2.err = jpeg_std_error(&data->jerr); jpeg_create_compress(&data->cinfo2); jpeg_stdio_dest(&data->cinfo2, data->file); data->cinfo2.image_width = width; data->cinfo2.image_height = height; data->cinfo2.input_components = 3; data->cinfo2.in_color_space = JCS_RGB; jpeg_set_defaults(&data->cinfo2); jpeg_start_compress(&data->cinfo2, TRUE); return data; } void jpeg_write_lines (void *_data, unsigned char *lines, int num_lines) { jpeg_data_t *data = (jpeg_data_t*)_data; JSAMPROW row_pointer[1]; int i; for ( i = 0; i < num_lines; ++i) { row_pointer[0] = &lines[ i * data->cinfo2.image_width * 3 ]; jpeg_write_scanlines(&data->cinfo2, row_pointer, 1); } } void jpeg_free_writer_data (void *_data) { jpeg_data_t *data = (jpeg_data_t*)_data; jpeg_finish_compress(&data->cinfo2); jpeg_destroy_compress(&data->cinfo2); fclose(data->file); free(data); } metapixel-1.0.2/convert.c0000644000127400012740000000503610537045432014633 0ustar schanischani/* -*- c -*- */ /* * convert.c * * metapixel * * Copyright (C) 2003-2004 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include "getopt.h" #include "lispreader.h" #include "metapixel.h" int main (int argc, char *argv[]) { int small_width = DEFAULT_WIDTH, small_height = DEFAULT_HEIGHT; while (1) { static struct option long_options[] = { { "width", required_argument, 0, 'w' }, { "height", required_argument, 0, 'h' }, { 0, 0, 0, 0 } }; int option, option_index; option = getopt_long(argc, argv, "w:h:", long_options, &option_index); if (option == -1) break; switch (option) { case 'w' : small_width = atoi(optarg); break; case 'h' : small_height = atoi(optarg); break; default : assert(0); } } printf("; -*- lisp -*-\n"); do { int i, channel; char filename[1024]; lisp_object_t *obj; float means[NUM_CHANNELS]; scanf("%s", filename); if (feof(stdin)) break; assert(strlen(filename) > 0); printf("(small-image "); obj = lisp_make_string(filename); lisp_dump(obj, stdout); lisp_free(obj); printf(" (size %d %d) ", small_width, small_height); for (channel = 0; channel < NUM_CHANNELS; ++channel) scanf("%f", &means[channel]); printf("(wavelet (means %f %f %f) (coeffs", means[0], means[1], means[2]); for (i = 0; i < NUM_COEFFS; ++i) { int index; scanf("%d", &index); printf(" %d", index); } printf(")) (subpixel"); for (channel = 0; channel < NUM_CHANNELS; ++channel) { static char *channel_names[NUM_CHANNELS] = { "y", "i", "q" }; printf(" (%s", channel_names[channel]); for (i = 0; i < NUM_SUBPIXELS; ++i) { int val; scanf("%d", &val); printf(" %d", val); } printf(")"); } printf("))\n"); } while (!feof(stdin)); return 0; } metapixel-1.0.2/lispreader.c0000644000127400012740000005526110537045432015312 0ustar schanischani/* * lispreader.c * * Copyright (C) 1998-2004 Mark Probst * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #define TOKEN_ERROR -1 #define TOKEN_EOF 0 #define TOKEN_OPEN_PAREN 1 #define TOKEN_CLOSE_PAREN 2 #define TOKEN_SYMBOL 3 #define TOKEN_STRING 4 #define TOKEN_INTEGER 5 #define TOKEN_REAL 6 #define TOKEN_PATTERN_OPEN_PAREN 7 #define TOKEN_DOT 8 #define TOKEN_TRUE 9 #define TOKEN_FALSE 10 #define MAX_TOKEN_LENGTH 8192 static char token_string[MAX_TOKEN_LENGTH + 1] = ""; static int token_length = 0; static char *mmap_token_start, *mmap_token_stop; static lisp_object_t end_marker = { LISP_TYPE_EOF }; static lisp_object_t error_object = { LISP_TYPE_PARSE_ERROR }; static lisp_object_t close_paren_marker = { LISP_TYPE_PARSE_ERROR }; static lisp_object_t dot_marker = { LISP_TYPE_PARSE_ERROR }; static void _token_clear (void) { token_string[0] = '\0'; token_length = 0; } static void _token_append (char c) { assert(token_length < MAX_TOKEN_LENGTH); token_string[token_length++] = c; token_string[token_length] = '\0'; } static void copy_mmapped_token (void) { token_length = mmap_token_stop - mmap_token_start; assert(token_length < MAX_TOKEN_LENGTH); memcpy(token_string, mmap_token_start, token_length); token_string[token_length] = '\0'; } static int _next_char (lisp_stream_t *stream) { switch (stream->type) { case LISP_STREAM_MMAP_FILE : case LISP_STREAM_STRING : assert(0); return EOF; case LISP_STREAM_FILE : return getc(stream->v.file); case LISP_STREAM_ANY: return stream->v.any.next_char(stream->v.any.data); } assert(0); return EOF; } static void _unget_char (char c, lisp_stream_t *stream) { switch (stream->type) { case LISP_STREAM_MMAP_FILE : case LISP_STREAM_STRING : assert(0); break; case LISP_STREAM_FILE : ungetc(c, stream->v.file); break; case LISP_STREAM_ANY: stream->v.any.unget_char(c, stream->v.any.data); break; default : assert(0); } } static int my_atoi (const char *start, const char *stop) { int value = 0; while (start < stop) { value = value * 10 + (*start - '0'); ++start; } return value; } #define SCAN_FUNC_NAME _scan_mmap #define SCAN_DECLS char *pos = stream->v.mmap.pos, *end = stream->v.mmap.end; #define NEXT_CHAR (pos == end ? EOF : *pos++) #define UNGET_CHAR(c) (--pos) #define TOKEN_START(o) (mmap_token_start = pos - (o)) #define TOKEN_APPEND(c) #define TOKEN_STOP (mmap_token_stop = pos) #define RETURN(t) ({ stream->v.mmap.pos = pos ; return (t); }) #include "lispscan.h" #undef SCAN_FUNC_NAME #undef SCAN_DECLS #undef NEXT_CHAR #undef UNGET_CHAR #undef TOKEN_START #undef TOKEN_APPEND #undef TOKEN_STOP #undef RETURN #define SCAN_FUNC_NAME _scan #define SCAN_DECLS #define NEXT_CHAR _next_char(stream) #define UNGET_CHAR(c) _unget_char((c), stream) #define TOKEN_START(o) _token_clear() #define TOKEN_APPEND(c) _token_append((c)) #define TOKEN_STOP #define RETURN(t) return (t) #include "lispscan.h" #undef SCAN_FUNC_NAME #undef SCAN_DECLS #undef NEXT_CHAR #undef UNGET_CHAR #undef TOKEN_START #undef TOKEN_APPEND #undef TOKEN_STOP #undef RETURN #define IS_STREAM_MMAPPED(s) ((s)->type <= LISP_LAST_MMAPPED_STREAM) #define SCAN(s) (IS_STREAM_MMAPPED((s)) ? _scan_mmap((s)) : _scan((s))) static lisp_object_t* lisp_object_alloc (allocator_t *allocator, int type) { lisp_object_t *obj = (lisp_object_t*)allocator_alloc(allocator, sizeof(lisp_object_t)); obj->type = type; return obj; } lisp_stream_t* lisp_stream_init_path (lisp_stream_t *stream, const char *path) { int fd; struct stat sb; size_t len; void *buf; fd = open(path, O_RDONLY, 0); if (fd == -1) return 0; if (fstat(fd, &sb) == -1) { close(fd); return 0; } len = sb.st_size; buf = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0); if (buf == (void*)-1) { FILE *file = fdopen(fd, "r"); if (file == 0) { close(fd); return 0; } else return lisp_stream_init_file(stream, file); } else { close(fd); stream->type = LISP_STREAM_MMAP_FILE; stream->v.mmap.buf = buf; stream->v.mmap.pos = buf; stream->v.mmap.end = buf + len; } return stream; } lisp_stream_t* lisp_stream_init_file (lisp_stream_t *stream, FILE *file) { stream->type = LISP_STREAM_FILE; stream->v.file = file; return stream; } lisp_stream_t* lisp_stream_init_string (lisp_stream_t *stream, char *buf) { stream->type = LISP_STREAM_STRING; stream->v.mmap.buf = buf; stream->v.mmap.end = buf + strlen(buf); stream->v.mmap.pos = buf; return stream; } lisp_stream_t* lisp_stream_init_any (lisp_stream_t *stream, void *data, int (*next_char) (void *data), void (*unget_char) (char c, void *data)) { assert(next_char != 0 && unget_char != 0); stream->type = LISP_STREAM_ANY; stream->v.any.data = data; stream->v.any.next_char= next_char; stream->v.any.unget_char = unget_char; return stream; } void lisp_stream_free_path (lisp_stream_t *stream) { assert(stream->type == LISP_STREAM_MMAP_FILE || stream->type == LISP_STREAM_FILE); if (stream->type == LISP_STREAM_MMAP_FILE) munmap(stream->v.mmap.buf, stream->v.mmap.end - stream->v.mmap.buf); else fclose(stream->v.file); } lisp_object_t* lisp_make_integer_with_allocator (allocator_t *allocator, int value) { lisp_object_t *obj = lisp_object_alloc(allocator, LISP_TYPE_INTEGER); obj->v.integer = value; return obj; } lisp_object_t* lisp_make_real_with_allocator (allocator_t *allocator, float value) { lisp_object_t *obj = lisp_object_alloc(allocator, LISP_TYPE_REAL); obj->v.real = value; return obj; } static lisp_object_t* lisp_make_symbol_with_allocator_internal (allocator_t *allocator, const char *str, size_t len) { lisp_object_t *obj = lisp_object_alloc(allocator, LISP_TYPE_SYMBOL); obj->v.string = allocator_alloc(allocator, len + 1); memcpy(obj->v.string, str, len + 1); obj->v.string[len] = '\0'; return obj; } lisp_object_t* lisp_make_symbol_with_allocator (allocator_t *allocator, const char *value) { return lisp_make_symbol_with_allocator_internal(allocator, value, strlen(value)); } lisp_object_t* lisp_make_string_with_allocator (allocator_t *allocator, const char *value) { lisp_object_t *obj = lisp_object_alloc(allocator, LISP_TYPE_STRING); obj->v.string = allocator_strdup(allocator, value); return obj; } lisp_object_t* lisp_make_cons_with_allocator (allocator_t *allocator, lisp_object_t *car, lisp_object_t *cdr) { lisp_object_t *obj = lisp_object_alloc(allocator, LISP_TYPE_CONS); obj->v.cons.car = car; obj->v.cons.cdr = cdr; return obj; } lisp_object_t* lisp_make_boolean_with_allocator (allocator_t *allocator, int value) { lisp_object_t *obj = lisp_object_alloc(allocator, LISP_TYPE_BOOLEAN); obj->v.integer = value ? 1 : 0; return obj; } lisp_object_t* lisp_make_integer (int value) { return lisp_make_integer_with_allocator(&malloc_allocator, value); } lisp_object_t* lisp_make_real (float value) { return lisp_make_real_with_allocator(&malloc_allocator, value); } lisp_object_t* lisp_make_symbol (const char *value) { return lisp_make_symbol_with_allocator(&malloc_allocator, value); } lisp_object_t* lisp_make_string (const char *value) { return lisp_make_string_with_allocator(&malloc_allocator, value); } lisp_object_t* lisp_make_cons (lisp_object_t *car, lisp_object_t *cdr) { return lisp_make_cons_with_allocator(&malloc_allocator, car, cdr); } lisp_object_t* lisp_make_boolean (int value) { return lisp_make_boolean_with_allocator(&malloc_allocator, value); } static lisp_object_t* lisp_make_pattern_cons_with_allocator (allocator_t *allocator, lisp_object_t *car, lisp_object_t *cdr) { lisp_object_t *obj = lisp_object_alloc(allocator, LISP_TYPE_PATTERN_CONS); obj->v.cons.car = car; obj->v.cons.cdr = cdr; return obj; } static lisp_object_t* lisp_make_pattern_var_with_allocator (allocator_t *allocator, int type, int index, lisp_object_t *sub) { lisp_object_t *obj = lisp_object_alloc(allocator, LISP_TYPE_PATTERN_VAR); obj->v.pattern.type = type; obj->v.pattern.index = index; obj->v.pattern.sub = sub; return obj; } lisp_object_t* lisp_read_with_allocator (allocator_t *allocator, lisp_stream_t *in) { int token = SCAN(in); lisp_object_t *obj = lisp_nil(); if (token == TOKEN_EOF) return &end_marker; switch (token) { case TOKEN_ERROR : return &error_object; case TOKEN_EOF : return &end_marker; case TOKEN_OPEN_PAREN : case TOKEN_PATTERN_OPEN_PAREN : { lisp_object_t *last = lisp_nil(), *car; do { car = lisp_read_with_allocator(allocator, in); if (car == &error_object || car == &end_marker) { lisp_free_with_allocator(allocator, obj); return &error_object; } else if (car == &dot_marker) { if (lisp_nil_p(last)) { lisp_free_with_allocator(allocator, obj); return &error_object; } car = lisp_read_with_allocator(allocator, in); if (car == &error_object || car == &end_marker) { lisp_free_with_allocator(allocator, obj); return car; } else { last->v.cons.cdr = car; if (SCAN(in) != TOKEN_CLOSE_PAREN) { lisp_free_with_allocator(allocator, obj); return &error_object; } car = &close_paren_marker; } } else if (car != &close_paren_marker) { if (lisp_nil_p(last)) obj = last = (token == TOKEN_OPEN_PAREN ? lisp_make_cons_with_allocator(allocator, car, lisp_nil()) : lisp_make_pattern_cons_with_allocator(allocator, car, lisp_nil())); else last = last->v.cons.cdr = lisp_make_cons_with_allocator(allocator, car, lisp_nil()); } } while (car != &close_paren_marker); } return obj; case TOKEN_CLOSE_PAREN : return &close_paren_marker; case TOKEN_SYMBOL : if (IS_STREAM_MMAPPED(in)) return lisp_make_symbol_with_allocator_internal(allocator, mmap_token_start, mmap_token_stop - mmap_token_start); else return lisp_make_symbol_with_allocator(allocator, token_string); case TOKEN_STRING : return lisp_make_string_with_allocator(allocator, token_string); case TOKEN_INTEGER : if (IS_STREAM_MMAPPED(in)) return lisp_make_integer_with_allocator(allocator, my_atoi(mmap_token_start, mmap_token_stop)); else return lisp_make_integer_with_allocator(allocator, atoi(token_string)); case TOKEN_REAL : if (IS_STREAM_MMAPPED(in)) copy_mmapped_token(); return lisp_make_real_with_allocator(allocator, (float)atof(token_string)); case TOKEN_DOT : return &dot_marker; case TOKEN_TRUE : return lisp_make_boolean_with_allocator(allocator, 1); case TOKEN_FALSE : return lisp_make_boolean_with_allocator(allocator, 0); } assert(0); return &error_object; } lisp_object_t* lisp_read (lisp_stream_t *in) { return lisp_read_with_allocator(&malloc_allocator, in); } void lisp_free_with_allocator (allocator_t *allocator, lisp_object_t *obj) { restart: if (obj == 0) return; switch (obj->type) { case LISP_TYPE_INTERNAL : case LISP_TYPE_PARSE_ERROR : case LISP_TYPE_EOF : return; case LISP_TYPE_SYMBOL : case LISP_TYPE_STRING : allocator_free(allocator, obj->v.string); break; case LISP_TYPE_CONS : case LISP_TYPE_PATTERN_CONS : /* If we just recursively free car and cdr we risk a stack overflow because lists may be nested arbitrarily deep. We can get rid of one recursive call with a tail call, but there's still one remaining. The solution is to flatten a recursive list until we can free the car without recursion. Then we free the cdr with a tail call. The transformation we perform on the list is this: ((a . b) . c) -> (a . (b . c)) */ if (!lisp_nil_p(obj->v.cons.car) && (lisp_type(obj->v.cons.car) == LISP_TYPE_CONS || lisp_type(obj->v.cons.car) == LISP_TYPE_PATTERN_CONS)) { /* this is the transformation */ lisp_object_t *car, *cdar; car = obj->v.cons.car; cdar = car->v.cons.cdr; car->v.cons.cdr = obj; obj->v.cons.car = cdar; obj = car; goto restart; } else { /* here we just free the car (which is not recursive), the cons itself and the cdr via a tail call. */ lisp_object_t *tmp; lisp_free_with_allocator(allocator, obj->v.cons.car); tmp = obj; obj = obj->v.cons.cdr; allocator_free(allocator, tmp); goto restart; } case LISP_TYPE_PATTERN_VAR : lisp_free_with_allocator(allocator, obj->v.pattern.sub); break; } allocator_free(allocator, obj); } void lisp_free (lisp_object_t *obj) { lisp_free_with_allocator(&malloc_allocator, obj); } lisp_object_t* lisp_read_from_string_with_allocator (allocator_t *allocator, const char *buf) { lisp_stream_t stream; lisp_stream_init_string(&stream, (char*)buf); return lisp_read_with_allocator(allocator, &stream); } lisp_object_t* lisp_read_from_string (const char *buf) { return lisp_read_from_string_with_allocator(&malloc_allocator, buf); } static int _compile_pattern (lisp_object_t **obj, int *index) { if (*obj == 0) return 1; switch (lisp_type(*obj)) { case LISP_TYPE_PATTERN_CONS : { struct { char *name; int type; } types[] = { { "any", LISP_PATTERN_ANY }, { "symbol", LISP_PATTERN_SYMBOL }, { "string", LISP_PATTERN_STRING }, { "integer", LISP_PATTERN_INTEGER }, { "real", LISP_PATTERN_REAL }, { "boolean", LISP_PATTERN_BOOLEAN }, { "list", LISP_PATTERN_LIST }, { "or", LISP_PATTERN_OR }, { "number", LISP_PATTERN_NUMBER }, { 0, 0 } }; char *type_name; int type = 0; /* makes gcc happy */ int i; lisp_object_t *pattern; if (lisp_type(lisp_car(*obj)) != LISP_TYPE_SYMBOL) return 0; type_name = lisp_symbol(lisp_car(*obj)); for (i = 0; types[i].name != 0; ++i) { if (strcmp(types[i].name, type_name) == 0) { type = types[i].type; break; } } if (types[i].name == 0) return 0; if (type != LISP_PATTERN_OR && lisp_cdr(*obj) != 0) return 0; pattern = lisp_make_pattern_var_with_allocator(&malloc_allocator, type, (*index)++, lisp_nil()); if (type == LISP_PATTERN_OR) { lisp_object_t *cdr = lisp_cdr(*obj); if (!_compile_pattern(&cdr, index)) { lisp_free(pattern); return 0; } pattern->v.pattern.sub = cdr; (*obj)->v.cons.cdr = lisp_nil(); } lisp_free(*obj); *obj = pattern; } break; case LISP_TYPE_CONS : if (!_compile_pattern(&(*obj)->v.cons.car, index)) return 0; if (!_compile_pattern(&(*obj)->v.cons.cdr, index)) return 0; break; } return 1; } int lisp_compile_pattern (lisp_object_t **obj, int *num_subs) { int index = 0; int result; result = _compile_pattern(obj, &index); if (result && num_subs != 0) *num_subs = index; return result; } static int _match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars); static int _match_pattern_var (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars) { assert(lisp_type(pattern) == LISP_TYPE_PATTERN_VAR); switch (pattern->v.pattern.type) { case LISP_PATTERN_ANY : break; case LISP_PATTERN_SYMBOL : if (obj == 0 || lisp_type(obj) != LISP_TYPE_SYMBOL) return 0; break; case LISP_PATTERN_STRING : if (obj == 0 || lisp_type(obj) != LISP_TYPE_STRING) return 0; break; case LISP_PATTERN_INTEGER : if (obj == 0 || lisp_type(obj) != LISP_TYPE_INTEGER) return 0; break; case LISP_PATTERN_REAL : if (obj == 0 || lisp_type(obj) != LISP_TYPE_REAL) return 0; break; case LISP_PATTERN_BOOLEAN : if (obj == 0 || lisp_type(obj) != LISP_TYPE_BOOLEAN) return 0; break; case LISP_PATTERN_LIST : if (obj == 0 || lisp_type(obj) != LISP_TYPE_CONS) return 0; break; case LISP_PATTERN_OR : { lisp_object_t *sub; int matched = 0; for (sub = pattern->v.pattern.sub; sub != 0; sub = lisp_cdr(sub)) { assert(lisp_type(sub) == LISP_TYPE_CONS); if (_match_pattern(lisp_car(sub), obj, vars)) matched = 1; } if (!matched) return 0; } break; case LISP_PATTERN_NUMBER : if (obj == 0 || (lisp_type(obj) != LISP_TYPE_INTEGER && lisp_type(obj) != LISP_TYPE_REAL)) return 0; break; default : assert(0); } if (vars != 0) vars[pattern->v.pattern.index] = obj; return 1; } static int _match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars) { if (pattern == 0) return obj == 0; if (obj == 0) return 0; if (lisp_type(pattern) == LISP_TYPE_PATTERN_VAR) return _match_pattern_var(pattern, obj, vars); if (lisp_type(pattern) != lisp_type(obj)) return 0; switch (lisp_type(pattern)) { case LISP_TYPE_SYMBOL : return strcmp(lisp_symbol(pattern), lisp_symbol(obj)) == 0; case LISP_TYPE_STRING : return strcmp(lisp_string(pattern), lisp_string(obj)) == 0; case LISP_TYPE_INTEGER : return lisp_integer(pattern) == lisp_integer(obj); case LISP_TYPE_REAL : return lisp_real(pattern) == lisp_real(obj); case LISP_TYPE_CONS : { int result1, result2; result1 = _match_pattern(lisp_car(pattern), lisp_car(obj), vars); result2 = _match_pattern(lisp_cdr(pattern), lisp_cdr(obj), vars); return result1 && result2; } break; default : assert(0); } return 0; } int lisp_match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars, int num_subs) { int i; if (vars != 0) for (i = 0; i < num_subs; ++i) vars[i] = &error_object; return _match_pattern(pattern, obj, vars); } int lisp_match_string (const char *pattern_string, lisp_object_t *obj, lisp_object_t **vars) { lisp_object_t *pattern; int result; int num_subs; pattern = lisp_read_from_string(pattern_string); if (pattern != 0 && (lisp_type(pattern) == LISP_TYPE_EOF || lisp_type(pattern) == LISP_TYPE_PARSE_ERROR)) return 0; if (!lisp_compile_pattern(&pattern, &num_subs)) { lisp_free(pattern); return 0; } result = lisp_match_pattern(pattern, obj, vars, num_subs); lisp_free(pattern); return result; } int lisp_type (lisp_object_t *obj) { if (obj == 0) return LISP_TYPE_NIL; return obj->type; } int lisp_integer (lisp_object_t *obj) { assert(obj->type == LISP_TYPE_INTEGER); return obj->v.integer; } char* lisp_symbol (lisp_object_t *obj) { assert(obj->type == LISP_TYPE_SYMBOL); return obj->v.string; } char* lisp_string (lisp_object_t *obj) { assert(obj->type == LISP_TYPE_STRING); return obj->v.string; } int lisp_boolean (lisp_object_t *obj) { assert(obj->type == LISP_TYPE_BOOLEAN); return obj->v.integer; } float lisp_real (lisp_object_t *obj) { assert(obj->type == LISP_TYPE_REAL || obj->type == LISP_TYPE_INTEGER); if (obj->type == LISP_TYPE_INTEGER) return obj->v.integer; return obj->v.real; } lisp_object_t* lisp_car (lisp_object_t *obj) { assert(obj->type == LISP_TYPE_CONS || obj->type == LISP_TYPE_PATTERN_CONS); return obj->v.cons.car; } lisp_object_t* lisp_cdr (lisp_object_t *obj) { assert(obj->type == LISP_TYPE_CONS || obj->type == LISP_TYPE_PATTERN_CONS); return obj->v.cons.cdr; } lisp_object_t* lisp_cxr (lisp_object_t *obj, const char *x) { int i; for (i = strlen(x) - 1; i >= 0; --i) if (x[i] == 'a') obj = lisp_car(obj); else if (x[i] == 'd') obj = lisp_cdr(obj); else assert(0); return obj; } int lisp_list_length (lisp_object_t *obj) { int length = 0; while (obj != 0) { assert(obj->type == LISP_TYPE_CONS || obj->type == LISP_TYPE_PATTERN_CONS); ++length; obj = obj->v.cons.cdr; } return length; } lisp_object_t* lisp_list_nth_cdr (lisp_object_t *obj, int index) { while (index > 0) { assert(obj != 0); assert(obj->type == LISP_TYPE_CONS || obj->type == LISP_TYPE_PATTERN_CONS); --index; obj = obj->v.cons.cdr; } return obj; } lisp_object_t* lisp_list_nth (lisp_object_t *obj, int index) { obj = lisp_list_nth_cdr(obj, index); assert(obj != 0); return obj->v.cons.car; } void lisp_dump (lisp_object_t *obj, FILE *out) { if (obj == 0) { fprintf(out, "()"); return; } switch (lisp_type(obj)) { case LISP_TYPE_EOF : fputs("#", out); break; case LISP_TYPE_PARSE_ERROR : fputs("#", out); break; case LISP_TYPE_INTEGER : fprintf(out, "%d", lisp_integer(obj)); break; case LISP_TYPE_REAL : fprintf(out, "%f", lisp_real(obj)); break; case LISP_TYPE_SYMBOL : fputs(lisp_symbol(obj), out); break; case LISP_TYPE_STRING : { char *p; fputc('"', out); for (p = lisp_string(obj); *p != 0; ++p) { if (*p == '"' || *p == '\\') fputc('\\', out); fputc(*p, out); } fputc('"', out); } break; case LISP_TYPE_CONS : case LISP_TYPE_PATTERN_CONS : fputs(lisp_type(obj) == LISP_TYPE_CONS ? "(" : "#?(", out); while (obj != 0) { lisp_dump(lisp_car(obj), out); obj = lisp_cdr(obj); if (obj != 0) { if (lisp_type(obj) != LISP_TYPE_CONS && lisp_type(obj) != LISP_TYPE_PATTERN_CONS) { fputs(" . ", out); lisp_dump(obj, out); break; } else fputc(' ', out); } } fputc(')', out); break; case LISP_TYPE_BOOLEAN : if (lisp_boolean(obj)) fputs("#t", out); else fputs("#f", out); break; default : assert(0); } } metapixel-1.0.2/getopt.c0000644000127400012740000005704510537045432014464 0ustar schanischani/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. 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, 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO #define _NO_PROTO #endif #ifdef HAVE_CONFIG_H #include #endif #if !defined (__STDC__) || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include #if defined (_LIBC) || defined (HAVE_UNISTD_H) #include #endif #endif /* GNU C library. */ #ifdef VMS #include #if HAVE_STRING_H - 0 #include #endif #endif #ifdef WIN32 /* It's not Unix, really. See? Capital letters. */ #include #define getpid() GetCurrentProcessId() #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ #ifdef HAVE_LIBINTL_H # include # define _(msgid) gettext (msgid) #else # define _(msgid) (msgid) #endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* XXX 1003.2 says this must be 1 before any call. */ int optind = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include #define my_index strchr #else /* Avoid depending on library functions or files whose names are inconsistent. */ char *getenv (); static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ #if !defined (__STDC__) || !__STDC__ /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); #endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ static const char *nonoption_flags; static int nonoption_flags_len; /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined (__STDC__) && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined (__STDC__) && __STDC__ static const char *_getopt_initialize (const char *); #endif static const char * _getopt_initialize (optstring) const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind = 1; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; if (posixly_correct == NULL) { /* Bash 2.0 puts a special variable in the environment for each command it runs, specifying which ARGV elements are the results of file name wildcard expansion and therefore should not be considered as options. */ char var[100]; sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ()); nonoption_flags = getenv (var); if (nonoption_flags == NULL) nonoption_flags_len = 0; else nonoption_flags_len = strlen (nonoption_flags); } return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns `EOF'. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { optarg = NULL; if (optind == 0) { optstring = _getopt_initialize (optstring); optind = 1; /* Don't scan ARGV[0], the program name. */ } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. */ #define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && nonoption_flags[optind] == '1')) if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return EOF; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return EOF; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; #ifdef lint /* Suppress `used before initialized' warning. */ indfound = 0; #endif /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if (nameend - nextchar == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == EOF) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ metapixel-1.0.2/metapixel.spec0000644000127400012740000000400310537045432015644 0ustar schanischani# $Id$ %define _bindir /usr/bin %define _mandir /usr/share/man Summary: Metapixel Photomosaic Generator Name: metapixel Version: 1.0.2 Release: 1 License: GNU General Public License Group: Applications/Multimedia URL: http://www.complang.tuwien.ac.at/schani/metapixel/ Source: http://www.complang.tuwien.ac.at/schani/%{name}/%{name}-%{version}.tar.gz #Buildroot: %{_tmppath}/%{name}-%{version}-root Requires: libpng Requires: libjpeg Requires: giflib Requires: perl BuildRequires: libpng-devel BuildRequires: libjpeg-devel BuildRequires: giflib-devel BuildRequires: make %description Metapixel is a program for generating photomosaics. It can generate classical photomosaics, in which the source image is viewed as a matrix of equally sized rectangles for each of which a matching image is substituted, as well as collage-style photomosaics, in which rectangular parts of the source image at arbitrary positions (i.e. not aligned to a matrix) are substituted by matching images. %prep %setup rm -rf $RPM_BUILD_ROOT %build %{__make} %install install -d $RPM_BUILD_ROOT/%{_bindir} install -d $RPM_BUILD_ROOT/%{_mandir}/man1 install metapixel $RPM_BUILD_ROOT/%{_bindir}/metapixel install metapixel-prepare $RPM_BUILD_ROOT/%{_bindir}/metapixel-prepare install metapixel-imagesize $RPM_BUILD_ROOT/%{_bindir}/metapixel-imagesize install metapixel-sizesort $RPM_BUILD_ROOT/%{_bindir}/metapixel-sizesort install metapixel.1 $RPM_BUILD_ROOT/%{_mandir}/man1/metapixel.1 gzip $RPM_BUILD_ROOT/%{_mandir}/man1/metapixel.1 %clean rm -rf %{buildroot} %files %defattr(-, root, root) %doc NEWS COPYING README %{_mandir}/man1/metapixel.1.gz %{_bindir}/metapixel-prepare %{_bindir}/metapixel %{_bindir}/metapixel-imagesize %{_bindir}/metapixel-sizesort %changelog * Sun Dec 10 2006 Mark Probst 1.0.2 - Update to 1.0.2 * Sun Feb 19 2006 Mark Probst 1.0.1 - Update to 1.0.1, added imagesize and sizesort * Thu Jul 28 2005 A. Pense 1.0.0 - First creation of spec file, source rpm metapixel-1.0.2/vector.c0000644000127400012740000002141110537045432014450 0ustar schanischani/* -*- c -*- */ /* * vector.c * * metapixel * * Copyright (C) 1997-1999 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "vector.h" Vector2D MakeVector2D (double x, double y) { Vector2D vec = { x, y }; return vec; } Vector2D* InitVector2D (Vector2D *vec, double x, double y) { vec->x = x; vec->y = y; return vec; } Vector2D* CopyVector2D (Vector2D *dest, const Vector2D *src) { dest->x = src->x; dest->y = src->y; return dest; } double Abs2D (const Vector2D *v) { return sqrt(v->x * v->x + v->y * v->y); } Vector2D* AddVectors2D (Vector2D *dest, const Vector2D *vec1, const Vector2D *vec2) { dest->x = vec1->x + vec2->x; dest->y = vec1->y + vec2->y; return dest; } Vector2D* SubVectors2D (Vector2D *dest, const Vector2D *vec1, const Vector2D *vec2) { dest->x = vec1->x - vec2->x; dest->y = vec1->y - vec2->y; return dest; } Vector2D* MultScalar2D (Vector2D *dest, double d, const Vector2D *vec) { dest->x = d * vec->x; dest->y = d * vec->y; return dest; } Vector2D* MultVectors2D (Vector2D *dest, const Vector2D *vec1, const Vector2D *vec2) { dest->x = vec1->x * vec2->x; dest->y = vec1->y * vec2->y; return dest; } Vector2D* Unity2D (Vector2D *dest, Vector2D *vec) { return MultScalar2D(dest, 1 / Abs2D(vec), vec); } Vector2D* Rectangular2DToPolar (Vector2D *dest, const Vector2D *src) { dest->y = sqrt(src->x * src->x + src->y * src->y); if (src->y == 0.0) { if (src->x > 0) dest->x = 0.0; else dest->x = M_PI; } else { dest->x = atan(src->y / src->x); if (src->x < 0.0) dest->x = M_PI + dest->x; } dest->x = fmod(dest->x, 2 * M_PI); return dest; } Vector2D* Polar2DToRectangular (Vector2D *dest, const Vector2D *src) { dest->x = cos(src->x) * src->y; dest->y = sin(src->x) * src->y; return dest; } Vector3D MakeVector3D (double x, double y, double z) { Vector3D vec = { x, y, z }; return vec; } Vector3D* InitVector3D (Vector3D *vec, double x, double y, double z) { vec->x = x; vec->y = y; vec->z = z; return vec; } Vector3D* CopyVector3D (Vector3D *dest, const Vector3D *src) { dest->x = src->x; dest->y = src->y; dest->z = src->z; return dest; } double Abs3D (const Vector3D *v) { return sqrt(v->x * v->x + v->y * v->y + v->z * v->z); } Vector3D* AddVectors3D (Vector3D *vec, const Vector3D *vec1, const Vector3D *vec2) { vec->x = vec1->x + vec2->x; vec->y = vec1->y + vec2->y; vec->z = vec1->z + vec2->z; return vec; } Vector3D* SubVectors3D (Vector3D *vec, const Vector3D *vec1, const Vector3D *vec2) { vec->x = vec1->x - vec2->x; vec->y = vec1->y - vec2->y; vec->z = vec1->z - vec2->z; return vec; } Vector3D* MultScalar3D (Vector3D *dest, double d, const Vector3D *vec) { dest->x = d * vec->x; dest->y = d * vec->y; dest->z = d * vec->z; return dest; } Vector3D* MultVectors3D (Vector3D *vec, const Vector3D *vec1, const Vector3D *vec2) { vec->x = vec1->x * vec2->x; vec->y = vec1->y * vec2->y; vec->z = vec1->z * vec2->z; return vec; } double DotProduct3D (const Vector3D *vec1, const Vector3D *vec2) { return vec1->x * vec2->x + vec1->y * vec2->y + vec1->z * vec2->z; } Vector3D* CrossProduct3D (Vector3D *vec, const Vector3D *vec1, const Vector3D *vec2) { vec->x = vec1->y * vec2->z - vec2->y * vec1->z; vec->y = vec1->z * vec2->x - vec2->z * vec1->x; vec->z = vec1->x * vec2->y - vec2->x * vec1->y; return vec; } Vector3D* Unity3D (Vector3D *dest, const Vector3D *vec) { return MultScalar3D(dest, 1 / Abs3D(vec), vec); } Matrix3D* InitMatrix3D (Matrix3D *mat) { int x, y; for (x = 0; x < 3; ++x) for (y = 0; y < 3; ++y) (*mat)[x][y] = 0.0; return mat; } Matrix3D* CopyMatrix3D (Matrix3D *dest, const Matrix3D *src) { int x, y; for (x = 0; x < 3; ++x) for (y = 0; y < 3; ++y) (*dest)[x][y] = (*src)[x][y]; return dest; } Vector3D* MultMatrixVector3D (Vector3D *dest, const Matrix3D *mat, const Vector3D *vec) { dest->x = (*mat)[0][0] * vec->x + (*mat)[0][1] * vec->y + (*mat)[0][2] * vec->z; dest->y = (*mat)[1][0] * vec->x + (*mat)[1][1] * vec->y + (*mat)[1][2] * vec->z; dest->z = (*mat)[2][0] * vec->x + (*mat)[2][1] * vec->y + (*mat)[2][2] * vec->z; return dest; } Matrix4D* InitMatrix4D (Matrix4D *mat) { int x, y; for (x = 0; x < 4; ++x) for (y = 0; y < 4; ++y) (*mat)[x][y] = 0.0; return mat; } Matrix4D* CopyMatrix4D (Matrix4D *dest, const Matrix4D *src) { int x, y; for (x = 0; x < 4; ++x) for (y = 0; y < 4; ++y) (*dest)[x][y] = (*src)[x][y]; return dest; } Matrix4D* MultMatrix4D (Matrix4D *dest, const Matrix4D *mat1, const Matrix4D *mat2) { int x, y, i; for (x = 0; x < 4; ++x) for (y = 0; y < 4; ++y) { (*dest)[x][y] = 0.0; for (i = 0; i < 4; ++i) (*dest)[x][y] += (*mat1)[x][i] * (*mat2)[i][y]; } return dest; } Vector3D* ApplyTransformation (Vector3D *dest, const Matrix4D *mat, const Vector3D *vec) { dest->x = (*mat)[0][0] * vec->x + (*mat)[0][1] * vec->y + (*mat)[0][2] * vec->z + (*mat)[0][3]; dest->y = (*mat)[1][0] * vec->x + (*mat)[1][1] * vec->y + (*mat)[1][2] * vec->z + (*mat)[1][3]; dest->z = (*mat)[2][0] * vec->x + (*mat)[2][1] * vec->y + (*mat)[2][2] * vec->z + (*mat)[2][3]; return dest; } Matrix4D* InitTranslationMatrix (Matrix4D *mat, double x, double y, double z) { int i; InitMatrix4D(mat); for (i = 0; i < 4; ++i) (*mat)[i][i] = 1.0; (*mat)[0][3] = x; (*mat)[1][3] = y; (*mat)[2][3] = z; return mat; } Matrix4D* InitXRotationMatrix (Matrix4D *mat, double theta) { double sine = sin(theta), cosine = cos(theta); InitMatrix4D(mat); (*mat)[0][0] = 1.0; (*mat)[3][3] = 1.0; (*mat)[1][1] = cosine; (*mat)[1][2] = -sine; (*mat)[2][1] = sine; (*mat)[2][2] = cosine; return mat; } Matrix4D* InitYRotationMatrix (Matrix4D *mat, double theta) { double sine = sin(theta), cosine = cos(theta); InitMatrix4D(mat); (*mat)[1][1] = 1.0; (*mat)[3][3] = 1.0; (*mat)[0][0] = cosine; (*mat)[0][2] = sine; (*mat)[2][0] = -sine; (*mat)[2][2] = cosine; return mat; } Matrix4D* InitZRotationMatrix (Matrix4D *mat, double theta) { double sine = sin(theta), cosine = cos(theta); InitMatrix4D(mat); (*mat)[2][2] = 1.0; (*mat)[3][3] = 1.0; (*mat)[0][0] = cosine; (*mat)[0][1] = -sine; (*mat)[1][0] = sine; (*mat)[1][1] = cosine; return mat; } Matrix4x3* InitMatrix4x3 (Matrix4x3 *mat) { int i, j; for (i = 0; i < 4; ++i) for (j = 0; j < 3; ++j) (*mat)[i][j] = 0.0; return mat; } Matrix4x3* MakeMatrix4x3 (Matrix4x3 *dest, const Vector3D *vec1, const Vector3D *vec2, const Vector3D *vec3, const Vector3D *vec4) { (*dest)[0][0] = vec1->x; (*dest)[0][1] = vec1->y; (*dest)[0][2] = vec1->z; (*dest)[1][0] = vec2->x; (*dest)[1][1] = vec2->y; (*dest)[1][2] = vec2->z; (*dest)[2][0] = vec3->x; (*dest)[2][1] = vec3->y; (*dest)[2][2] = vec3->z; (*dest)[3][0] = vec4->x; (*dest)[3][1] = vec4->y; (*dest)[3][2] = vec4->z; return dest; } Matrix4x3* CopyMatrix4x3 (Matrix4x3 *dest, const Matrix4x3 *src) { int i, j; for (i = 0; i < 4; ++i) for (j = 0; j < 3; ++j) (*dest)[i][j] = (*src)[i][j]; return dest; } Matrix4x3* MultMatrix4x3 (Matrix4x3 *dest, const Matrix4D *mat1, const Matrix4x3 *mat2) { int i, j, k; for (i = 0; i < 4; ++i) for (j = 0; j < 3; ++j) { (*dest)[i][j] = 0.0; for (k = 0; k < 4; ++k) (*dest)[i][j] += (*mat1)[i][k] * (*mat2)[k][j]; } return dest; } Vector3D* MultVector4DMatrix4x3 (Vector3D *dest, const Vector4D *vec, const Matrix4x3 *mat) { dest->x = (*vec)[0] * (*mat)[0][0] + (*vec)[1] * (*mat)[1][0] + (*vec)[2] * (*mat)[2][0] + (*vec)[3] * (*mat)[3][0]; dest->y = (*vec)[0] * (*mat)[0][1] + (*vec)[1] * (*mat)[1][1] + (*vec)[2] * (*mat)[2][1] + (*vec)[3] * (*mat)[3][1]; dest->z = (*vec)[0] * (*mat)[0][2] + (*vec)[1] * (*mat)[1][2] + (*vec)[2] * (*mat)[2][2] + (*vec)[3] * (*mat)[3][2]; return dest; } metapixel-1.0.2/lispreader.h0000644000127400012740000001260610537045432015313 0ustar schanischani/* * lispreader.h * * Copyright (C) 1998-2004 Mark Probst * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __LISPREADER_H__ #define __LISPREADER_H__ #include #include #define LISP_STREAM_MMAP_FILE 1 #define LISP_STREAM_STRING 2 #define LISP_STREAM_FILE 3 #define LISP_STREAM_ANY 4 #define LISP_LAST_MMAPPED_STREAM LISP_STREAM_STRING #define LISP_TYPE_INTERNAL -3 #define LISP_TYPE_PARSE_ERROR -2 #define LISP_TYPE_EOF -1 #define LISP_TYPE_NIL 0 #define LISP_TYPE_SYMBOL 1 #define LISP_TYPE_INTEGER 2 #define LISP_TYPE_STRING 3 #define LISP_TYPE_REAL 4 #define LISP_TYPE_CONS 5 #define LISP_TYPE_PATTERN_CONS 6 #define LISP_TYPE_BOOLEAN 7 #define LISP_TYPE_PATTERN_VAR 8 #define LISP_PATTERN_ANY 1 #define LISP_PATTERN_SYMBOL 2 #define LISP_PATTERN_STRING 3 #define LISP_PATTERN_INTEGER 4 #define LISP_PATTERN_REAL 5 #define LISP_PATTERN_BOOLEAN 6 #define LISP_PATTERN_LIST 7 #define LISP_PATTERN_OR 8 #define LISP_PATTERN_NUMBER 9 typedef struct { int type; union { FILE *file; struct { char *buf; char *end; char *pos; } mmap; struct { void *data; int (*next_char) (void *data); void (*unget_char) (char c, void *data); } any; } v; } lisp_stream_t; typedef struct _lisp_object_t lisp_object_t; struct _lisp_object_t { int type; union { struct { struct _lisp_object_t *car; struct _lisp_object_t *cdr; } cons; char *string; int integer; float real; struct { int type; int index; struct _lisp_object_t *sub; } pattern; } v; }; lisp_stream_t* lisp_stream_init_path (lisp_stream_t *stream, const char *path); lisp_stream_t* lisp_stream_init_file (lisp_stream_t *stream, FILE *file); lisp_stream_t* lisp_stream_init_string (lisp_stream_t *stream, char *buf); lisp_stream_t* lisp_stream_init_any (lisp_stream_t *stream, void *data, int (*next_char) (void *data), void (*unget_char) (char c, void *data)); void lisp_stream_free_path (lisp_stream_t *stream); lisp_object_t* lisp_read_with_allocator (allocator_t *allocator, lisp_stream_t *in); lisp_object_t* lisp_read (lisp_stream_t *in); void lisp_free_with_allocator (allocator_t *allocator, lisp_object_t *obj); void lisp_free (lisp_object_t *obj); lisp_object_t* lisp_read_from_string_with_allocator (allocator_t *allocator, const char *buf); lisp_object_t* lisp_read_from_string (const char *buf); int lisp_compile_pattern (lisp_object_t **obj, int *num_subs); int lisp_match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars, int num_subs); int lisp_match_string (const char *pattern_string, lisp_object_t *obj, lisp_object_t **vars); int lisp_type (lisp_object_t *obj); int lisp_integer (lisp_object_t *obj); float lisp_real (lisp_object_t *obj); char* lisp_symbol (lisp_object_t *obj); char* lisp_string (lisp_object_t *obj); int lisp_boolean (lisp_object_t *obj); lisp_object_t* lisp_car (lisp_object_t *obj); lisp_object_t* lisp_cdr (lisp_object_t *obj); lisp_object_t* lisp_cxr (lisp_object_t *obj, const char *x); lisp_object_t* lisp_make_integer_with_allocator (allocator_t *allocator, int value); lisp_object_t* lisp_make_real_with_allocator (allocator_t *allocator, float value); lisp_object_t* lisp_make_symbol_with_allocator (allocator_t *allocator, const char *value); lisp_object_t* lisp_make_string_with_allocator (allocator_t *allocator, const char *value); lisp_object_t* lisp_make_cons_with_allocator (allocator_t *allocator, lisp_object_t *car, lisp_object_t *cdr); lisp_object_t* lisp_make_boolean_with_allocator (allocator_t *allocator, int value); lisp_object_t* lisp_make_integer (int value); lisp_object_t* lisp_make_real (float value); lisp_object_t* lisp_make_symbol (const char *value); lisp_object_t* lisp_make_string (const char *value); lisp_object_t* lisp_make_cons (lisp_object_t *car, lisp_object_t *cdr); lisp_object_t* lisp_make_boolean (int value); int lisp_list_length (lisp_object_t *obj); lisp_object_t* lisp_list_nth_cdr (lisp_object_t *obj, int index); lisp_object_t* lisp_list_nth (lisp_object_t *obj, int index); void lisp_dump (lisp_object_t *obj, FILE *out); #define lisp_nil() ((lisp_object_t*)0) #define lisp_nil_p(obj) (obj == 0) #define lisp_integer_p(obj) (lisp_type((obj)) == LISP_TYPE_INTEGER) #define lisp_real_p(obj) (lisp_type((obj)) == LISP_TYPE_REAL) #define lisp_symbol_p(obj) (lisp_type((obj)) == LISP_TYPE_SYMBOL) #define lisp_string_p(obj) (lisp_type((obj)) == LISP_TYPE_STRING) #define lisp_cons_p(obj) (lisp_type((obj)) == LISP_TYPE_CONS) #define lisp_boolean_p(obj) (lisp_type((obj)) == LISP_TYPE_BOOLEAN) #endif metapixel-1.0.2/imagesize.c0000644000127400012740000000212110537045432015120 0ustar schanischani/* -*- c -*- */ /* * imagesize.c * * metapixel * * Copyright (C) 2003 Mark Probst * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include "readimage.h" int main (int argc, char *argv[]) { image_reader_t *reader; assert(argc == 2); reader = open_image_reading(argv[1]); if (reader == 0) printf("0 0\n"); else printf("%d %d\n", reader->width, reader->height); return 0; }