blob: cda32b79e26d5cf4c4f57b86e373105ac437fa88 [file] [log] [blame]
/* Copyright (C) 2016 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "third_party/chromium_headless/libwebp/webp/decode.h"
#if 0
#define LOG(x...) fprintf(stderr,"WebP decode error: " x)
#else
#define LOG(x...) do {} while (0)
#endif
////////////////////////////////////////////////////////////
//
// readWebP
//
// Decode a WebP-compressed image from memory, producing RGBA
//
// Input:
// |base| Address of the WebP image in memory
// |size| Number of bytes in the WebP image
//
// Output:
// |pWidth| The width of the decoded image
// |pHeight| The height of the decoded image
//
// Return value: If successful, the address of the
// malloc'd buffer that holds the
// decoded RGBA data
// If unsuccessful, 0
void* readWebP(const unsigned char* base, size_t size,
unsigned *pWidth, unsigned *pHeight)
{
WebPDecoderConfig webpConfig;
VP8StatusCode decodeStatus;
//////////////////////////////
*pWidth = 0;
*pHeight = 0;
// Configure the decoder for RGBA output
memset(&webpConfig, 0, sizeof(webpConfig));
webpConfig.output.colorspace = MODE_RGBA;
// Decode to RGBA
decodeStatus = WebPDecode(base, size, &webpConfig);
if (decodeStatus != VP8_STATUS_OK) {
LOG("WebPDecode() failed\n");
return 0;
}
// Success
*pWidth = webpConfig.output.width;
*pHeight = webpConfig.output.height;
return (void*)webpConfig.output.u.RGBA.rgba;
}
////////////////////////////////////////////////////////////
//
// loadWebP
//
// Decode a WebP-compressed image from a file, producing RGBA
//
// Input:
// |fileName| Path and name of the WebP file
//
// Output:
// |pWidth| The width of the decoded image
// |pHeight| The height of the decode image
//
// Return value: If successful, the address of the
// malloc'd buffer that holds the
// decoded RGBA data
// If unsuccessful, 0
#define HEADER_SIZE 12
void* loadWebP(const char *fileName, unsigned *pWidth, unsigned *pHeight) {
int bytesRead;
int fileSize;
struct stat fileStatus;
FILE* fp;
void* rgbaAddr;
uint8_t* webpBytes;
uint8_t webpHeader[HEADER_SIZE];
//////////////////////////////
*pWidth = 0;
*pHeight = 0;
// Get the file size
if (stat(fileName, &fileStatus) != 0) {
LOG("Could not status file: %s\n", fileName);
return 0;
}
fileSize = fileStatus.st_size;
if (fileSize < HEADER_SIZE) {
LOG("WebP file is way too small: %s\n", fileName);
return 0;
}
// Read the first few bytes into memory
fp = fopen(fileName, "rb");
if(fp == 0) {
LOG("Failed to open file: %s\n", fileName);
return 0;
}
bytesRead = fread(webpHeader, 1, HEADER_SIZE, fp);
if (bytesRead != HEADER_SIZE) {
LOG("Failed to read header of file: %s\n", fileName);
fclose(fp);
return 0;
}
// Verify that it is probably WebP
if (webpHeader[ 0] != 'R' ||
webpHeader[ 1] != 'I' ||
webpHeader[ 2] != 'F' ||
webpHeader[ 3] != 'F' ||
webpHeader[ 8] != 'W' ||
webpHeader[ 9] != 'E' ||
webpHeader[10] != 'B' ||
webpHeader[11] != 'P' )
{
LOG("Not a WebP file: %s\n", fileName);
fclose(fp);
return 0;
}
rewind(fp);
// Read the entire file into memory
webpBytes = malloc(fileSize);
if (webpBytes == NULL) {
LOG("malloc(%d) failed\n", fileSize);
fclose(fp);
return 0;
}
bytesRead = fread(webpBytes, 1, fileSize, fp);
fclose(fp);
if (bytesRead != fileSize) {
LOG("Failed to read contents of file %s\n", fileName);
free(webpBytes);
return 0;
}
rgbaAddr = readWebP(webpBytes, fileSize, pWidth, pHeight);
// Free the file data. Keep the pixel data.
free(webpBytes);
return rgbaAddr;
}