Ejemplo n.º 1
0
static int
attach_blob( VipsImage *im, const char *field, void *data, int data_length )
{
    char *data_copy;

    /* Only use the first one.
     */
    if( vips_image_get_typeof( im, field ) ) {
#ifdef DEBUG
        printf( "attach_blob: second %s block, ignoring\n", field );
#endif /*DEBUG*/

        return( 0 );
    }

#ifdef DEBUG
    printf( "attach_blob: attaching %d bytes of %s\n", data_length, field );
#endif /*DEBUG*/

    /* Always attach a copy of the unparsed exif data.
     */
    if( !(data_copy = vips_malloc( NULL, data_length )) )
        return( -1 );
    memcpy( data_copy, data, data_length );
    vips_image_set_blob( im, field,
                         (VipsCallbackFn) vips_free, data_copy, data_length );

    return( 0 );
}
Ejemplo n.º 2
0
/* Make a char* from GSList of GValue. Each GValue should be a ref_string.
 * free the result. Empty list -> "", not NULL. Join strings with '\n'.
 */
char *
vips__gslist_gvalue_get( const GSList *list )
{
	const GSList *p;
	size_t length;
	char *all;
	char *q;

	/* Need to estimate length first.
	 */
	length = 0;
	for( p = list; p; p = p->next ) {
		GValue *value = (GValue *) p->data;
		size_t l2;

		g_assert( G_VALUE_TYPE( value ) == VIPS_TYPE_REF_STRING );

		/* +1 for the newline we will add for each item.
		 */
		(void) vips_value_get_ref_string( value, &l2 );
		length += l2 + 1;
	}

	if( length == 0 )
		return( NULL );

	/* More than 10MB of history? Madness!
	 */
	g_assert( length < 10 * 1024 * 1024 );

	/* +1 for '\0'.
	 */
	if( !(all = vips_malloc( NULL, length + 1 )) )
		return( NULL );

	q = all;
	for( p = list; p; p = p->next ) {
		GValue *value = (GValue *) p->data;
		size_t l2;

		strcpy( q, vips_value_get_ref_string( value, &l2 ) );
		q += l2;
		strcpy( q, "\n" );
		q += 1;
	}

	g_assert( (size_t) (q - all) == length );

	return( all );
}
Ejemplo n.º 3
0
/* Decode base64 back to binary in a malloc'd buffer. NULL on error.
 */
unsigned char *
vips__b64_decode( const char *buffer, size_t *data_length )
{
	const size_t buffer_length = strlen( buffer );

	/* Worst case.
	 */
	const size_t output_data_length = buffer_length * 3 / 4;

	unsigned char *data;
	unsigned char *p;
	unsigned int bits;
	int nbits;
	size_t i;

	if( output_data_length > 1024 * 1024 ) {
		/* We shouldn't really be used for large amounts of data.
		 */
		vips_error( "vips__b64_decode", "%s", _( "too much data" ) );
		return( NULL );
	}

	if( !(data = vips_malloc( NULL, output_data_length )) )
		return( NULL );

	p = data;
	bits = 0;
	nbits = 0;

	for( i = 0; i < buffer_length; i++ ) {
		unsigned int val;

		if( (val = b64_index[(int) buffer[i]]) != XX ) {
			bits <<= 6;
			bits |= val;
			nbits += 6;

			if( nbits >= 8 ) {
				*p++ = (bits >> (nbits - 8)) & 0xff;
				nbits -= 8;
			}
		}
Ejemplo n.º 4
0
static int
read_header( Read *read, VipsImage *out )
{
	vips_image_init_fields( out,
		read->width, read->height,
		read->config.input.has_alpha ? 4 : 3,
		VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
		VIPS_INTERPRETATION_sRGB,
		1.0, 1.0 );

	vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );

#ifdef HAVE_LIBWEBPMUX
{
	WebPData bitstream;
	WebPMux *mux;
	int i;

	/* We have to parse the whole file again to get the metadata out.
	 *
	 * Don't make parse failure an error. We don't want to refuse to read
	 * any pixels because of some malformed metadata.
	 */
	bitstream.bytes = read->data;
	bitstream.size = read->length;
	if( !(mux = WebPMuxCreate( &bitstream, 0 )) ) {
		vips_warn( "webp", "%s", _( "unable to read image metadata" ) ); 
		return( 0 ); 
	}

	for( i = 0; i < vips__n_webp_names; i++ ) { 
		const char *vips = vips__webp_names[i].vips;
		const char *webp = vips__webp_names[i].webp;

		WebPData data;

		if( WebPMuxGetChunk( mux, webp, &data ) == WEBP_MUX_OK ) { 
			void *blob;

			if( !(blob = vips_malloc( NULL, data.size )) ) {
				WebPMuxDelete( mux ); 
				return( -1 ); 
			}

			memcpy( blob, data.bytes, data.size );
			vips_image_set_blob( out, vips, 
				(VipsCallbackFn) vips_free, blob, data.size );
		}
	}

	WebPMuxDelete( mux ); 

	/* We may have read some exif ... parse into the header.
	 */
	if( vips__exif_parse( out ) )
		return( -1 ); 
}
#endif /*HAVE_LIBWEBPMUX*/

	return( 0 );
}
Ejemplo n.º 5
0
/* Load up a file as a string.
 */
char *
vips__file_read( FILE *fp, const char *filename, unsigned int *length_out )
{
        long len;
	size_t read;
        char *str;

        /* Find length.
         */
        fseek( fp, 0L, 2 );
        len = ftell( fp );
	if( len > 20 * 1024 * 1024 ) {
		/* Seems crazy!
		 */
                vips_error( "vips__file_read", 
			_( "\"%s\" too long" ), filename );
                return( NULL );
        }

	if( len == -1 ) {
		int size;

		/* Can't get length: read in chunks and realloc() to end of
		 * file.
		 */
		str = NULL;
		len = 0;
		size = 0;
		do {
			size += 1024;
			if( !(str = realloc( str, size )) ) {
				vips_error( "vips__file_read", 
					"%s", _( "out of memory" ) );
				return( NULL );
			}

			/* -1 to allow space for an extra NULL we add later.
			 */
			read = fread( str + len, sizeof( char ), 
				(size - len - 1) / sizeof( char ),
				fp );
			len += read;
		} while( !feof( fp ) );

#ifdef DEBUG
		printf( "read %ld bytes from unseekable stream\n", len );
#endif /*DEBUG*/
	}
	else {
		/* Allocate memory and fill.    
		 */
		if( !(str = vips_malloc( NULL, len + 1 )) )
			return( NULL );
		rewind( fp );
		read = fread( str, sizeof( char ), (size_t) len, fp );
		if( read != (size_t) len ) {
			vips_free( str );
			vips_error( "vips__file_read", 
				_( "error reading from file \"%s\"" ), 
				filename );
			return( NULL );
		}
	}

	str[len] = '\0';

	if( length_out )
		*length_out = len;

        return( str );
}
Ejemplo n.º 6
0
/* Read a png header.
 */
static int
png2vips_header( Read *read, VipsImage *out )
{
	png_uint_32 width, height;
	int bit_depth, color_type;
	int interlace_type;

	png_uint_32 res_x, res_y;
	int unit_type;

	png_charp name;
	int compression_type;

	/* Well thank you, libpng.
	 */
#if PNG_LIBPNG_VER < 10400
	png_charp profile;
#else
	png_bytep profile;
#endif

	png_uint_32 proflen;

	int bands; 
	VipsInterpretation interpretation;
	double Xres, Yres;

	if( setjmp( png_jmpbuf( read->pPng ) ) ) 
		return( -1 );

	png_get_IHDR( read->pPng, read->pInfo, 
		&width, &height, &bit_depth, &color_type,
		&interlace_type, NULL, NULL );

	/* png_get_channels() gives us 1 band for palette images ... so look
	 * at colour_type for output bands.
	 *
	 * Ignore alpha, we detect that separately below.
	 */
	switch( color_type ) {
	case PNG_COLOR_TYPE_PALETTE: 
		bands = 3; 
		break;

	case PNG_COLOR_TYPE_GRAY_ALPHA: 
	case PNG_COLOR_TYPE_GRAY: 
		bands = 1; 
		break;

	case PNG_COLOR_TYPE_RGB: 
	case PNG_COLOR_TYPE_RGB_ALPHA: 
		bands = 3; 
		break;

	default:
		vips_error( "png2vips", "%s", _( "unsupported color type" ) );
		return( -1 );
	}

	if( bit_depth > 8 ) {
		if( bands < 3 )
			interpretation = VIPS_INTERPRETATION_GREY16;
		else
			interpretation = VIPS_INTERPRETATION_RGB16;
	}
	else {
		if( bands < 3 )
			interpretation = VIPS_INTERPRETATION_B_W;
		else
			interpretation = VIPS_INTERPRETATION_sRGB;
	}

	/* Expand palette images.
	 */
	if( color_type == PNG_COLOR_TYPE_PALETTE )
		png_set_palette_to_rgb( read->pPng );

	/* Expand transparency.
	 */
	if( png_get_valid( read->pPng, read->pInfo, PNG_INFO_tRNS ) ) {
		png_set_tRNS_to_alpha( read->pPng );
		bands += 1;
	}
	else if( color_type == PNG_COLOR_TYPE_GRAY_ALPHA || 
		color_type == PNG_COLOR_TYPE_RGB_ALPHA ) {
		/* Some images have no transparency chunk, but still set
		 * color_type to alpha.
		 */
		bands += 1;
	}

	/* Expand <8 bit images to full bytes.
	 */
	if( color_type == PNG_COLOR_TYPE_GRAY &&
		bit_depth < 8 ) 
		png_set_expand_gray_1_2_4_to_8( read->pPng );

	/* If we're an INTEL byte order machine and this is 16bits, we need
	 * to swap bytes.
	 */
	if( bit_depth > 8 && 
		!vips_amiMSBfirst() )
		png_set_swap( read->pPng );

	/* Get resolution. Default to 72 pixels per inch, the usual png value. 
	 */
	unit_type = PNG_RESOLUTION_METER;
	res_x = (72 / 2.54 * 100);
	res_y = (72 / 2.54 * 100);
	png_get_pHYs( read->pPng, read->pInfo, &res_x, &res_y, &unit_type );
	switch( unit_type ) {
	case PNG_RESOLUTION_METER:
		Xres = res_x / 1000.0;
		Yres = res_y / 1000.0;
		break;
	
	default:
		Xres = res_x;
		Yres = res_y;
		break;
	}

	/* Set VIPS header.
	 */
	vips_image_init_fields( out,
		width, height, bands,
		bit_depth > 8 ? 
			VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR,
		VIPS_CODING_NONE, interpretation, 
		Xres, Yres );

	/* Sequential mode needs thinstrip to work with things like
	 * vips_shrink().
	 */
        vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );

	/* Fetch the ICC profile. @name is useless, something like "icc" or
	 * "ICC Profile" etc.  Ignore it.
	 *
	 * @profile was png_charpp in libpngs < 1.5, png_bytepp is the
	 * modern one. Ignore the warning, if any.
	 */
	if( png_get_iCCP( read->pPng, read->pInfo, 
		&name, &compression_type, &profile, &proflen ) ) {
		void *profile_copy;

#ifdef DEBUG
		printf( "png2vips_header: attaching %zd bytes of ICC profile\n",
			proflen );
		printf( "png2vips_header: name = \"%s\"\n", name );
#endif /*DEBUG*/

		if( !(profile_copy = vips_malloc( NULL, proflen )) ) 
			return( -1 );
		memcpy( profile_copy, profile, proflen );
		vips_image_set_blob( out, VIPS_META_ICC_NAME, 
			(VipsCallbackFn) vips_free, profile_copy, proflen );
	}

	/* Sanity-check line size.
	 */
	png_read_update_info( read->pPng, read->pInfo );
	if( png_get_rowbytes( read->pPng, read->pInfo ) != 
		VIPS_IMAGE_SIZEOF_LINE( out ) ) {
		vips_error( "vipspng", 
			"%s", _( "unable to read PNG header" ) );
		return( -1 );
	}

	return( 0 );
}
Ejemplo n.º 7
0
/* Make and init a Write.
 */
static Write *
write_new( VipsImage *im, const char *filename,
	VipsForeignTiffCompression compression, int Q, 
		VipsForeignTiffPredictor predictor,
	char *profile,
	gboolean tile, int tile_width, int tile_height,
	gboolean pyramid,
	gboolean squash,
	gboolean miniswhite,
	VipsForeignTiffResunit resunit, double xres, double yres,
	gboolean bigtiff,
	gboolean rgbjpeg,
	gboolean properties,
	gboolean strip )
{
	Write *write;

	if( !(write = VIPS_NEW( im, Write )) )
		return( NULL );
	write->im = im;
	write->filename = vips_strdup( VIPS_OBJECT( im ), filename );
	write->layer = NULL;
	write->tbuf = NULL;
	write->compression = get_compression( compression );
	write->jpqual = Q;
	write->predictor = predictor;
	write->tile = tile;
	write->tilew = tile_width;
	write->tileh = tile_height;
	write->pyramid = pyramid;
	write->onebit = squash;
	write->miniswhite = miniswhite;
	write->icc_profile = vips_strdup( NULL, profile );
	write->bigtiff = bigtiff;
	write->rgbjpeg = rgbjpeg;
	write->properties = properties;
	write->strip = strip;

	write->resunit = get_resunit( resunit );
	write->xres = xres;
	write->yres = yres;

	/* In strip mode we use tileh to set rowsperstrip, and that does not
	 * have the multiple-of-16 restriction.
	 */
	if( tile ) { 
		if( (write->tilew & 0xf) != 0 || 
			(write->tileh & 0xf) != 0 ) {
			vips_error( "vips2tiff", 
				"%s", _( "tile size not a multiple of 16" ) );
			return( NULL );
		}
	}

	/* We can only pyramid LABQ and non-complex images. 
	 */
	if( write->pyramid ) {
		if( im->Coding == VIPS_CODING_NONE && 
			vips_band_format_iscomplex( im->BandFmt ) ) {
			vips_error( "vips2tiff", 
				"%s", _( "can only pyramid LABQ and "
				"non-complex images" ) );
			return( NULL );
		}
	}

	/* Only 1-bit-ize 8 bit mono images.
	 */
	if( write->onebit &&
		(im->Coding != VIPS_CODING_NONE || 
			im->BandFmt != VIPS_FORMAT_UCHAR ||
			im->Bands != 1) ) {
		vips_warn( "vips2tiff", 
			"%s", _( "can only squash 1 band uchar images -- "
				"disabling squash" ) );
		write->onebit = 0;
	}

	if( write->onebit && 
		write->compression == COMPRESSION_JPEG ) {
		vips_warn( "vips2tiff", 
			"%s", _( "can't have 1-bit JPEG -- disabling JPEG" ) );
		write->compression = COMPRESSION_NONE;
	}
 
	/* We can only MINISWHITE non-complex images of 1 or 2 bands.
	 */
	if( write->miniswhite &&
		(im->Coding != VIPS_CODING_NONE || 
			vips_band_format_iscomplex( im->BandFmt ) ||
			im->Bands > 2) ) {
		vips_warn( "vips2tiff", 
			"%s", _( "can only save non-complex greyscale images "
				"as miniswhite -- disabling miniswhite" ) );
		write->miniswhite = FALSE;
	}

	/* Sizeof a line of bytes in the TIFF tile.
	 */
	if( im->Coding == VIPS_CODING_LABQ )
		write->tls = write->tilew * 3;
	else if( write->onebit )
		write->tls = VIPS_ROUND_UP( write->tilew, 8 ) / 8;
	else
		write->tls = VIPS_IMAGE_SIZEOF_PEL( im ) * write->tilew;

	/* Build the pyramid framework.
	 */
	write->layer = pyramid_new( write, NULL, im->Xsize, im->Ysize );

	/* Fill all the layers.
	 */
	if( pyramid_fill( write ) ) {
		write_free( write );
		return( NULL );
	}

	if( tile ) 
		write->tbuf = vips_malloc( NULL, 
			TIFFTileSize( write->layer->tif ) );
	else
		write->tbuf = vips_malloc( NULL, 
			TIFFScanlineSize( write->layer->tif ) );
	if( !write->tbuf ) {
		write_free( write );
		return( NULL );
	}

	return( write );
}
Ejemplo n.º 8
0
/* Copy a TIFF file ... we know we wrote it, so just copy the tags we know 
 * we might have set.
 */
static int
write_copy_tiff( Write *write, TIFF *out, TIFF *in )
{
	uint32 i32;
	uint16 i16;
	float f;
	tdata_t buf;
	ttile_t tile;
	ttile_t n;

	/* All the fields we might have set.
	 */
	CopyField( TIFFTAG_IMAGEWIDTH, i32 );
	CopyField( TIFFTAG_IMAGELENGTH, i32 );
	CopyField( TIFFTAG_PLANARCONFIG, i16 );
	CopyField( TIFFTAG_ORIENTATION, i16 );
	CopyField( TIFFTAG_XRESOLUTION, f );
	CopyField( TIFFTAG_YRESOLUTION, f );
	CopyField( TIFFTAG_RESOLUTIONUNIT, i16 );
	CopyField( TIFFTAG_COMPRESSION, i16 );
	CopyField( TIFFTAG_SAMPLESPERPIXEL, i16 );
	CopyField( TIFFTAG_BITSPERSAMPLE, i16 );
	CopyField( TIFFTAG_PHOTOMETRIC, i16 );
	CopyField( TIFFTAG_ORIENTATION, i16 );
	CopyField( TIFFTAG_TILEWIDTH, i32 );
	CopyField( TIFFTAG_TILELENGTH, i32 );
	CopyField( TIFFTAG_ROWSPERSTRIP, i32 );
	CopyField( TIFFTAG_SUBFILETYPE, i32 );

	if( write->predictor != VIPS_FOREIGN_TIFF_PREDICTOR_NONE ) 
		TIFFSetField( out, TIFFTAG_PREDICTOR, write->predictor );

	/* TIFFTAG_JPEGQUALITY is a pesudo-tag, so we can't copy it.
	 * Set explicitly from Write.
	 */
	if( write->compression == COMPRESSION_JPEG ) {
		TIFFSetField( out, TIFFTAG_JPEGQUALITY, write->jpqual );

		/* Only for three-band, 8-bit images.
		 */
		if( write->im->Bands == 3 &&
			write->im->BandFmt == VIPS_FORMAT_UCHAR ) { 
			/* Enable rgb->ycbcr conversion in the jpeg write. 
			 */
			if( !write->rgbjpeg &&
				write->jpqual < 90 ) 
				TIFFSetField( out, 
					TIFFTAG_JPEGCOLORMODE, 
						JPEGCOLORMODE_RGB );

			/* And we want ycbcr expanded to rgb on read. Otherwise
			 * TIFFTileSize() will give us the size of a chrominance
			 * subsampled tile.
			 */
			TIFFSetField( in, 
				TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
		}
	}

	/* We can't copy profiles or xmp :( Set again from Write.
	 */
	if( !write->strip ) 
		if( write_embed_profile( write, out ) ||
			write_embed_xmp( write, out ) ||
			write_embed_ipct( write, out ) ||
			write_embed_photoshop( write, out ) ||
			write_embed_imagedescription( write, out ) )
			return( -1 );

	buf = vips_malloc( NULL, TIFFTileSize( in ) );
	n = TIFFNumberOfTiles( in );
	for( tile = 0; tile < n; tile++ ) {
		tsize_t len;

		/* It'd be good to use TIFFReadRawTile()/TIFFWriteRawTile() 
		 * here to save compression/decompression, but sadly it seems
		 * not to work :-( investigate at some point.
		 */
		len = TIFFReadEncodedTile( in, tile, buf, -1 );
		if( len < 0 ||
			TIFFWriteEncodedTile( out, tile, buf, len ) < 0 ) {
			vips_free( buf );
			return( -1 );
		}
	}
	vips_free( buf );

	return( 0 );
}
Ejemplo n.º 9
0
/* Read a cinfo to a VIPS image. Set invert_pels if the pixel reader needs to
 * do 255-pel.
 */
static int
read_jpeg_header( ReadJpeg *jpeg, VipsImage *out )
{
    struct jpeg_decompress_struct *cinfo = &jpeg->cinfo;

    jpeg_saved_marker_ptr p;
    VipsInterpretation interpretation;
    double xres, yres;

    /* Capture app2 sections here for assembly.
     */
    void *app2_data[MAX_APP2_SECTIONS] = { 0 };
    size_t app2_data_length[MAX_APP2_SECTIONS] = { 0 };
    size_t data_length;
    int i;

    /* Read JPEG header. libjpeg will set out_color_space sanely for us
     * for YUV YCCK etc.
     */
    jpeg_read_header( cinfo, TRUE );
    cinfo->scale_denom = jpeg->shrink;
    cinfo->scale_num = 1;
    jpeg_calc_output_dimensions( cinfo );

    jpeg->invert_pels = FALSE;
    switch( cinfo->out_color_space ) {
    case JCS_GRAYSCALE:
        interpretation = VIPS_INTERPRETATION_B_W;
        break;

    case JCS_CMYK:
        interpretation = VIPS_INTERPRETATION_CMYK;
        /* Photoshop writes CMYK JPEG inverted :-( Maybe this is a
         * way to spot photoshop CMYK JPGs.
         */
        if( cinfo->saw_Adobe_marker )
            jpeg->invert_pels = TRUE;
        break;

    case JCS_RGB:
    default:
        interpretation = VIPS_INTERPRETATION_sRGB;
        break;
    }

    /* Get the jfif resolution. exif may overwrite this later.
     */
    xres = 1.0;
    yres = 1.0;
    if( cinfo->saw_JFIF_marker &&
            cinfo->X_density != 1U &&
            cinfo->Y_density != 1U ) {
#ifdef DEBUG
        printf( "read_jpeg_header: seen jfif _density %d, %d\n",
                cinfo->X_density, cinfo->Y_density );
#endif /*DEBUG*/

        switch( cinfo->density_unit ) {
        case 1:
            /* Pixels per inch.
             */
            xres = cinfo->X_density / 25.4;
            yres = cinfo->Y_density / 25.4;
            break;

        case 2:
            /* Pixels per cm.
             */
            xres = cinfo->X_density / 10.0;
            yres = cinfo->Y_density / 10.0;
            break;

        default:
            vips_warn( "VipsJpeg",
                       "%s", _( "unknown JFIF resolution unit" ) );
            break;
        }

#ifdef DEBUG
        printf( "read_jpeg_header: seen jfif resolution %g, %g p/mm\n",
                xres, yres );
#endif /*DEBUG*/
    }

    /* Set VIPS header.
     */
    vips_image_init_fields( out,
                            cinfo->output_width, cinfo->output_height,
                            cinfo->output_components,
                            VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
                            interpretation,
                            xres, yres );

    vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );

    /* Interlaced jpegs need lots of memory to read, so our caller needs
     * to know.
     */
    (void) vips_image_set_int( out, "jpeg-multiscan",
                               jpeg_has_multiple_scans( cinfo ) );

    /* Look for EXIF and ICC profile.
     */
    for( p = cinfo->marker_list; p; p = p->next ) {
#ifdef DEBUG
        {
            printf( "read_jpeg_header: seen %d bytes of APP%d\n",
            p->data_length,
            p->marker - JPEG_APP0 );

            for( i = 0; i < 10; i++ )
                printf( "\t%d) '%c' (%d)\n",
                i, p->data[i], p->data[i] );
        }
#endif /*DEBUG*/

        switch( p->marker ) {
        case JPEG_APP0 + 1:
            /* Possible EXIF or XMP data.
             */
            if( p->data_length > 4 &&
                    vips_isprefix( "Exif", (char *) p->data ) ) {
                if( parse_exif( out,
                                p->data, p->data_length ) ||
                        attach_blob( out, VIPS_META_EXIF_NAME,
                                     p->data, p->data_length ) )
                    return( -1 );
            }

            if( p->data_length > 4 &&
                    vips_isprefix( "http", (char *) p->data ) &&
                    attach_blob( out, VIPS_META_XMP_NAME,
                                 p->data, p->data_length ) )
                return( -1 );

            break;

        case JPEG_APP0 + 2:
            /* Possible ICC profile.
             */
            if( p->data_length > 14 &&
                    vips_isprefix( "ICC_PROFILE",
                                   (char *) p->data ) ) {
                /* cur_marker numbers from 1, according to
                 * spec.
                 */
                int cur_marker = p->data[12] - 1;

                if( cur_marker >= 0 &&
                        cur_marker < MAX_APP2_SECTIONS ) {
                    app2_data[cur_marker] = p->data + 14;
                    app2_data_length[cur_marker] =
                        p->data_length - 14;
                }
            }
            break;

        case JPEG_APP0 + 13:
            /* Possible IPCT data block.
             */
            if( p->data_length > 5 &&
                    vips_isprefix( "Photo", (char *) p->data ) &&
                    attach_blob( out, VIPS_META_IPCT_NAME,
                                 p->data, p->data_length ) )
                return( -1 );
            break;

        default:
            break;
        }
    }

    /* Assemble ICC sections.
     */
    data_length = 0;
    for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ )
        data_length += app2_data_length[i];
    if( data_length ) {
        unsigned char *data;
        int p;

#ifdef DEBUG
        printf( "read_jpeg_header: assembled %zd byte ICC profile\n",
                data_length );
#endif /*DEBUG*/

        if( !(data = vips_malloc( NULL, data_length )) )
            return( -1 );

        p = 0;
        for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ ) {
            memcpy( data + p, app2_data[i], app2_data_length[i] );
            p += app2_data_length[i];
        }

        vips_image_set_blob( out, VIPS_META_ICC_NAME,
                             (VipsCallbackFn) vips_free, data, data_length );
    }

    return( 0 );
}
Ejemplo n.º 10
0
/* Output to a malloc'd buffer, NULL on error. Try to be simple and reliable,
 * rather than quick.
 */
char *
vips__b64_encode( const unsigned char *data, size_t data_length )
{
	/* Worst case: 1.333 chars per byte, plus 10% for extra carriage 
	 * returns and stuff. And the \n\0 at the end.
	 */
	const size_t output_data_length = data_length * 44 / 30 + 2;

	char *buffer;
	char *p;
	size_t i;
	int cursor;

	if( data_length <= 0 ) {
		vips_error( "vips__b64_encode", "%s", _( "too little data" ) );
		return( NULL );
	}
	if( output_data_length > 1024 * 1024 ) {
		/* We shouldn't really be used for large amounts of data.
		 */
		vips_error( "vips__b64_encode", "%s", _( "too much data" ) );
		return( NULL );
	}
	if( !(buffer = vips_malloc( NULL, output_data_length )) ) 
		return( NULL );

	p = buffer;
	*p++ = '\n';
	cursor = 0;

	for( i = 0; i < data_length; i += 3 ) {
		size_t remaining = data_length - i;
		int bits;

		bits = read24( data + i, remaining );
		encode24( p, bits, remaining * 8 );
		p += 4;
		cursor += 4;

		if( cursor >= 76 ) {
			*p++ = '\n';
			cursor = 0;
		}
	}
	if( cursor > 0 ) 
		*p++ = '\n';
	*p++ = '\0';

#ifdef DEBUG
{
	unsigned int total;

	/* Calculate a very simple checksum for debugging.
	 */
	for( total = 0, i = 0; i < data_length; i++ )
		total += data[i];

	printf( "vips__b64_encode: length = %d, checksum 0x%x\n", 
		data_length, total & 0xffff );
}
#endif /*DEBUG*/

	return( buffer );
}
Ejemplo n.º 11
0
static int
vips_histogram_build( VipsObject *object )
{
	VipsHistogram *histogram = VIPS_HISTOGRAM( object );
	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
	VipsHistogramClass *hclass = VIPS_HISTOGRAM_GET_CLASS( histogram );

	VipsImage **decode;
	VipsImage **format;
	VipsImage **band;
	VipsImage **size;
	VipsImage **memory;

	VipsPel *outbuf;		
	VipsPel **inbuf;		
	int i;

#ifdef DEBUG
	printf( "vips_histogram_build: " );
	vips_object_print_name( object );
	printf( "\n" );
#endif /*DEBUG*/

	if( VIPS_OBJECT_CLASS( vips_histogram_parent_class )->build( object ) )
		return( -1 );

	g_assert( histogram->n > 0 ); 

	/* Must be NULL-terminated.
	 */
	g_assert( !histogram->in[histogram->n] ); 

	decode = (VipsImage **) vips_object_local_array( object, histogram->n );
	format = (VipsImage **) vips_object_local_array( object, histogram->n );
	band = (VipsImage **) vips_object_local_array( object, histogram->n );
	size = (VipsImage **) vips_object_local_array( object, histogram->n );
	memory = (VipsImage **) vips_object_local_array( object, histogram->n );

	g_object_set( histogram, "out", vips_image_new(), NULL ); 

	for( i = 0; i < histogram->n; i++ ) 
		if( vips_image_decode( histogram->in[i], &decode[i] ) ||
			vips_check_hist( class->nickname, decode[i] ) )
			return( -1 ); 

	/* Cast our input images up to a common format, bands and size. If
	 * input_format is set, cast to a fixed input type.
	 */
	if( hclass->input_format != VIPS_FORMAT_NOTSET ) {
		for( i = 0; i < histogram->n; i++ ) 
			if( vips_cast( decode[i], &format[i],
				hclass->input_format, NULL ) )
				return( -1 ); 
	}
	else {
		if( vips__formatalike_vec( decode, format, histogram->n ) )
			return( -1 );
	}
		
	if( vips__bandalike_vec( class->nickname, 
		format, band, histogram->n, 1 ) ||
		vips__hist_sizealike_vec( band, size, histogram->n ) ) 
		return( -1 );

	if( vips_image_pipeline_array( histogram->out, 
		VIPS_DEMAND_STYLE_THINSTRIP, size ) ) 
		return( -1 );

	/* Need a copy of the inputs in memory.
	 */
	if( !(inbuf = VIPS_ARRAY( object, histogram->n + 1, VipsPel * )) )
                return( -1 );
	for( i = 0; i < histogram->n; i++ ) {
		if( !(memory[i] = vips_image_copy_memory( size[i] )) )
			return( -1 ); 
		inbuf[i] = VIPS_IMAGE_ADDR( memory[i], 0, 0 );
	}
	inbuf[i] = NULL; 

	/* Keep a copy of the memory images here for subclasses.
	 */
	histogram->ready = memory;

	histogram->out->Xsize = VIPS_IMAGE_N_PELS( histogram->ready[0] );
	histogram->out->Ysize = 1;
	if( hclass->format_table ) 
		histogram->out->BandFmt = 
			hclass->format_table[histogram->ready[0]->BandFmt];
	histogram->out->Type = VIPS_INTERPRETATION_HISTOGRAM;

	if( !(outbuf = vips_malloc( object, 
		VIPS_IMAGE_SIZEOF_LINE( histogram->out ))) )
                return( -1 );

	hclass->process( histogram, outbuf, inbuf, histogram->ready[0]->Xsize );

	if( vips_image_write_line( histogram->out, 0, outbuf ) )
		return( -1 ); 

	return( 0 );
}