adding support for toDataURL and toDataURLAs on canvas. bug 245684. patches from Brett Wilson <brettw@gmail.com>. r=me, sr=vlad

This commit is contained in:
pavlov%pavlov.net 2005-08-31 22:16:51 +00:00
Родитель a80cc79252
Коммит 3ce096343b
4 изменённых файлов: 133 добавлений и 1 удалений

Просмотреть файл

@ -42,6 +42,7 @@
#include "nsPresContext.h"
#include "gfxIImageFrame.h"
#include "nsICanvasElement.h"
#include "nsIInputStream.h"
// {0be74436-51a3-4be3-8357-ede741750080}
#define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
@ -58,6 +59,16 @@ public:
// Will be called whenever the target image frame changes
NS_IMETHOD SetTargetImageFrame(gfxIImageFrame* aImageFrame) = 0;
// Gives you a stream containing the image represented by this context.
// The format is given in aMimeTime, for example "image/png".
//
// If the image format does not support transparency or aIncludeTransparency
// is false, alpha will be discarded and the result will be the image
// composited on black.
NS_IMETHOD GetInputStream(const nsACString& aMimeType,
const nsAString& aEncoderOptions,
nsIInputStream **aStream) = 0;
// Will be called whenever the element needs to be redrawn,
// e.g. due to a Redraw on the frame.
NS_IMETHOD UpdateImageFrame() = 0;

Просмотреть файл

@ -77,6 +77,7 @@
#include "nsIDOMWindow.h"
#include "cairo.h"
#include "imgIEncoder.h"
static NS_DEFINE_IID(kBlenderCID, NS_BLENDER_CID);
@ -198,6 +199,9 @@ public:
// nsICanvasRenderingContextInternal
NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
NS_IMETHOD SetTargetImageFrame(gfxIImageFrame* aImageFrame);
NS_IMETHOD GetInputStream(const nsACString& aMimeType,
const nsAString& aEncoderOptions,
nsIInputStream **aStream);
NS_IMETHOD UpdateImageFrame();
// nsISupports interface
@ -537,6 +541,26 @@ nsCanvasRenderingContext2D::SetTargetImageFrame(gfxIImageFrame* aImageFrame)
return ClearRect (0, 0, mWidth, mHeight);
}
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetInputStream(const nsACString& aMimeType,
const nsAString& aEncoderOptions,
nsIInputStream **aStream)
{
nsCString conid(NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type="));
conid += aMimeType;
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid.get());
if (!encoder)
return NS_ERROR_FAILURE;
encoder->InitFromData(mSurfaceData,
mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4,
imgIEncoder::INPUT_FORMAT_HOSTARGB,
aEncoderOptions);
return CallQueryInterface(encoder, aStream);
}
NS_IMETHODIMP
nsCanvasRenderingContext2D::UpdateImageFrame()

Просмотреть файл

@ -45,6 +45,9 @@
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsNodeInfoManager.h"
#include "plbase64.h"
#include "nsNetUtil.h"
#include "prmem.h"
#include "nsICanvasElement.h"
@ -251,6 +254,91 @@ nsHTMLCanvasElement::ParseAttribute(nsIAtom* aAttribute,
return nsGenericHTMLElement::ParseAttribute(aAttribute, aValue, aResult);
}
// nsHTMLCanvasElement::toDataURL
//
// This is the version in the spec, it returns a PNG with transparency
NS_IMETHODIMP
nsHTMLCanvasElement::ToDataURL(nsAString& aDataURL)
{
return ToDataURLAs(NS_LITERAL_STRING("image/png"), EmptyString(),
aDataURL);
}
// nsHTMLCanvasElement::toDataURLAs
//
// http://www.mozilla.org/quality/networking/docs/aboutdata.html
//
// Get the data
// encode it as PNG
// base64 encode it
NS_IMETHODIMP
nsHTMLCanvasElement::ToDataURLAs(const nsAString& aMimeType,
const nsAString& aEncoderOptions,
nsAString& aDataURL)
{
nsresult rv;
// We get an input stream from the context. If more than one context type
// is supported in the future, this will have to be changed to do the right
// thing. For now, just assume that the 2D context has all the goods.
nsCOMPtr<nsICanvasRenderingContextInternal> context;
rv = GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(context));
NS_ENSURE_SUCCESS(rv, rv);
// get image bytes
nsCOMPtr<nsIInputStream> imgStream;
NS_ConvertUTF16toUTF8 aMimeType8(aMimeType);
rv = context->GetInputStream(aMimeType8, aEncoderOptions,
getter_AddRefs(imgStream));
NS_ENSURE_SUCCESS(rv, rv);
// Generally, there will be only one chunk of data, and it will be available
// for us to read right away, so optimize this case.
PRUint32 bufSize;
rv = imgStream->Available(&bufSize);
NS_ENSURE_SUCCESS(rv, rv);
// ...leave a little extra room so we can call read again and make sure we
// got everything. 16 bytes for better padding (maybe)
bufSize += 16;
PRUint32 imgSize = 0;
char* imgData = (char*)PR_Malloc(bufSize);
if (! imgData)
return NS_ERROR_OUT_OF_MEMORY;
PRUint32 numReadThisTime = 0;
while ((rv = imgStream->Read(&imgData[imgSize], bufSize - imgSize,
&numReadThisTime)) == NS_OK && numReadThisTime > 0) {
imgSize += numReadThisTime;
if (imgSize == bufSize) {
// need a bigger buffer, just double
bufSize *= 2;
char* newImgData = (char*)PR_Realloc(imgData, bufSize);
if (! newImgData) {
PR_Free(imgData);
return NS_ERROR_OUT_OF_MEMORY;
}
imgData = newImgData;
}
}
// base 64, result will be NULL terminated
char* encodedImg = PL_Base64Encode(imgData, imgSize, nsnull);
PR_Free(imgData);
if (!encodedImg) // not sure why this would fail
return NS_ERROR_OUT_OF_MEMORY;
// build data URL string
aDataURL = NS_LITERAL_STRING("data:") + aMimeType +
NS_LITERAL_STRING(";base64,") + NS_ConvertUTF8toUTF16(encodedImg);
PR_Free(encodedImg);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
nsISupports **aContext)

Просмотреть файл

@ -49,12 +49,21 @@
// XXX This should inherit from nsIDOMHTMLImageElement instead,
// and implement that interface as well.
[scriptable, uuid(332dd7d0-97e2-44a0-af5b-1c3bafb0b1f2)]
[scriptable, uuid(d0090186-a2b1-4591-9160-e1f044c69da0)]
interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement
{
attribute long width;
attribute long height;
DOMString toDataURL();
// This version lets you specify different image types and pass parameters
// to the encoder. For example toDataURLAs("image/png", "transparency=none")
// gives you a PNG with the alpha channel discarded. See the encoder for
// the options string that it supports. Separate multiple options with
// semicolons.
DOMString toDataURLAs(in DOMString mimeType, in DOMString encoderOptions);
nsISupports getContext(in DOMString contextId);
};