X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libqscale.c;h=b784294def3eedb9f4210bd187675b56dee71393;hb=115192a9fe4206be3bbe897daf0e5fc3e2561fe8;hp=c02aa1a58ee685471f2a0fa31157341ea363432c;hpb=6afad16d3da6c38b615271d4126c71e6ce5a9f1e;p=qscale diff --git a/libqscale.c b/libqscale.c index c02aa1a..b784294 100644 --- a/libqscale.c +++ b/libqscale.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "libqscale.h" @@ -171,12 +172,39 @@ static double lanczos_tap(double x) return sinc(x*M_PI) * sinc(x*M_PI / 3.0); } +static double mitchell_tap(double x) +{ + const double b = 1.0 / 3.0; + const double c = 1.0 / 3.0; + const double p0 = ( 6.0 - 2.0*b ) / 6.0; + const double p2 = (-18.0 + 12.0*b + 6.0*c) / 6.0; + const double p3 = ( 12.0 - 9.0*b - 6.0*c) / 6.0; + const double q0 = ( 8.0*b + 24.0*c) / 6.0; + const double q1 = ( - 12.0*b - 48.0*c) / 6.0; + const double q2 = ( 6.0*b + 30.0*c) / 6.0; + const double q3 = ( - b - 6.0*c) / 6.0; + + if (x < -2.0) { + return 0.0; + } else if (x < -1.0) { + return q0 - x * (q1 - x * (q2 - x * q3)); + } else if (x < 0.0) { + return p0 + x * x * (p2 - x * p3); + } else if (x < 1.0) { + return p0 + x * x * (p2 + x * p3); + } else if (x < 2.0) { + return q0 + x * (q1 + x * (q2 + x * q3)); + } else { + return 0.0; + } +} + struct pix_desc { unsigned start, end; unsigned startcoeff; }; -static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsigned nw, unsigned sstride, unsigned dstride) +static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsigned nw, unsigned sstride, unsigned dstride, enum qscale_scaling_filter scaling_filter) { struct pix_desc *pd = (struct pix_desc *)malloc(nw * sizeof(struct pix_desc)); int size_coeffs = 8; @@ -184,7 +212,13 @@ static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsi int num_coeffs = 0; int x, y; double sf = (double)w / (double)nw; - double support = (w > nw) ? (3.0 * sf) : (3.0 / sf); + double support; + + if (scaling_filter == LANCZOS) { + support = (w > nw) ? (3.0 * sf) : (3.0 / sf); + } else { /* Mitchell */ + support = (w > nw) ? (2.0 * sf) : (2.0 / sf); + } /* calculate the filter */ for (x = 0; x < nw; ++x) { @@ -221,7 +255,12 @@ static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsi for (sx = start; sx <= end; ++sx) { double nd = (w > nw) ? (sx/sf - x) : (sx - x*sf); - double f = lanczos_tap(nd); + double f; + if (scaling_filter == LANCZOS) { + f = lanczos_tap(nd); + } else { /* Mitchell */ + f = mitchell_tap(nd); + } if (num_coeffs == size_coeffs) { size_coeffs <<= 1; coeffs = (float *)realloc(coeffs, size_coeffs * sizeof(float)); @@ -299,7 +338,7 @@ static void hscale(float *pix, unsigned char *npix, unsigned w, unsigned h, unsi } } -static void vscale(unsigned char *pix, float *npix, unsigned w, unsigned h, unsigned nh, unsigned dstride) +static void vscale(unsigned char *pix, float *npix, unsigned w, unsigned h, unsigned nh, unsigned dstride, enum qscale_scaling_filter scaling_filter) { struct pix_desc *pd = (struct pix_desc *)malloc(nh * sizeof(struct pix_desc)); int size_coeffs = 8; @@ -307,7 +346,13 @@ static void vscale(unsigned char *pix, float *npix, unsigned w, unsigned h, unsi int num_coeffs = 0; int x, y, sy; double sf = (double)h / (double)nh; - double support = (h > nh) ? (3.0 * sf) : (3.0 / sf); + double support; + + if (scaling_filter == LANCZOS) { + support = (h > nh) ? (3.0 * sf) : (3.0 / sf); + } else { /* Mitchell */ + support = (h > nh) ? (2.0 * sf) : (2.0 / sf); + } /* calculate the filter */ for (y = 0; y < nh; ++y) { @@ -328,7 +373,12 @@ static void vscale(unsigned char *pix, float *npix, unsigned w, unsigned h, unsi for (sy = start; sy <= end; ++sy) { double nd = (h > nh) ? (sy/sf - y) : (sy - y*sf); - double f = lanczos_tap(nd); + double f; + if (scaling_filter == LANCZOS) { + f = lanczos_tap(nd); + } else { /* Mitchell */ + f = mitchell_tap(nd); + } if (num_coeffs == size_coeffs) { size_coeffs <<= 1; coeffs = (float *)realloc(coeffs, size_coeffs * sizeof(float)); @@ -479,6 +529,36 @@ static void vscale(unsigned char *pix, float *npix, unsigned w, unsigned h, unsi } } +qscale_img *qscale_clone(const qscale_img *img) +{ + qscale_img *dst = (qscale_img *)malloc(sizeof(qscale_img)); + if (dst == NULL) { + return NULL; + } + + *dst = *img; + + unsigned dstride0 = (dst->w0 + DCTSIZE-1) & ~(DCTSIZE-1); + unsigned dstride1 = (dst->w1 + DCTSIZE-1) & ~(DCTSIZE-1); + unsigned dstride2 = (dst->w2 + DCTSIZE-1) & ~(DCTSIZE-1); + + /* FIXME: handle out-of-memory gracefully */ + { + dst->data_y = (unsigned char *)malloc(dst->h0 * dstride0); + memcpy(dst->data_y, img->data_y, dst->h0 * dstride0); + } + { + dst->data_cb = (unsigned char *)malloc(dst->h1 * dstride1); + memcpy(dst->data_cb, img->data_cb, dst->h1 * dstride1); + } + { + dst->data_cr = (unsigned char *)malloc(dst->h2 * dstride2); + memcpy(dst->data_cr, img->data_cr, dst->h2 * dstride2); + } + + return dst; +} + qscale_img *qscale_scale(qscale_img *src, unsigned width, unsigned height, unsigned samp_h0, unsigned samp_v0, unsigned samp_h1, unsigned samp_v1, unsigned samp_h2, unsigned samp_v2, enum qscale_scaling_filter scaling_filter) { qscale_img *dst = (qscale_img *)malloc(sizeof(qscale_img)); @@ -531,23 +611,23 @@ qscale_img *qscale_scale(qscale_img *src, unsigned width, unsigned height, unsig /* FIXME: handle out-of-memory gracefully */ { float *npix = (float*)memalign(16, sstride0 * dst->h0 * sizeof(float)); - vscale(src->data_y, npix, sstride0, src->h0, dst->h0, sstride0); + vscale(src->data_y, npix, sstride0, src->h0, dst->h0, sstride0, scaling_filter); dst->data_y = (unsigned char *)malloc(dst->h0 * dstride0); - hscale(npix, dst->data_y, src->w0, dst->h0, dst->w0, sstride0, dstride0); + hscale(npix, dst->data_y, src->w0, dst->h0, dst->w0, sstride0, dstride0, scaling_filter); free(npix); } { float *npix = (float*)memalign(16, sstride1 * dst->h1 * sizeof(float)); - vscale(src->data_cr, npix, sstride1, src->h1, dst->h1, sstride1); + vscale(src->data_cr, npix, sstride1, src->h1, dst->h1, sstride1, scaling_filter); dst->data_cr = (unsigned char *)malloc(dst->h1 * dstride1); - hscale(npix, dst->data_cr, src->w1, dst->h1, dst->w1, sstride1, dstride1); + hscale(npix, dst->data_cr, src->w1, dst->h1, dst->w1, sstride1, dstride1, scaling_filter); free(npix); } { float *npix = (float*)memalign(16, sstride2 * dst->h2 * sizeof(float)); - vscale(src->data_cb, npix, sstride2, src->h2, dst->h2, sstride2); + vscale(src->data_cb, npix, sstride2, src->h2, dst->h2, sstride2, scaling_filter); dst->data_cb = (unsigned char *)malloc(dst->h2 * dstride2); - hscale(npix, dst->data_cb, src->w2, dst->h2, dst->w2, sstride2, dstride2); + hscale(npix, dst->data_cb, src->w2, dst->h2, dst->w2, sstride2, dstride2, scaling_filter); free(npix); } @@ -577,6 +657,11 @@ int qscale_save_jpeg_to_stdio(const qscale_img *img, FILE *file, unsigned jpeg_q cinfo.input_components = 3; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, jpeg_quality, FALSE); + + if (jpeg_mode == PROGRESSIVE) { + jpeg_simple_progression(&cinfo); + } + cinfo.image_width = img->width; cinfo.image_height = img->height; cinfo.raw_data_in = TRUE;