From 599a8e20c02fa48bab5102d15fab79dd6b631c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Mart=C3=ADn?= Date: Sun, 7 Sep 2003 21:39:37 +0000 Subject: Updating to last version of pdp 0.12.2 svn path=/trunk/externals/pdp/; revision=940 --- system/type/pdp_image.c | 580 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 580 insertions(+) create mode 100644 system/type/pdp_image.c (limited to 'system/type/pdp_image.c') diff --git a/system/type/pdp_image.c b/system/type/pdp_image.c new file mode 100644 index 0000000..1aa9763 --- /dev/null +++ b/system/type/pdp_image.c @@ -0,0 +1,580 @@ +/* + * Pure Data Packet system implementation. : 16 bit image packet implementation + * Copyright (c) by Tom Schouten + * + * 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. + * + */ + +/* + This file contains methods for the image packets + pdp_packet_new_* methods are several image packet constructors + pdp_type_* are image type checkers & converters + +*/ + +#include "pdp.h" +#include "pdp_internals.h" +#include + + +/* the class object */ +static t_pdp_class* image_class; + + + +/* check dimensions */ +static void _checkdim(u32 width, u32 height){ + if ((pdp_imageproc_legalwidth(width) != width) || + (pdp_imageproc_legalheight(height) != height)){ + post("WARNING: request to create image packet with illegal dimensions %d x %d", width, height); + } +} + + +/* image packet constructors */ +int pdp_packet_new_image_YCrCb(u32 w, u32 h) +{ + t_pdp *header; + t_image *image; + int packet; + + + u32 size = w*h; + u32 totalnbpixels = size + (size >> 1); + u32 packet_size = totalnbpixels << 1; + + _checkdim(w,h); + + packet = pdp_packet_new(PDP_IMAGE, packet_size); + header = pdp_packet_header(packet); + image = pdp_packet_image_info(packet); + if (!header) return -1; + + image->encoding = PDP_IMAGE_YV12; + image->width = w; + image->height = h; + header->desc = pdp_packet_image_get_description(packet); + header->theclass = image_class; + + return packet; +} + +int pdp_packet_new_image_grey(u32 w, u32 h) +{ + t_pdp *header; + t_image *image; + int packet; + + + u32 size = w*h; + u32 totalnbpixels = size; + u32 packet_size = totalnbpixels << 1; + + _checkdim(w,h); + + packet = pdp_packet_new(PDP_IMAGE, packet_size); + header = pdp_packet_header(packet); + image = pdp_packet_image_info(packet); + if (!header) return -1; + + image->encoding = PDP_IMAGE_GREY; + image->width = w; + image->height = h; + header->desc = pdp_packet_image_get_description(packet); + header->theclass = image_class; + + return packet; +} + +int pdp_packet_new_image_mchp(u32 w, u32 h, u32 d) +{ + t_pdp *header; + t_image *image; + int packet; + + + u32 size = w*h*d; + u32 totalnbpixels = size; + u32 packet_size = totalnbpixels << 1; + + _checkdim(w,h); + + packet = pdp_packet_new(PDP_IMAGE, packet_size); + header = pdp_packet_header(packet); + image = pdp_packet_image_info(packet); + if (!header) return -1; + + + image->encoding = PDP_IMAGE_MCHP; + image->width = w; + image->height = h; + image->depth = d; + header->desc = pdp_packet_image_get_description(packet); + header->theclass = image_class; + + return packet; +} + + +int pdp_packet_new_image(u32 type, u32 w, u32 h) +{ + switch (type){ + case PDP_IMAGE_YV12: + return pdp_packet_new_image_YCrCb(w,h); + case PDP_IMAGE_GREY: + return pdp_packet_new_image_grey(w,h); + default: + return -1; + } +} + + +/****************** packet type checking and conversion methods ********************/ + + + +/* check if two image packets are allocated and of the same type */ +int pdp_packet_image_compat(int packet0, int packet1) +{ + t_pdp *header0 = pdp_packet_header(packet0); + t_pdp *header1 = pdp_packet_header(packet1); + t_image *image0 = pdp_packet_image_info(packet0); + t_image *image1 = pdp_packet_image_info(packet1); + + + if (!(pdp_packet_compat(packet0, packet1))) return 0; + if (header0->type != PDP_IMAGE){ + //post("pdp_type_compat_image: not a PDP_IMAGE"); + return 0; + } + if (image0->encoding != image1->encoding){ + //post("pdp_type_compat_image: encodings differ"); + return 0; + } + if (image0->width != image1->width){ + //post("pdp_type_compat_image: image withs differ"); + return 0; + } + if (image0->height != image1->height){ + //post("pdp_type_compat_image: image heights differ"); + return 0; + } + return 1; +} + +/* check if packet is a valid image packet */ +int pdp_packet_image_isvalid(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + if (!header) return 0; + if (PDP_IMAGE != header->type) return 0; + if ((PDP_IMAGE_YV12 != image->encoding) + && (PDP_IMAGE_GREY != image->encoding) + && (PDP_IMAGE_MCHP != image->encoding)) return 0; + + return 1; + +} + +/* set the channel mask for the image */ +void pdp_packet_image_set_chanmask(int packet, unsigned int chanmask) +{ + if (pdp_packet_image_isvalid(packet)) pdp_packet_image_info(packet)->chanmask = chanmask; + +} + + +t_image *pdp_packet_image_info(int packet) +{ + return (t_image *)pdp_packet_subheader(packet); +} + + +t_pdp_symbol *pdp_packet_image_get_description(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + char description[1024]; + char *c = description; + int encoding; + + if (!header) return pdp_gensym("invalid"); + else if (!header->desc){ + /* if description is not defined, try to reconstruct it (for backwards compat) */ + if (header->type == PDP_IMAGE){ + c += sprintf(c, "image"); + encoding = image->encoding; + switch(encoding){ + case PDP_IMAGE_YV12: c += sprintf(c, "/YCrCb"); break; + case PDP_IMAGE_GREY: c += sprintf(c, "/grey"); break; + case PDP_IMAGE_MCHP: c += sprintf(c, "/multi"); break; + default: + c += sprintf(c, "/unknown"); goto exit; + } + if (encoding == PDP_IMAGE_MCHP){ + c += sprintf(c, "/%dx%dx%d", + image->width, + image->height, + image->depth); + } + else { + c += sprintf(c, "/%dx%d", + image->width, + image->height); + } + + exit: + return pdp_gensym(description); + } + else return pdp_gensym("unknown"); + } + else return header->desc; +} + + + + + +/* IMAGE PACKAGE CONVERSION ROUTINES */ + +/* note: these are internal: no extra checking is done + it is assumed the packets are of correct type (the type template associated with the conversion program) */ + +// image/YCrCb/* -> image/grey/* +// image/multi/* -> image/grey/* (only first channel) +static int _pdp_packet_image_convert_YCrCb_to_grey(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + int w = image->width; + int h = image->height; + int p = pdp_packet_new_image_grey(w,h); + if (p == -1) return p; + memcpy(pdp_packet_data(p), pdp_packet_data(packet), 2*w*h); + return p; +} + +// image/grey/* -> image/YCrCb/* +static int _pdp_packet_image_convert_grey_to_YCrCb(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + int w = image->width; + int h = image->height; + int p = pdp_packet_new_image_YCrCb(w,h); + int y_bytes = 2*w*h; + void *data; + if (p == -1) return p; + data = pdp_packet_data(p); + memcpy(data, pdp_packet_data(packet), y_bytes); + memset(data+y_bytes, 0, y_bytes >> 1); + return p; +} + +// image/grey/* -> image/multi/* +static int _pdp_packet_image_convert_grey_to_multi(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + int w = image->width; + int h = image->height; + int p = pdp_packet_new_image_mchp(w,h,1); + int y_bytes = 2*w*h; + void *data; + if (p == -1) return p; + data = pdp_packet_data(p); + memcpy(data, pdp_packet_data(packet), y_bytes); + return p; +} + +// image/multi/* -> image/YCrCb/* (only first 3 channels) +static int _pdp_packet_image_convert_multi_to_YCrCb(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + s16 *data, *newdata; + + /* get info */ + int w = image->width; + int h = image->height; + int d = image->depth; + int plane_size = w*h; + + /* create new packet */ + int newpacket = pdp_packet_new_image_YCrCb(w, h); + if (-1 == newpacket) return -1; + + data = pdp_packet_data(packet); + newdata = pdp_packet_data(newpacket); + + /* copy channel 0 */ + memcpy(newdata, data, plane_size<<1); + newdata += plane_size; + data += plane_size; + + /* copy channel 1 */ + if (d >= 1) pdp_resample_halve(data, newdata, w, h); + else memset(newdata, 0, plane_size >> 1); + data += plane_size; + newdata += (plane_size >> 2); + + + /* copy channel 2 */ + if (d >= 2) pdp_resample_halve(data, newdata, w, h); + else memset(newdata, 0, plane_size >> 1); + + return newpacket; + +} + +// image/YCrCb/* -> image/multi/* +static int _pdp_packet_image_convert_YCrCb_to_multi(int packet, t_pdp_symbol *dest_template) +{ + t_pdp *header = pdp_packet_header(packet); + t_image *image = pdp_packet_image_info(packet); + s16 *data, *newdata; + + /* get info */ + int w = image->width; + int h = image->height; + int plane_size = w*h; + + /* create new packet */ + int newpacket = pdp_packet_new_image_mchp(w, h, 3); + if (-1 == newpacket) return -1; + + data = pdp_packet_data(packet); + newdata = pdp_packet_data(newpacket); + + /* copy channel 0 */ + memcpy(newdata, data, plane_size<<1); + newdata += plane_size; + data += plane_size; + w >>= 1; + h >>= 1; + + /* copy channel 1 */ + pdp_resample_double(data, newdata, w, h); + data += (plane_size >> 2); + newdata += plane_size; + + /* copy channel 2 */ + pdp_resample_double(data, newdata, w, h); + + return newpacket; + +} + +static void _pdp_description_get_dims(t_pdp_symbol *template, int *w, int *h, int *d) +{ + char *c = template->s_name; + // get requested dimensions + *w = 0; + *h = 0; + *d = 0; + while (*c++ != '/'); + while (*c++ != '/'); + sscanf(c, "%dx%dx%d", w, h, d); + +} + +// resample image/YCrCb/* +static int _pdp_packet_image_convert_resample_YCrCb(int packet, t_pdp_symbol *dest_template) +{ + int quality = 1; + int dst_w, dst_h, dummy; + int new_packet; + unsigned int src_size, src_voffset, src_uoffset; + unsigned int dst_size, dst_voffset, dst_uoffset; + t_pdp *header0 = pdp_packet_header(packet); + t_image *image0 = pdp_packet_image_info(packet); + unsigned int src_w = image0->width; + unsigned int src_h = image0->height; + short int *src_image = (short int *)pdp_packet_data(packet); + short int *dst_image; + _pdp_description_get_dims(dest_template, &dst_w, &dst_h, &dummy); + new_packet = pdp_packet_new_image_YCrCb(dst_w, dst_h); + if (-1 == new_packet) return -1; + dst_image = (short int*)pdp_packet_data(new_packet); + src_size = src_w*src_h; + src_voffset = src_size; + src_uoffset = src_size + (src_size>>2); + dst_size = dst_w*dst_h; + dst_voffset = dst_size; + dst_uoffset = dst_size + (dst_size>>2); + if (quality){ + pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h); + pdp_resample_scale_bilin(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + pdp_resample_scale_bilin(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + } + else{ + pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h); + pdp_resample_scale_nn(src_image+src_voffset, dst_image+dst_voffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + pdp_resample_scale_nn(src_image+src_uoffset, dst_image+dst_uoffset, src_w>>1, src_h>>1, dst_w>>1, dst_h>>1); + } + return new_packet; +} + +// resample image/grey/* and image/multi/* +static int _pdp_packet_image_convert_resample_multi(int packet, t_pdp_symbol *dest_template) +{ + int quality = 1; + int dst_w, dst_h, depth; + int new_packet; + unsigned int src_size; + unsigned int dst_size; + t_pdp *header0 = pdp_packet_header(packet); + t_image *image0 = pdp_packet_image_info(packet); + unsigned int src_w = image0->width; + unsigned int src_h = image0->height; + short int *src_image = (short int *)pdp_packet_data(packet); + short int *dst_image; + _pdp_description_get_dims(dest_template, &dst_w, &dst_h, &depth); + + if (depth == 0){ + depth = 1; + new_packet = pdp_packet_new_image_grey(dst_w, dst_h); + } + else { + new_packet = pdp_packet_new_image_mchp(dst_w, dst_h, depth); + } + if (-1 == new_packet) return -1; + + dst_image = (short int*)pdp_packet_data(new_packet); + + src_size = src_w*src_h; + dst_size = dst_w*dst_h; + while (depth--){ + if (quality){ + pdp_resample_scale_bilin(src_image, dst_image, src_w, src_h, dst_w, dst_h); + } + else{ + pdp_resample_scale_nn(src_image, dst_image, src_w, src_h, dst_w, dst_h); + } + src_image += src_size; + dst_image += dst_size; + } + + return new_packet; +} + +static int _pdp_packet_image_convert_fallback(int packet, t_pdp_symbol *dest_template) +{ + post("can't convert image type %s to %s", + pdp_packet_get_description(packet)->s_name, dest_template->s_name); + + return -1; +} + + + +/* the expensive factory method */ +static int pdp_image_factory(t_pdp_symbol *type) +{ + t_pdp_list *l; + t_pdp_symbol *s; + int t; + int w = 0; + int h = 0; + int d = 0; + int p = -1; + int n = 0; + int m = 0; + char *garbage = 0; + + //post("creating:"); + //post("%s", type->s_name); + + l = pdp_type_to_list(type); + s = pdp_list_pop(l).w_symbol; // first element is "image" + s = pdp_list_pop(l).w_symbol; + + /* get image type */ + if (s == pdp_gensym("grey")) t = PDP_IMAGE_GREY; + else if (s == pdp_gensym("YCrCb")) t = PDP_IMAGE_YV12; + else if (s == pdp_gensym("multi")) t = PDP_IMAGE_MCHP; + else goto exit; + + /* get image dimensions and create image */ + s = pdp_list_pop(l).w_symbol; + switch (t){ + case PDP_IMAGE_MCHP: + m = sscanf(s->s_name, "%dx%dx%d", &w, &h, &d); + p = pdp_packet_new_image_mchp(w,h,d); + break; + default: + sscanf(s->s_name, "%dx%d", &w, &h); + p = pdp_packet_new_image(t,w,h); + break; + } + if (p != -1){ + t_pdp *h = pdp_packet_header(p); + /* if type is not exact, delete the packet */ + if (type != h->desc) { + pdp_packet_delete(p); + p = -1; + } + } + exit: + pdp_list_free(l); + return p; +} + + + +void pdp_image_words_setup(t_pdp_class *c); + +void pdp_image_setup(void) +{ + t_pdp_conversion_program *program; + + /* setup the class object */ + image_class = pdp_class_new(pdp_gensym("image/*/*"), pdp_image_factory); + + /* setup image words */ + pdp_image_words_setup(image_class); + + + /* setup conversion programs */ + program = pdp_conversion_program_new(_pdp_packet_image_convert_YCrCb_to_grey, 0); + pdp_type_register_conversion(pdp_gensym("image/YCrCb/*"), pdp_gensym("image/grey/*"), program); + pdp_type_register_conversion(pdp_gensym("image/multi/*"), pdp_gensym("image/grey/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_grey_to_YCrCb, 0); + pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("image/YCrCb/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_grey_to_multi, 0); + pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("image/multi/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_multi_to_YCrCb, 0); + pdp_type_register_conversion(pdp_gensym("image/multi/*"), pdp_gensym("image/YCrCb/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_YCrCb_to_multi, 0); + pdp_type_register_conversion(pdp_gensym("image/YCrCb/*"), pdp_gensym("image/multi/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_resample_YCrCb, 0); + pdp_type_register_conversion(pdp_gensym("image/YCrCb/*"), pdp_gensym("image/YCrCb/*"), program); + + program = pdp_conversion_program_new(_pdp_packet_image_convert_resample_multi, 0); + pdp_type_register_conversion(pdp_gensym("image/multi/*"), pdp_gensym("image/multi/*"), program); + pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("image/grey/*"), program); + + /* catch-all fallback */ + program = pdp_conversion_program_new(_pdp_packet_image_convert_fallback, 0); + pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("image/*/*"), program); + +} -- cgit v1.2.1