ImageBufferSkia.cpp [plain text]
#include "config.h"
#include "ImageBuffer.h"
#include "Base64.h"
#include "BitmapImage.h"
#include "BitmapImageSingleFrameSkia.h"
#include "GraphicsContext.h"
#include "ImageData.h"
#include "PlatformContextSkia.h"
#include "PNGImageEncoder.h"
#include "SkiaUtils.h"
using namespace std;
namespace WebCore {
ImageBufferData::ImageBufferData(const IntSize& size)
: m_platformContext(0) {
}
ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
: m_data(size)
, m_size(size)
{
if (!m_data.m_canvas.initialize(size.width(), size.height(), false)) {
success = false;
return;
}
m_data.m_platformContext.setCanvas(&m_data.m_canvas);
m_context.set(new GraphicsContext(&m_data.m_platformContext));
#if PLATFORM(WIN_OS)
m_context->platformContext()->setDrawingToImageBuffer(true);
#endif
m_data.m_canvas.drawARGB(0, 0, 0, 0, SkPorterDuff::kClear_Mode);
success = true;
}
ImageBuffer::~ImageBuffer()
{
}
GraphicsContext* ImageBuffer::context() const
{
return m_context.get();
}
Image* ImageBuffer::image() const
{
if (!m_image) {
m_image = BitmapImageSingleFrameSkia::create(
*m_data.m_platformContext.bitmap());
}
return m_image.get();
}
PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
{
ASSERT(context());
RefPtr<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()) > m_size.width() ||
(rect.y() + rect.height()) > m_size.height())
memset(data, 0, result->data()->length());
int originX = rect.x();
int destX = 0;
if (originX < 0) {
destX = -originX;
originX = 0;
}
int endX = rect.x() + rect.width();
if (endX > m_size.width())
endX = m_size.width();
int numColumns = endX - originX;
int originY = rect.y();
int destY = 0;
if (originY < 0) {
destY = -originY;
originY = 0;
}
int endY = rect.y() + rect.height();
if (endY > m_size.height())
endY = m_size.height();
int numRows = endY - originY;
const SkBitmap& bitmap = *context()->platformContext()->bitmap();
ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
SkAutoLockPixels bitmapLock(bitmap);
unsigned destBytesPerRow = 4 * rect.width();
unsigned char* destRow = data + destY * destBytesPerRow + destX * 4;
for (int y = 0; y < numRows; ++y) {
uint32_t* srcRow = bitmap.getAddr32(originX, originY + y);
for (int x = 0; x < numColumns; ++x) {
SkColor color = SkPMColorToColor(srcRow[x]);
unsigned char* destPixel = &destRow[x * 4];
destPixel[0] = SkColorGetR(color);
destPixel[1] = SkColorGetG(color);
destPixel[2] = SkColorGetB(color);
destPixel[3] = SkColorGetA(color);
}
destRow += destBytesPerRow;
}
return result;
}
void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect,
const IntPoint& destPoint)
{
ASSERT(sourceRect.width() > 0);
ASSERT(sourceRect.height() > 0);
int originX = sourceRect.x();
int destX = destPoint.x() + sourceRect.x();
ASSERT(destX >= 0);
ASSERT(destX < m_size.width());
ASSERT(originX >= 0);
ASSERT(originX < sourceRect.right());
int endX = destPoint.x() + sourceRect.right();
ASSERT(endX <= m_size.width());
int numColumns = endX - destX;
int originY = sourceRect.y();
int destY = destPoint.y() + sourceRect.y();
ASSERT(destY >= 0);
ASSERT(destY < m_size.height());
ASSERT(originY >= 0);
ASSERT(originY < sourceRect.bottom());
int endY = destPoint.y() + sourceRect.bottom();
ASSERT(endY <= m_size.height());
int numRows = endY - destY;
const SkBitmap& bitmap = *context()->platformContext()->bitmap();
ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
SkAutoLockPixels bitmapLock(bitmap);
unsigned srcBytesPerRow = 4 * source->width();
const unsigned char* srcRow = source->data()->data()->data() + originY * srcBytesPerRow + originX * 4;
for (int y = 0; y < numRows; ++y) {
uint32_t* destRow = bitmap.getAddr32(destX, destY + y);
for (int x = 0; x < numColumns; ++x) {
const unsigned char* srcPixel = &srcRow[x * 4];
destRow[x] = SkPreMultiplyARGB(srcPixel[3], srcPixel[0],
srcPixel[1], srcPixel[2]);
}
srcRow += srcBytesPerRow;
}
}
String ImageBuffer::toDataURL(const String&) const
{
Vector<unsigned char> pngEncodedData;
PNGImageEncoder::encode(*context()->platformContext()->bitmap(), &pngEncodedData);
Vector<char> base64EncodedData;
base64Encode(*reinterpret_cast<Vector<char>*>(&pngEncodedData), base64EncodedData);
base64EncodedData.append('\0');
return String::format("data:image/png;base64,%s", base64EncodedData.data());
}
}