ImageBufferHaiku.cpp [plain text]
#include "config.h"
#include "ImageBuffer.h"
#include "Base64.h"
#include "GraphicsContext.h"
#include "ImageData.h"
#include "MIMETypeRegistry.h"
#include "StillImageHaiku.h"
#include <wtf/text/CString.h>
#include <BitmapStream.h>
#include <String.h>
#include <TranslatorRoster.h>
namespace WebCore {
ImageBufferData::ImageBufferData(const IntSize& size)
: m_bitmap(BRect(0, 0, size.width() - 1, size.height() - 1), B_RGBA32, true)
, m_view(m_bitmap.Bounds(), "WebKit ImageBufferData", 0, 0)
{
m_bitmap.Lock();
m_bitmap.AddChild(&m_view);
memset(m_bitmap.Bits(), 0, m_bitmap.BitsLength());
m_view.SetLineMode(B_BUTT_CAP, B_MITER_JOIN, 10);
m_view.SetDrawingMode(B_OP_ALPHA);
m_view.SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
}
ImageBufferData::~ImageBufferData()
{
m_view.RemoveSelf();
m_bitmap.Unlock();
}
ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
: m_data(size)
, m_size(size)
{
m_context.set(new GraphicsContext(&m_data.m_view));
success = true;
}
ImageBuffer::~ImageBuffer()
{
}
GraphicsContext* ImageBuffer::context() const
{
ASSERT(m_data.m_view.Window());
return m_context.get();
}
Image* ImageBuffer::image() const
{
if (!m_image) {
ASSERT(context());
m_data.m_view.Sync();
m_image = StillImage::create(m_data.m_bitmap);
}
return m_image.get();
}
void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
{
uint8* rowData = reinterpret_cast<uint8*>(m_data.m_bitmap.Bits());
unsigned bytesPerRow = m_data.m_bitmap.BytesPerRow();
unsigned rows = m_size.height();
unsigned columns = m_size.width();
for (unsigned y = 0; y < rows; y++) {
uint8* pixel = rowData;
for (unsigned x = 0; x < columns; x++) {
pixel[0] = lookUpTable[pixel[0]];
pixel[1] = lookUpTable[pixel[1]];
pixel[2] = lookUpTable[pixel[2]];
pixel += 4;
}
rowData += bytesPerRow;
}
}
static inline void convertFromData(const uint8* sourceRows, unsigned sourceBytesPerRow,
uint8* destRows, unsigned destBytesPerRow,
unsigned rows, unsigned columns)
{
for (unsigned y = 0; y < rows; y++) {
const uint8* sourcePixel = sourceRows;
uint8* destPixel = destRows;
for (unsigned x = 0; x < columns; x++) {
destPixel[0] = sourcePixel[2];
destPixel[1] = sourcePixel[1];
destPixel[2] = sourcePixel[0];
destPixel[3] = sourcePixel[3];
destPixel += 4;
sourcePixel += 4;
}
sourceRows += sourceBytesPerRow;
destRows += destBytesPerRow;
}
}
static inline void convertFromInternalData(const uint8* sourceRows, unsigned sourceBytesPerRow,
uint8* destRows, unsigned destBytesPerRow,
unsigned rows, unsigned columns,
bool premultiplied)
{
if (premultiplied) {
for (unsigned y = 0; y < rows; y++) {
const uint8* sourcePixel = sourceRows;
uint8* destPixel = destRows;
for (unsigned x = 0; x < columns; x++) {
destPixel[0] = static_cast<uint16>(sourcePixel[2]) * sourcePixel[3] / 255;
destPixel[1] = static_cast<uint16>(sourcePixel[1]) * sourcePixel[3] / 255;
destPixel[2] = static_cast<uint16>(sourcePixel[0]) * sourcePixel[3] / 255;
destPixel[3] = sourcePixel[3];
destPixel += 4;
sourcePixel += 4;
}
sourceRows += sourceBytesPerRow;
destRows += destBytesPerRow;
}
} else {
convertFromData(sourceRows, sourceBytesPerRow,
destRows, destBytesPerRow,
rows, columns);
}
}
static inline void convertToInternalData(const uint8* sourceRows, unsigned sourceBytesPerRow,
uint8* destRows, unsigned destBytesPerRow,
unsigned rows, unsigned columns,
bool premultiplied)
{
if (premultiplied) {
for (unsigned y = 0; y < rows; y++) {
const uint8* sourcePixel = sourceRows;
uint8* destPixel = destRows;
for (unsigned x = 0; x < columns; x++) {
if (sourcePixel[3]) {
destPixel[0] = static_cast<uint16>(sourcePixel[2]) * 255 / sourcePixel[3];
destPixel[1] = static_cast<uint16>(sourcePixel[1]) * 255 / sourcePixel[3];
destPixel[2] = static_cast<uint16>(sourcePixel[0]) * 255 / sourcePixel[3];
destPixel[3] = sourcePixel[3];
} else {
destPixel[0] = 0;
destPixel[1] = 0;
destPixel[2] = 0;
destPixel[3] = 0;
}
destPixel += 4;
sourcePixel += 4;
}
sourceRows += sourceBytesPerRow;
destRows += destBytesPerRow;
}
} else {
convertFromData(sourceRows, sourceBytesPerRow,
destRows, destBytesPerRow,
rows, columns);
}
}
static PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size, bool premultiplied)
{
PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
unsigned char* data = result->data()->data()->data();
if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height())
memset(data, 0, result->data()->length());
if (rect.x() > size.width() || rect.y() > size.height() || rect.right() < 0 || rect.bottom() < 0)
return result;
BRect sourceRect(0, 0, size.width() - 1, size.height() - 1);
sourceRect = BRect(rect) & sourceRect;
unsigned destBytesPerRow = 4 * rect.width();
unsigned char* destRows = data;
destRows += (rect.x() - static_cast<int>(sourceRect.left)) * 4
+ (rect.y() - static_cast<int>(sourceRect.top)) * destBytesPerRow;
const uint8* sourceRows = reinterpret_cast<const uint8*>(imageData.m_bitmap.Bits());
uint32 sourceBytesPerRow = imageData.m_bitmap.BytesPerRow();
sourceRows += static_cast<int>(sourceRect.left) * 4
+ static_cast<int>(sourceRect.top) * sourceBytesPerRow;
unsigned rows = sourceRect.IntegerHeight() + 1;
unsigned columns = sourceRect.IntegerWidth() + 1;
convertFromInternalData(sourceRows, sourceBytesPerRow, destRows, destBytesPerRow,
rows, columns, premultiplied);
return result;
}
PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
{
m_data.m_view.Sync();
return getImageData(rect, m_data, m_size, false);
}
PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
{
m_data.m_view.Sync();
return getImageData(rect, m_data, m_size, true);
}
static void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size, bool premultiplied)
{
if (destPoint.x() > size.width() || destPoint.y() > size.height()
|| destPoint.x() + sourceRect.width() < 0
|| destPoint.y() + sourceRect.height() < 0) {
return;
}
const unsigned char* sourceRows = source->data()->data()->data();
unsigned sourceBytesPerRow = 4 * source->width();
sourceRows += sourceRect.x() * 4 + sourceRect.y() * sourceBytesPerRow;
BRect destRect(destPoint.x(), destPoint.y(), sourceRect.width() - 1, sourceRect.height() - 1);
destRect = destRect & BRect(0, 0, size.width() - 1, size.height() - 1);
unsigned char* destRows = reinterpret_cast<unsigned char*>(imageData.m_bitmap.Bits());
uint32 destBytesPerRow = imageData.m_bitmap.BytesPerRow();
destRows += static_cast<int>(destRect.left) * 4
+ static_cast<int>(destRect.top) * destBytesPerRow;
unsigned rows = sourceRect.height();
unsigned columns = sourceRect.width();
convertToInternalData(sourceRows, sourceBytesPerRow, destRows, destBytesPerRow,
rows, columns, premultiplied);
}
void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
{
m_data.m_view.Sync();
putImageData(source, sourceRect, destPoint, m_data, m_size, false);
}
void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
{
m_data.m_view.Sync();
putImageData(source, sourceRect, destPoint, m_data, m_size, true);
}
String ImageBuffer::toDataURL(const String& mimeType) const
{
if (!MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType))
return "data:,";
BString mimeTypeString(mimeType);
uint32 translatorType = 0;
BTranslatorRoster* roster = BTranslatorRoster::Default();
translator_id* translators;
int32 translatorCount;
roster->GetAllTranslators(&translators, &translatorCount);
for (int32 i = 0; i < translatorCount; i++) {
const translation_format* inputFormats;
int32 formatCount;
roster->GetInputFormats(translators[i], &inputFormats, &formatCount);
bool supportsBitmaps = false;
for (int32 j = 0; j < formatCount; j++) {
if (inputFormats[j].type == B_TRANSLATOR_BITMAP) {
supportsBitmaps = true;
break;
}
}
if (!supportsBitmaps)
continue;
const translation_format* outputFormats;
roster->GetOutputFormats(translators[i], &outputFormats, &formatCount);
for (int32 j = 0; j < formatCount; j++) {
if (outputFormats[j].group == B_TRANSLATOR_BITMAP
&& mimeTypeString == outputFormats[j].MIME) {
translatorType = outputFormats[j].type;
}
}
if (translatorType)
break;
}
BMallocIO translatedStream;
BBitmap* bitmap = const_cast<BBitmap*>(&m_data.m_bitmap);
BBitmapStream bitmapStream(bitmap);
if (roster->Translate(&bitmapStream, 0, 0, &translatedStream, translatorType,
B_TRANSLATOR_BITMAP, mimeType.utf8().data()) != B_OK) {
bitmapStream.DetachBitmap(&bitmap);
return "data:,";
}
bitmapStream.DetachBitmap(&bitmap);
Vector<char> encodedBuffer;
base64Encode(reinterpret_cast<const char*>(translatedStream.Buffer()),
translatedStream.BufferLength(), encodedBuffer);
return String::format("data:%s;base64,%s", mimeType.utf8().data(),
encodedBuffer.data());
}
}