Below is a include for the decoder part only of libwebp.lib, and further below is a example of how to convert from WebP to something that the PureBasic image library can use.
This is just a proof of concept, I'm not happy with this (the loop in the example in particular), and can easily be improved.
If anyone feel like improving it feel free to post in this thread, that's what it's here for.
Only the WebP functions used in the example have been tested, and only the x86 libwebp.lib has been tested, but the x64 libwebp.lib should also work unless I messed up some .i stuff or padding/alignment stuff. (no x64 stuff was pointed out in the original .h decoder file)
Hopefully WebP will be a imageplugin some day (tries to bribe Fred and Freak with a WebP beer http://www.wpclipart.com/food/beverages ... r.png.html ).
ImportC include:
Code: Select all
;Copyright 2010 Google Inc. All Rights Reserved.
;
;This code is licensed under the same terms as WebM:
;Software License Agreement: http://www.webmproject.org/license/software/
;Additional IP Rights Grant: http://www.webmproject.org/license/additional/
;Main decoding functions for WebP images.
;Author: Skal (pascal.massimino@gmail.com)
;Quick'n'dirty PureBasic import include by Roger Hågensen, http://www.EmSai.net/
#WEBP_DECODER_ABI_VERSION=$0200 ;MAJOR(8b) + MINOR(8b)
Enumeration 0 ;status codes
#VP8_STATUS_OK
#VP8_STATUS_OUT_OF_MEMORY
#VP8_STATUS_INVALID_PARAM
#VP8_STATUS_BITSTREAM_ERROR
#VP8_STATUS_UNSUPPORTED_FEATURE
#VP8_STATUS_SUSPENDED
#VP8_STATUS_USER_ABORT
#VP8_STATUS_NOT_ENOUGH_DATA
EndEnumeration
Structure WebPRGBABuffer ;view as RGBA
*rgba ;pointer to RGBA samples
stride.l ;stride in bytes from one scanline to the next.
size.i ;total size of the *rgba buffer.
EndStructure
Structure WebPYUVABuffer ;view as YUVA
*y ;pointer to luma samples
*u ;pointer to chroma U samples
*v ;pointer to chroma V samples
*a ;pointer to alpha samples
y_stride.l ;luma stride
u_stride.l ;chroma u stride
v_stride.l ;chroma v stride
a_stride.l ;alpha stride
y_size.i ;luma plane size
u_size.i ;chroma u plane size
v_size.i ;chroma v plane size
a_size.i ;alpha-plane size
EndStructure
;Output buffer
Structure WebPDecBuffer
colorspace.l ;Colorspace.
width.l ;Dimension width.
height.l ;Dimension height.
is_external_memory.l ;If true, 'internal_memory' pointer is not used.
StructureUnion
u.l
RGBA.WebPRGBABuffer
YUVA.WebPYUVABuffer
EndStructureUnion
pad.l[4] ;padding for later use
*private_memory ;Internally allocated memory (only when is_external_memory is false).
;Should not be use externally, but accessed via the buffer union.
EndStructure
;Features gathered from the bitstream
Structure WebPBitstreamFeatures
width.l ;Width in pixels, as read from the bitstream.
height.l ;Height in pixels, as read from the bitstream.
has_alpha.l ;True if the bitstream contains an alpha channel.
;Unused for now:
bitstream_version.l ;should be 0 for now. TODO(later)
no_incremental_decoding.l ;if true, using incremental decoding is not recommended.
rotate.l ;TODO(later)
uv_sampling.l ;should be 0 for now. TODO(later)
pad.l[3] ;padding for later use
EndStructure
;Decoding options
Structure WebPDecoderOptions
bypass_filtering.l ;if true, skip the in-loop filtering
no_fancy_upsampling.l ;if true, use faster pointwise upsampler
use_cropping.l ;if true, cropping is applied _first_
crop_left.l ;top-left position for cropping.
crop_top.l ;Will be snapped to even values.
crop_width.l ;dimension of the cropping area
crop_height.l ;dimension of the cropping area
use_scaling.l ;if true, scaling is applied _afterward_
scaled_width.l ;final resolution
scaled_height.l ;final resolution
use_threads.l ;if true, use multi-threaded decoding
;Unused for now:
force_rotation.l ;forced rotation (to be applied _last_)
no_enhancement.l ;if true, discard enhancement layer
pad.l[6] ;padding for later use
EndStructure
;Main object storing the configuration for advanced decoding.
Structure WebPDecoderConfig
input.WebPBitstreamFeatures ;Immutable bitstream features (optional)
output.WebPDecBuffer ;Output buffer (can point to external mem)
options.WebPDecoderOptions ;Decoding options
EndStructure
;Colorspaces
;Note: the naming describes the byte-ordering of packed samples in memory.
;For instance, MODE_BGRA relates to samples ordered as B,G,R,A,B,G,R,A,...
;Non-capital names (e.g.:MODE_Argb) relates to pre-multiplied RGB channels.
;RGB-565 and RGBA-4444 are also endian-agnostic and byte-oriented.
Enumeration
#WEBP_MODE_RGB=0
#WEBP_MODE_RGBA=1
#WEBP_MODE_BGR=2
#WEBP_MODE_BGRA=3
#WEBP_MODE_ARGB=4
#WEBP_MODE_RGBA_4444=5
#WEBP_MODE_RGB_565=6
;RGB-premultiplied transparent modes (alpha value is preserved)
#WEBP_MODE_PRGBA=7
#WEBP_MODE_PBGRA=8
#WEBP_MODE_PARGB=9
#WEBP_MODE_PRGBA_4444=10
;YUV modes must come after RGB ones.
#WEBP_MODE_YUV=11
#WEBP_MODE_YUVA=12 ;yuv 4:2:0
#WEBP_MODE_LAST=13
EndEnumeration
;Some useful macros:
Macro WebPIsPremultipliedMode(mode)
((mode&#WEBP_MODE_PRGBA) | (mode&#WEBP_MODE_PBGRA) | (mode&#WEBP_MODE_PARGB) | (mode&#WEBP_MODE_RGBA_4444))
EndMacro
Macro WebPIsAlphaMode(mode)
((mode&#WEBP_MODE_RGBA) | (mode&#WEBP_MODE_BGRA) | (mode&#WEBP_MODE_ARGB) | (mode&#WEBP_MODE_RGBA_4444) | (mode&#WEBP_MODE_YUVA) | WebPIsPremultipliedMode(mode))
EndMacro
Macro WebPIsRGBMode(mode)
(mode<#WEBP_MODE_YUV)
EndMacro
ImportC "libwebp.lib"
;Return the decoder's version number, packed in hexadecimal using 8bits for
;each of major/minor/revision. E.g: v2.5.7 is 0x020507.
WebPGetDecoderVersion.l()
;Retrieve basic header information: width, height.
;This function will also validate the header and return 0 in
;case of formatting error.
;Pointers 'width' and 'height' can be passed NULL if deemed irrelevant.
WebPGetInfo.l(*webp,data_size.l,*width,*height)
;Decodes WebP images pointed to by 'data' and returns RGBA samples, along
;with the dimensions in *width and *height. The ordering of samples in
;memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
;The returned pointer should be deleted calling free().
;Returns NULL in case of error.
WebPDecodeRGBA.i(*webp,data_size.l,*width,*height)
;Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
WebPDecodeARGB.i(*webp,data_size.l,*width,*height)
;Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
WebPDecodeBGRA.i(*webp,data_size.l,*width,*height)
;Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
;If the bitstream contains transparency, it is ignored.
WebPDecodeRGB.i(*webp,data_size.l,*width,*height)
;Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
WebPDecodeBGR.i(*webp,data_size.l,*width,*height)
;Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
;returned is the Y samples buffer. Upon return, *u and *v will point to
;the U and V chroma data. These U and V buffers need NOT be free()'d,
;unlike the returned Y luma one. The dimension of the U and V planes
;are both (*width + 1) / 2 and (*height + 1)/ 2.
;Upon return, the Y buffer has a stride returned as '*stride', while U and V
;have a common stride returned as '*uv_stride'.
;Return NULL in case of error.
;(*) Also named Y'CbCr. See: http://en.wikipedia.org/wiki/YCbCr
WebPDecodeYUV.i(*webp,data_size.l,*width,*height,*u,*v,*stride,*uv_stride)
;These five functions are variants of the above ones, that decode the image
;directly into a pre-allocated buffer 'output_buffer'. The maximum storage
;available in this buffer is indicated by 'output_buffer_size'. If this
;storage is not sufficient (or an error occurred), NULL is returned.
;Otherwise, output_buffer is returned, for convenience.
;The parameter 'output_stride' specifies the distance (in bytes)
;between scanlines. Hence, output_buffer_size is expected to be at least
;output_stride x picture-height.
WebPDecodeRGBAInto.i(*webp,data_size.l,*output_buffer,output_buffer_size.i,output_stride.l)
WebPDecodeARGBInto.i(*webp,data_size.l,*output_buffer,output_buffer_size.i,output_stride.l)
WebPDecodeBGRAInto.i(*webp,data_size.l,*output_buffer,output_buffer_size.i,output_stride.l)
;RGB and BGR variants. Here too the transparency information, if present,
;will be dropped and ignored.
WebPDecodeRGBInto.i(*webp,data_size.l,*output_buffer,output_buffer_size.i,output_stride.l)
WebPDecodeBGRInto.i(*webp,data_size.l,*output_buffer,output_buffer_size.i,output_stride.l)
;WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly
;into pre-allocated luma/chroma plane buffers. This function requires the
;strides to be passed: one for the luma plane and one for each of the
;chroma ones. The size of each plane buffer is passed as 'luma_size',
;'u_size' and 'v_size' respectively.
;Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
;during decoding (or because some buffers were found to be too small).
WebPDecodeYUVInto.i(*webp,data_size.l,*luma,luma_size.i,luma_stride.l,*u,u_size.i,u_stride.l,*v,v_size.i,v_stride.l)
;Internal, version-checked, entry point
WebPInitDecBufferInternal.l(*buffer,int.l)
;Initialize the structure as empty. Must be called before any other use.
;Returns false in case of version mismatch
Macro WebPInitDecBuffer(buffer)
WebPInitDecBufferInternal(buffer,#WEBP_DECODER_ABI_VERSION)
EndMacro
;Free any memory associated with the buffer. Must always be called last.
;Note: doesn't free the 'buffer' structure itself.
WebPFreeDecBuffer(*buffer)
;Incremental decoding
;This API allows streamlined decoding of partial data.
;Picture can be incrementally decoded as data become available thanks to the
;WebPIDecoder object. This object can be left in a SUSPENDED state if the
;picture is only partially decoded, pending additional input.
;Code example:
;
; WebPInitDecBuffer(&buffer);
; buffer.colorspace = mode;
; ...
; WebPIDecoder* idec = WebPINewDecoder(&buffer);
; while (has_more_data) {
; ;... (get additional data)
; status = WebPIAppend(idec, new_data, new_data_size);
; if (status != VP8_STATUS_SUSPENDED ||
; break;
; }
;
; ;The above call decodes the current available buffer.
; ;Part of the image can now be refreshed by calling to
; ;WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
; }
; WebPIDelete(idec);
;typedef struct WebPIDecoder WebPIDecoder
;Creates a new incremental decoder with the supplied buffer parameter.
;This output_buffer can be passed NULL, in which case a default output buffer
;is used (with MODE_RGB). Otherwise, an internal reference to 'output_buffer'
;is kept, which means that the lifespan of 'output_buffer' must be larger than
;that of the returned WebPIDecoder object.
;Returns NULL if the allocation failed.
WebPINewDecoder.i(*output_buffer)
;This function allocates and initializes an incremental-decoder object, which
;will output the RGB/A samples specified by 'csp' into a preallocated
;buffer 'output_buffer'. The size of this buffer is at least
;'output_buffer_size' and the stride (distance in bytes between two scanlines)
;is specified by 'output_stride'. Returns NULL if the allocation failed.
WebPINewRGB.i(csp.l,*output_buffer,output_buffer_size.i,output_stride.l)
;This function allocates and initializes an incremental-decoder object, which
;will output the raw luma/chroma samples into a preallocated planes. The luma
;plane is specified by its pointer 'luma', its size 'luma_size' and its stride
;'luma_stride'. Similarly, the chroma-u plane is specified by the 'u',
;'u_size' and 'u_stride' parameters, and the chroma-v plane by 'v'
;and 'v_size'. And same for the alpha-plane. The 'a' pointer can be pass
;NULL in case one is not interested in the transparency plane.
;Returns NULL if the allocation failed.
WebPINewYUVA.i(*luma,luma_size.i,luma_stride.l,*u,u_size.i,u_stride.l,*v,v_size.i,v_stride.l,*a,a_size.i,a_stride.l)
;Deletes the WebPIDecoder object and associated memory. Must always be called
;if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded.
WebPIDelete(*idec)
;Copies and decodes the next available data. Returns VP8_STATUS_OK when
;the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
;data is expected. Returns error in other cases.
WebPIAppend.l(*idec,*webp,data_size.l)
;A variant of the above function to be used when data buffer contains
;partial data from the beginning. In this case data buffer is not copied
;to the internal memory.
;Note that the value of the 'data' pointer can change between calls to
;WebPIUpdate, for instance when the data buffer is resized to fit larger data.
WebPIUpdate.l(*idec,*webp,data_size.l)
;Returns the RGB/A image decoded so far. Returns NULL if output params
;are not initialized yet. The RGB/A output type corresponds to the colorspace
;specified during call to WebPINewDecoder() or WebPINewRGB().
;*last_y is the index of last decoded row in raster scan order. Some pointers
;(*last_y, *width etc.) can be NULL if corresponding information is not
;needed.
WebPIDecGetRGB.i(*idec,*last_y,*width,*height,*stride)
;Same as above function to get a YUVA image. Returns pointer to the luma
;plane or NULL in case of error. If there is no alpha information
;the alpha pointer '*a' will be returned NULL.
WebPIDecGetYUVA.i(*idec,*last_y,*u,*v,*a,*width,*height,*stride,*uv_stride,*a_stride)
;Generic call to retrieve information about the displayable area.
;If non NULL, the left/right/width/height pointers are filled with the visible
;rectangular area so far.
;Returns NULL in case the incremental decoder object is in an invalid state.
;Otherwise returns the pointer to the internal representation. This structure
;is read-only, tied to WebPIDecoder's lifespan and should not be modified.
WebPIDecodedArea.i(*idec,*left,*top,*width,*height)
;Advanced decoding parametrization
; Code sample for using the advanced decoding API
; /*
; ;A) Init a configuration object
; WebPDecoderConfig config;
; CHECK(WebPInitDecoderConfig(&config))
;
; ;B) optional: retrieve the bitstream's features.
; CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK)
;
; ;C) Adjust 'config', if needed
; config.no_fancy = 1
; config.output.colorspace = MODE_BGRA
; ;etc.
;
; ;Note that you can also make config.output point to an externally
; ;supplied memory buffer, provided it's big enough to store the decoded
; ;picture. Otherwise, config.output will just be used to allocate memory
; ;and store the decoded picture.
;
; ;D) Decode!
; CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK)
;
; ;E) Decoded image is now in config.output (and config.output.u.RGBA)
;
; ;F) Reclaim memory allocated in config's object. It's safe to call
; ;this function even if the memory is external and wasn't allocated
; ;by WebPDecode().
; WebPFreeDecBuffer(&config.output)
; */
;Internal, version-checked, entry point
WebPGetFeaturesInternal.l(*webp,data_size.l,*features,int.l)
;Retrieve features from the bitstream. The *features structure is filled
;with information gathered from the bitstream.
;Returns false in case of error or version mismatch.
;In case of error, features->bitstream_status will reflect the error code.
Macro WebPGetFeatures(webp,data_size,features)
WebPGetFeaturesInternal(webp,data_size,features,#WEBP_DECODER_ABI_VERSION)
EndMacro
;Internal, version-checked, entry point
WebPInitDecoderConfigInternal.l(*config,int.l)
;Initialize the configuration as empty. This function must always be
;called first, unless WebPGetFeatures() is to be called.
;Returns false in case of mismatched version.
Macro WebPInitDecoderConfig(config)
WebPInitDecoderConfigInternal(config,#WEBP_DECODER_ABI_VERSION)
EndMacro
;Instantiate a new incremental decoder object with the requested
;configuration. The bitstream can be passed using 'data' and 'data_size'
;parameter, in which case the features will be parsed and stored into
;config->input. Otherwise, 'data' can be NULL and no parsing will occur.
;Note that 'config' can be NULL too, in which case a default configuration
;is used.
;The return WebPIDecoder object must always be deleted calling WebPIDelete().
;Returns NULL in case of error (and config->status will then reflect
;the error condition).
WebPIDecode.i(*webp,data_size.l,*config)
;Non-incremental version. This version decodes the full data at once, taking
;'config' into account. Returns decoding status (which should be VP8_STATUS_OK
;if the decoding was successful).
WebPDecode.l(*webp,data_size.l,*config)
EndImport
Code: Select all
;Parameters:
;image = #PB_Any or a image ID
;*webp = memorypointer to a WebP image (as loaded directly from disk or some other way)
;webpsize = size of the WebP image (or more correctly the *webp memory size)
;Result:
;image ID is returned, use IsImage() to check if it is a valid image or not.
Procedure.i WebP_to_Image(image.i,*webp,webpsize.i)
Protected result.i=#False,width.i,height.i,pitch.i,*rawimg,*rawimgend,i.i,imagesize.i
If WebPGetInfo(*webp,webpsize,@width,@height) ;get width and height
image=CreateImage(image,width,height,32) ;must be 32
If IsImage(image)
imagesize=(width*height)<<2 ;same as (width*height)*4, multiply by 4 is because we are dealing with 32bit pixels (4 bytes)
If StartDrawing(ImageOutput(image))
pitch=DrawingBufferPitch()
*rawimg=DrawingBuffer()
If WebPDecodeBGRAInto(*webp,webpsize,*rawimg,imagesize,pitch)
If (height>1) And (width>0) ;No point in swapping a single line, checking width>0 is done to harden against buffer overrun.
*webp=AllocateMemory(pitch) ;temporary scanline storage, and we're recycling the *webp variable just because we're clever.
If *webp
*rawimgend=*rawimg+imagesize ;these lines are here to minimize the code needed inside the loop (minor speedup).
height>>1 ;divide height by 2, due to nature of power of twos the last line of a odd number height is ignored which is what we want.
For i=1 To height
*rawimgend-pitch
CopyMemory(*rawimg,*webp,pitch)
CopyMemory(*rawimgend,*rawimg,pitch) ;Yeah, not a pretty thing, this can probably be optimized a damn lot.
CopyMemory(*webp,*rawimgend,pitch)
*rawimg+pitch
Next
FreeMemory(*webp)
EndIf
EndIf
result=#True ;Image decoded ok, and we'll assume that the flipping also went ok.
EndIf
StopDRawing()
EndIf
EndIf
EndIf
If result=#False ;Something went wrong, free the empty image if there is one and return the imageid.
If IsImage(image) : FreeImage(image) : EndIf
EndIf
ProcedureReturn image ;Use IsImage() on the return value to check if the conversion succeeded.
EndProcedure
Changed "For i=0 To height" to "For i=1 To height"