FloatPixMapRef FPMCopySub(FloatPixMapRef pm, FPMRect rect)
{
	FloatPixMapRef sub = FPMCreateSub(pm, rect);
	FloatPixMapRef result = FPMCopy(sub);
	FPMRelease(&sub);
	return result;
}
Exemple #2
0
void ReadCubeDestructor(void *context)
{
	assert(context != NULL);
	ReadCubeContext *cx = context;
	
	FPMRelease(&cx->pm);
	free(cx);
}
static void Destroy(FloatPixMapRef pm)
{
	FPM_INTERNAL_ASSERT(pm != NULL);
	
	// Only "masterless" FPMs own their pixels.
	if (pm->master == NULL)
	{
		free(pm->pixels);
	}
	else
	{
		FPMRelease(&pm->master);
	}
	
	free(pm);
}
Exemple #4
0
FloatPixMapRef ConvertPNGData(void *data, size_t width, size_t height, size_t rowBytes, uint8_t depth, uint8_t colorType)
{
    FloatPixMapRef result = FPMCreateC(width, height);
    if (result == NULL)  return NULL;

    // Libpng transformations should have given us one of these formats.
    if (depth == 8 && (colorType == PNG_COLOR_TYPE_RGB_ALPHA || colorType == PNG_COLOR_TYPE_RGB))
    {
        return ConvertPNGDataRGBA8(result, data, width, height, rowBytes);
    }
    if (depth == 16 && colorType == PNG_COLOR_TYPE_RGB_ALPHA)
    {
        return ConvertPNGDataRGBA16(result, data, width, height, rowBytes);
    }
    if (depth == 16 && colorType == PNG_COLOR_TYPE_RGB)
    {
        return ConvertPNGDataRGB16(result, data, width, height, rowBytes);
    }

    fprintf(stderr, "Unexpected PNG depth/colorType combination: %u, 0x%X\n", depth, colorType);
    FPMRelease(&result);
    return NULL;
}
Exemple #5
0
FloatPixMapRef FPMCreateWithPNGCustom(png_voidp ioPtr, png_rw_ptr readDataFn, FPMGammaFactor desiredGamma, FPMPNGErrorHandler errorHandler)
{
    png_structp			png = NULL;
    png_infop			pngInfo = NULL;
    png_infop			pngEndInfo = NULL;
    FloatPixMapRef		result = NULL;
    png_uint_32			i, width, height, rowBytes;
    int					depth, colorType;
    png_bytepp			rows = NULL;
    void				*data = NULL;

    png = png_create_read_struct(PNG_LIBPNG_VER_STRING, errorHandler, PNGError, PNGWarning);
    if (png == NULL)  goto FAIL;

    pngInfo = png_create_info_struct(png);
    if (pngInfo == NULL)  goto FAIL;

    pngEndInfo = png_create_info_struct(png);
    if (pngEndInfo == NULL)  goto FAIL;

    if (setjmp(png_jmpbuf(png)))
    {
        // libpng will jump here on error.
        goto FAIL;
    }

    png_set_read_fn(png, ioPtr, readDataFn);

    png_read_info(png, pngInfo);
    if (!png_get_IHDR(png, pngInfo, &width, &height, &depth, &colorType, NULL, NULL, NULL))  goto FAIL;

#if __LITTLE_ENDIAN__
    if (depth == 16)  png_set_swap(png);
#endif
    if (depth <= 8 && !(colorType & PNG_COLOR_MASK_ALPHA))
    {
        png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
    }
    png_set_gray_to_rgb(png);
    if (depth < 8)
    {
        png_set_packing(png);
        png_set_expand(png);
    }

    png_read_update_info(png, pngInfo);
    rowBytes = png_get_rowbytes(png, pngInfo);

    rows = malloc(sizeof *rows * height);
    data = malloc(rowBytes * height);
    if (rows == NULL || data == NULL)  goto FAIL;

    // Set up row pointers.
    for (i = 0; i < height; i++)
    {
        rows[i] = (png_bytep)data + i * rowBytes;
    }

    png_read_image(png, rows);
    png_read_end(png, pngEndInfo);

    free(rows);

    result = ConvertPNGData(data, width, height, rowBytes, png_get_bit_depth(png, pngInfo), png_get_color_type(png, pngInfo));

    if (result != NULL)
    {
        double invGamma = 1.0/kFPMGammaSRGB;
        png_get_gAMA(png, pngInfo, &invGamma);
        FPMApplyGamma(result, 1.0/invGamma, desiredGamma, png_get_bit_depth(png, pngInfo) == 16 ? 65536 : 256);
    }

    png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
    free(data);

    return result;

FAIL:
    FPMRelease(&result);
    if (png != NULL)  png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
    free(rows);
    free(data);

    return NULL;
}
Exemple #6
0
bool FPMWritePNGCustom(FloatPixMapRef srcPM, png_voidp ioPtr, png_rw_ptr writeDataFn, png_flush_ptr flushDataFn, FPMWritePNGFlags options, FPMGammaFactor sourceGamma, FPMGammaFactor fileGamma, FPMPNGErrorHandler errorHandler)
{
    if (srcPM != NULL)
    {
        bool				success = false;
        png_structp			png = NULL;
        png_infop			pngInfo = NULL;
        FloatPixMapRef		pm = NULL;

        // Prepare data.
        FPMDimension width = FPMGetWidth(srcPM);
        FPMDimension height = FPMGetHeight(srcPM);
        if (width > UINT32_MAX || height > UINT32_MAX)
        {
            if (errorHandler != NULL)  errorHandler("image is too large for PNG format.", true);
            return false;
        }

        pm = FPMCopy(srcPM);
        if (pm == NULL)  return false;

        unsigned steps = (options & kFPMWritePNG16BPC) ? 0x10000 : 0x100;
        FPMApplyGamma(pm, sourceGamma, fileGamma, steps);
        FPMQuantize(pm, 0.0f, 1.0f, 0.0f, steps - 1, steps, (options & kFPMQuantizeDither & kFPMQuantizeJitter) | kFMPQuantizeClip | kFMPQuantizeAlpha);

        png = png_create_write_struct(PNG_LIBPNG_VER_STRING, errorHandler, PNGError, PNGWarning);
        if (png == NULL)  goto FAIL;

        pngInfo = png_create_info_struct(png);
        if (pngInfo == NULL)  goto FAIL;

        if (setjmp(png_jmpbuf(png)))
        {
            // libpng will jump here on error.
            goto FAIL;
        }

        png_set_write_fn(png, ioPtr, writeDataFn, flushDataFn);

        png_set_IHDR(png, pngInfo, width, height, (options & kFPMWritePNG16BPC) ? 16 : 8,PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

        if (fileGamma == kFPMGammaSRGB)
        {
            png_set_sRGB_gAMA_and_cHRM(png, pngInfo, PNG_sRGB_INTENT_PERCEPTUAL);
        }
        else
        {
            png_set_gAMA(png, pngInfo, fileGamma);
        }

        /*	Select function used to transform a row of data to PNG-friendly
        	format. NOTE: these work in place,and overwrite the data in pm,
        	which is OK since we copied it.
        */
        RowTransformer transformer = NULL;
        if (options & kFPMWritePNG16BPC)
        {
            transformer = TransformRow16;
        }
        else
        {
            transformer = TransformRow8;
        }

        png_write_info(png, pngInfo);

        size_t i;
        size_t rowOffset = FPMGetRowByteCount(pm);
        png_bytep row = (png_bytep)FPMGetBufferPointer(pm);
        for (i = 0; i < height; i++)
        {
            transformer(row, width);
            png_write_row(png, row);
            row += rowOffset;
        }
        png_write_end(png, pngInfo);
        success = true;

FAIL:
        if (png != NULL)  png_destroy_write_struct(&png, &pngInfo);
        FPMRelease(&pm);

        return success;
    }
    else
    {
        return false;
    }
}
FloatPixMapRef FPMCreateWithPNGCustom(png_voidp ioPtr, png_rw_ptr readDataFn, FPMGammaFactor desiredGamma, FPMPNGErrorHandler errorHandler, FPMPNGProgressHandler progressHandler, void *callbackContext)
{
	png_structp			png = NULL;
	png_infop			pngInfo = NULL;
	png_infop			pngEndInfo = NULL;
	FloatPixMapRef		result = NULL;
	png_uint_32			i, width, height, rowBytes;
	int					depth, colorType;
	void				*data = NULL;
	ErrorInfo			errInfo = { errorHandler, callbackContext };
	
	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, &errInfo, PNGError, PNGWarning);
	if (png == NULL)  goto FAIL;
	
	pngInfo = png_create_info_struct(png);
	if (pngInfo == NULL)  goto FAIL;
	
	pngEndInfo = png_create_info_struct(png);
	if (pngEndInfo == NULL)  goto FAIL;
	
	if (setjmp(png_jmpbuf(png)))
	{
		// libpng will jump here on error.
		goto FAIL;
	}
	
	png_set_read_fn(png, ioPtr, readDataFn);
	
	png_read_info(png, pngInfo);
	if (!png_get_IHDR(png, pngInfo, &width, &height, &depth, &colorType, NULL, NULL, NULL))  goto FAIL;
	
#if FPM_LITTLE_ENDIAN
	if (depth == 16)  png_set_swap(png);
#endif
	if (depth <= 8 && !(colorType & PNG_COLOR_MASK_ALPHA))
	{
		png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
	}
	png_set_gray_to_rgb(png);
	if (depth < 8)
	{
		png_set_packing(png);
		png_set_expand(png);
	}
	
	if (colorType & PNG_COLOR_MASK_PALETTE)
	{
		png_set_palette_to_rgb(png);
	}
	
	png_read_update_info(png, pngInfo);
	rowBytes = png_get_rowbytes(png, pngInfo);
	
	data = malloc(rowBytes * height);
	if (data == NULL)  goto FAIL;
	
	// Set up row pointers.
	for (i = 0; i < height; i++)
	{
		png_read_row(png, (png_bytep)data + i * rowBytes, NULL);
		if (progressHandler)  progressHandler((float)(i + 1) / (float)height, callbackContext);
	}
	
	png_read_end(png, pngEndInfo);
	
	result = ConvertPNGData(data, width, height, rowBytes, png_get_bit_depth(png, pngInfo), png_get_color_type(png, pngInfo));
	
	if (result != NULL)
	{
		double invGamma = 1.0/kFPMGammaSRGB;
		png_get_gAMA(png, pngInfo, &invGamma);
		FPMApplyGamma(result, 1.0/invGamma, desiredGamma, png_get_bit_depth(png, pngInfo) == 16 ? 65536 : 256);
	}
	else
	{
		if (errorHandler != NULL)  errorHandler("Could not convert PNG data to native representation.", true, callbackContext);
	}

	
	png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
	free(data);
	
	return result;
	
FAIL:
	FPMRelease(&result);
	if (png != NULL)  png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
	free(data);
	
	return NULL;
}