Hi,

Some times ago I've encoutered the same problem. In my case I've needed
a program to build thumbnails in a small cgi script and found no small
solutions. Installing imagemagick and all his dependancy on the web
server was against my religion ;-) so I've build a small resizer.

Before I say anything other be warned that this program was quickly
written, and the used only for a few weeks. So this is far from optimal
and may have a lot of bugs. I've never reused this code so I've never
improved it. It stay in my directory of project "that I must finish a
day a publish...."

This program only resize jpeg file but it was written with hability to
load a save other file formats so adding png will be easy, just add
loadin and saving of png, and select the good loader/saver depending on
file extention.

In order to produce an output of size (w,h), resizing is done in two
steps :
- First an the source picture is resample in a picture of size (5*w,5*h)
  using nearest neighboor.
- Second the final image is computed from this using a convolution
  matrix of size 5x5.

This allow good quality result with easy coding, but it require a lot of
memory and time if destination picture is huge. But keep in mind that it
was originaly written to produce thumbnails....

It only require the jpeglib. To compile it you can use something like :
        cc -W -Wall -ansi -pedantic -O3 -ljpeg -o apr apr.c

So use it at your own risk...

Tom

On Fri, Jun 13, 2008 at 10:43:46AM +0200, markus schnalke wrote:
> Hoi community,
> 
> I feel the need for a image resize program that matches the
> Unix and suckless philosophy.
> Currently I'm using ImageMagick, which is just fine, if it is already
> installed. But I was shocked, when I had to install it on a clean
> system: I has that many dependencies!
> The only thing I wanted was a program to resize images and I had to
> install about 80 megabyte!
> 
> Does anyone know a small program that can resize JPEG and PNG images?
> 
> 
> meillo



-- 
Thomas Lavergne                    "Entia non sunt multiplicanda praeter
                                     necessitatem." (Guillaume d'Ockham)
[EMAIL PROTECTED]                            http://oniros.org
/* Copyright (c) 2008 Thomas Lavergne <[EMAIL PROTECTED]>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <jpeglib.h>

typedef unsigned char byte;
typedef struct image_s {
        unsigned   width;
        unsigned   height;
        unsigned   quality;
        byte     **data;
} image_t;

static image_t *img_new(unsigned width, unsigned height) {
        image_t *img;
        unsigned size, i;

        if (width == 0 || height == 0)
                return NULL;

        size = sizeof(byte *) * height + 3 * width * height;
        img = (image_t *)malloc(sizeof(image_t) + size);
        if (img == NULL)
                return NULL;

        img->data = (byte **)((byte *)img + sizeof(image_t));
        for (i = 0; i < height; ++i)
                img->data[i] = (byte *)(img->data + height) + i * 3 * width;

        img->width = width;
        img->height = height;

        return img;
}

static void img_free(image_t *img) {
        free(img);
}

static image_t *jpg_load(const char *filename) {
        struct jpeg_decompress_struct dinfo;
        struct jpeg_error_mgr jerr;
        FILE *file;
        image_t *img;

        file = fopen(filename, "rb");
        if (file == NULL)
                return NULL;

        dinfo.err = jpeg_std_error(&jerr);
        jpeg_create_decompress(&dinfo);
        jpeg_stdio_src(&dinfo, file);
        jpeg_read_header(&dinfo, TRUE);
        jpeg_start_decompress(&dinfo);

        img = img_new(dinfo.output_width, dinfo.output_height);
        if (img == NULL) {
                jpeg_destroy_decompress(&dinfo);
                fclose(file);
                return NULL;
        }

        img->quality = dinfo.quant_tbl_ptrs[0]->quantval[6];
        if (img->quality > 51)
                img->quality = (50 * 51 + img->quality / 2) / img->quality;
        else
                img->quality = (5126 - 50 * img->quality) / 51;

        while (dinfo.output_scanline < img->height)
                jpeg_read_scanlines(&dinfo, img->data + dinfo.output_scanline, 
16);

        jpeg_finish_decompress(&dinfo);
        jpeg_destroy_decompress(&dinfo);
        fclose(file);

        return img;
}

static int jpg_save(image_t *img, const char *filename) {
        struct jpeg_compress_struct cinfo;
        struct jpeg_error_mgr jerr;
        FILE *file;

        file = fopen(filename, "wb");
        if (file == NULL)
                return 0;

        cinfo.err = jpeg_std_error(&jerr);
        jpeg_create_compress(&cinfo);
        jpeg_stdio_dest(&cinfo, file);
        cinfo.image_width = img->width;
        cinfo.image_height = img->height;
        cinfo.input_components = 3;
        cinfo.in_color_space = JCS_RGB;

        jpeg_set_defaults(&cinfo);
        jpeg_set_quality(&cinfo, img->quality, TRUE);
        jpeg_start_compress(&cinfo, TRUE);
        jpeg_write_scanlines(&cinfo, img->data, img->height);
        jpeg_finish_compress(&cinfo);
        jpeg_destroy_compress(&cinfo);
        fclose(file);

        return 1;
}

static image_t *img_load(const char *filename) {
        return jpg_load(filename);
}

static int img_save(image_t *img, const char *filename) {
        return jpg_save(img, filename);
}

static image_t *img_resample(image_t *src, unsigned width, unsigned height) {
        image_t *dst;
        unsigned *offset_x;
        unsigned *offset_y;
        unsigned i, x, y;

        dst = img_new(width, height);
        if (dst == NULL)
                return NULL;

        offset_x = (unsigned *)malloc(sizeof(long) * dst->width);
        offset_y = (unsigned *)malloc(sizeof(long) * dst->height);
        if (offset_x == NULL || offset_y == NULL) {
                free(offset_x);
                free(offset_y);
                free(dst);
        }

        for (i = 0; i < dst->width; ++i)
                offset_x[i] = ((double)i + 0.5) * src->width / dst->width;
        for (i = 0; i < dst->height; ++i)
                offset_y[i] = ((double)i + 0.5) * src->height / dst->height;

        for (y = 0; y < dst->height; ++y) {
                byte *src_line = src->data[offset_y[y]];
                byte *dst_line = dst->data[y];
                for (x = 0; x < dst->width; ++x) {
                        dst_line[3 * x + 0] = src_line[3 * offset_x[x] + 0];
                        dst_line[3 * x + 1] = src_line[3 * offset_x[x] + 1];
                        dst_line[3 * x + 2] = src_line[3 * offset_x[x] + 2];
                }
        }

        free(offset_x);
        free(offset_y);

        return dst;
}

static image_t *img_resize(image_t *src, unsigned width, unsigned height) {
        int coefs[25]= {1, 1, 2, 1, 1, 1, 2, 4, 2, 1, 2, 4, 8, 4, 2, 1, 2, 4,
                        2, 1, 1, 1, 2, 1, 1};
        image_t *tmp, *dst;
        unsigned x, y;

        tmp = img_resample(src, width * 5, height * 5);
        if (tmp == NULL)
                return NULL;
        dst = img_new(width, height);
        if (dst == NULL) {
                free(tmp);
                return NULL;
        }
        dst->quality = src->quality;

        for (y = 0; y < dst->height; ++y) {
                for (x = 0; x < dst->width; ++x) {
                        int c, r = 0, g = 0, b = 0;
                        for (c = 0; c < 25; ++c) {
                                int tx = 5 * x + c % 5;
                                int ty = 5 * y + c / 5;
                                r += tmp->data[ty][3 * tx + 0] * coefs[c];
                                g += tmp->data[ty][3 * tx + 1] * coefs[c];
                                b += tmp->data[ty][3 * tx + 2] * coefs[c];
                        }
                        dst->data[y][3 * x + 0] = r / 52;
                        dst->data[y][3 * x + 1] = g / 52;
                        dst->data[y][3 * x + 2] = b / 52;
                }
        }

        free(tmp);
        return dst;
}

static int decodesize(const char *str, unsigned *width, unsigned *height) {
        unsigned p = 0, w = 0, h = 0;
        if (str == NULL || width == NULL || height == NULL)
                return 0;
        while (isdigit(str[p]))
                w = w * 10 + (str[p++] - '0');
        if (str[p++] == 'x')
                while (isdigit(str[p]))
                        h = h * 10 + (str[p++] - '0');
        *width = w;
        *height = h;
        return 1;
}

int main(int argc, char *argv[]) {
        unsigned width, height;
        double ratio;
        image_t *src, *dst;

        if (argc <= 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
                fprintf(stderr, "usage: apr -h | --help\n");
                fprintf(stderr, "       apr input output width\n");
                fprintf(stderr, "       apr input output widthxheight\n");
                return EXIT_SUCCESS;
        }

        if (argc != 4) {
                fprintf(stderr, "error: wrong number of arguments\n");
                return EXIT_FAILURE;
        }

        src = img_load(argv[1]);
        if (!decodesize(argv[3], &width, &height)) {
                fprintf(stderr, "error: invalid size format");
                return EXIT_FAILURE;
        }
        
        ratio = (double)src->width / src->height;
        if (height == 0 || width / ratio < height)
                height = width / ratio;
        else
                width = height * ratio;

        dst = img_resize(src, width, height);
        img_save(dst, argv[2]);

        img_free(src);
        img_free(dst);

        return EXIT_SUCCESS;
}

Reply via email to