Add a way to save to PDF in SampleApp on Android and elsewhere.

In Android, add the PDF file to downloads, so it can be opened.

Reviewed at http://codereview.appspot.com/4638052/


git-svn-id: http://skia.googlecode.com/svn/trunk@1659 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Scroggo 2011-06-21 14:44:57 +00:00
parent ccb74eabcc
commit 8ac0d542b0
11 changed files with 203 additions and 44 deletions

View File

@ -40,6 +40,7 @@ LOCAL_C_INCLUDES += \
external/skia/src/core \
external/skia/gpu/include \
frameworks/base/opengl/include/GLES2 \
external/skia/include/pdf \
$(LOCAL_PATH)/jni
LOCAL_SHARED_LIBRARIES := \
@ -60,6 +61,18 @@ LOCAL_MODULE := libskia-sample
LOCAL_SRC_FILES := \
../../src/ports/SkXMLParser_empty.cpp \
../../src/pdf/SkPDFCatalog.cpp \
../../src/pdf/SkPDFDevice.cpp \
../../src/pdf/SkPDFDocument.cpp \
../../src/pdf/SkPDFFont.cpp \
../../src/pdf/SkPDFFormXObject.cpp \
../../src/pdf/SkPDFGraphicState.cpp \
../../src/pdf/SkPDFImage.cpp \
../../src/pdf/SkPDFPage.cpp \
../../src/pdf/SkPDFShader.cpp \
../../src/pdf/SkPDFStream.cpp \
../../src/pdf/SkPDFTypes.cpp \
../../src/pdf/SkPDFUtils.cpp \
jni/sample-jni.cpp
include external/skia/src/views/views_files.mk

View File

@ -17,6 +17,10 @@
package="com.skia.sampleapp"
android:versionCode="1"
android:versionName="1.0">
<!-- Needed to save a file to the file system. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- Needed to add to the download manager. -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-sdk android:minSdkVersion="3" />
<application android:label="@string/app_name"
android:debuggable="true">

View File

@ -38,11 +38,13 @@ struct ActivityGlue {
jweak m_obj;
jmethodID m_setTitle;
jmethodID m_startTimer;
jmethodID m_addToDownloads;
ActivityGlue() {
m_env = NULL;
m_obj = NULL;
m_setTitle = NULL;
m_startTimer = NULL;
m_addToDownloads = NULL;
}
} gActivityGlue;
@ -82,6 +84,24 @@ void SkOSWindow::onHandleInval(const SkIRect& rect)
gActivityGlue.m_env->CallVoidMethod(gWindowGlue.m_obj, gWindowGlue.m_inval);
}
void SkOSWindow::onPDFSaved(const char title[], const char desc[],
const char path[])
{
if (gActivityGlue.m_env) {
JNIEnv* env = gActivityGlue.m_env;
jstring jtitle = env->NewStringUTF(title);
jstring jdesc = env->NewStringUTF(desc);
jstring jpath = env->NewStringUTF(path);
env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_addToDownloads,
jtitle, jdesc, jpath);
env->DeleteLocalRef(jtitle);
env->DeleteLocalRef(jdesc);
env->DeleteLocalRef(jpath);
}
}
///////////////////////////////////////////
/////////////// SkEvent impl //////////////
///////////////////////////////////////////
@ -151,6 +171,8 @@ JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_processSkEvent(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_serviceQueueTimer(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_saveToPdf(
JNIEnv* env, jobject thiz);
};
JNIEXPORT bool JNICALL Java_com_skia_sampleapp_SampleApp_handleKeyDown(
@ -217,6 +239,8 @@ JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_init(JNIEnv* env,
gActivityGlue.m_obj = env->NewWeakGlobalRef(thiz);
gActivityGlue.m_setTitle = GetJMethod(env, clazz, "setTitle",
"(Ljava/lang/CharSequence;)V");
gActivityGlue.m_addToDownloads = GetJMethod(env, clazz, "addToDownloads",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
gActivityGlue.m_startTimer = GetJMethod(gActivityGlue.m_env, clazz,
"startTimer", "(I)V");
env->DeleteLocalRef(clazz);
@ -343,3 +367,9 @@ JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_serviceQueueTimer(
{
SkEvent::ServiceQueueTimer();
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_saveToPdf(
JNIEnv* env, jobject thiz)
{
gWindow->saveToPdf();
}

View File

@ -43,7 +43,8 @@
android:id="@+id/slideshow"
android:title="@string/slideshow"
/>
<!--
android:icon="@drawable/ic_menu_new_window"
-->
<item
android:id="@+id/save_to_pdf"
android:title="@string/save_to_pdf"
/>
</menu>

View File

@ -13,10 +13,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">SampleApp</string>
<string name="overview">Overview</string>
<string name="toggle_rendering">Toggle rendering</string>
<string name="slideshow">Slideshow</string>
<string name="fps">FPS</string>
<string name="file_saved"><xliff:g id="title">%s1</xliff:g> saved!</string>
<string name="failed">PDF creation failed</string>
<string name="save_to_pdf">Save as PDF</string>
</resources>

View File

@ -17,6 +17,7 @@
package com.skia.sampleapp;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.graphics.Canvas;
import android.opengl.GLSurfaceView;
@ -32,10 +33,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import java.io.File;
public class SampleApp extends Activity
{
private TextView mTitle;
@ -126,6 +130,15 @@ public class SampleApp extends Activity
}
});
return true;
case R.id.save_to_pdf:
mView.queueEvent(new Runnable() {
@Override
public void run() {
saveToPdf();
}
});
return true;
default:
return false;
}
@ -164,6 +177,7 @@ public class SampleApp extends Activity
}
private static final int SET_TITLE = 1;
private static final int TOAST_DOWNLOAD = 2;
private Handler mHandler = new Handler() {
@Override
@ -173,6 +187,10 @@ public class SampleApp extends Activity
mTitle.setText((String) msg.obj);
SampleApp.this.getActionBar().setSubtitle((String) msg.obj);
break;
case TOAST_DOWNLOAD:
Toast.makeText(SampleApp.this, (String) msg.obj,
Toast.LENGTH_SHORT).show();
break;
default:
break;
}
@ -184,6 +202,30 @@ public class SampleApp extends Activity
mHandler.obtainMessage(SET_TITLE, title).sendToTarget();
}
// Called by JNI
@SuppressWarnings("unused")
private void addToDownloads(final String title, final String desc,
final String path) {
File file = new File(path);
final long length = file.exists() ? file.length() : 0;
if (length == 0) {
String failed = getString(R.string.failed);
mHandler.obtainMessage(TOAST_DOWNLOAD, failed).sendToTarget();
return;
}
String toast = getString(R.string.file_saved).replace("%s", title);
mHandler.obtainMessage(TOAST_DOWNLOAD, toast).sendToTarget();
final DownloadManager manager = (DownloadManager) getSystemService(
Context.DOWNLOAD_SERVICE);
new Thread("Add pdf to downloads") {
@Override
public void run() {
manager.addCompletedDownload(title, desc, true,
"application/pdf", path, length, true);
}
}.start();
}
// Called by JNI
@SuppressWarnings("unused")
private void startTimer(int ms) {
@ -217,6 +259,7 @@ public class SampleApp extends Activity
native void toggleFps();
native void processSkEvent();
native void serviceQueueTimer();
native void saveToPdf();
static {
System.loadLibrary("skia-sample");

View File

@ -132,6 +132,7 @@
'experimental.gyp:experimental',
'gpu.gyp:gr',
'gpu.gyp:skgr',
'pdf.gyp:pdf',
],
'conditions' : [
[ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', {

View File

@ -29,6 +29,9 @@ public:
void detachGL() {}
void presentGL() {}
virtual void onPDFSaved(const char title[], const char desc[],
const char path[]);
protected:
// overrides from SkWindow
virtual void onHandleInval(const SkIRect&);

View File

@ -70,6 +70,8 @@ public:
void preConcat(const SkMatrix&);
void postConcat(const SkMatrix&);
virtual void onPDFSaved(const char title[], const char desc[],
const char path[]) {}
protected:
virtual bool onEvent(const SkEvent&);
virtual bool onDispatchClick(int x, int y, Click::State);

View File

@ -18,6 +18,10 @@
#include "GrGLInterface.h"
#include "SkPDFDevice.h"
#include "SkPDFDocument.h"
#include "SkStream.h"
#define TEST_GPIPEx
#ifdef TEST_GPIPE
@ -383,6 +387,9 @@ SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
fZoomLevel = 0;
fZoomScale = SK_Scalar1;
fSaveToPdf = false;
fPdfCanvas = NULL;
// this->setConfig(SkBitmap::kRGB_565_Config);
this->setConfig(SkBitmap::kARGB_8888_Config);
this->setVisibleP(true);
@ -412,6 +419,7 @@ SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
SampleWindow::~SampleWindow() {
delete fPicture;
delete fGpuCanvas;
delete fPdfCanvas;
if (NULL != fGrContext) {
fGrContext->unref();
}
@ -549,7 +557,7 @@ void SampleWindow::draw(SkCanvas* canvas) {
} else {
this->INHERITED::draw(canvas);
}
if (fShowZoomer && fCanvasType != kGPU_CanvasType) {
if (fShowZoomer && fCanvasType != kGPU_CanvasType && !fSaveToPdf) {
// In the GPU case, INHERITED::draw calls beforeChildren, which
// creates an SkGpuCanvas. All further draw calls are directed
// at that canvas, which is deleted in afterChildren (which is
@ -668,6 +676,12 @@ static void reverseRedAndBlue(const SkBitmap& bm) {
}
}
void SampleWindow::saveToPdf()
{
fSaveToPdf = true;
this->inval(NULL);
}
SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
if (kGPU_CanvasType != fCanvasType) {
#ifdef SK_SUPPORT_GL
@ -675,47 +689,57 @@ SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
#endif
}
switch (fCanvasType) {
case kRaster_CanvasType:
canvas = this->INHERITED::beforeChildren(canvas);
break;
case kPicture_CanvasType:
fPicture = new SkPicture;
canvas = fPicture->beginRecording(9999, 9999);
break;
case kGPU_CanvasType: {
if (make3DReady()) {
SkDevice* device = canvas->getDevice();
const SkBitmap& bitmap = device->accessBitmap(true);
GrRenderTarget* renderTarget;
GrPlatformSurfaceDesc desc;
desc.reset();
desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
desc.fWidth = bitmap.width();
desc.fHeight = bitmap.height();
desc.fConfig = kRGBA_8888_GrPixelConfig;
desc.fStencilBits = 8;
GrGLint buffer;
GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, &buffer);
desc.fPlatformRenderTarget = buffer;
renderTarget = static_cast<GrRenderTarget*>(
fGrContext->createPlatformSurface(desc));
fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
renderTarget->unref();
device = new SkGpuDevice(fGrContext, renderTarget);
fGpuCanvas->setDevice(device)->unref();
fGpuCanvas->concat(canvas->getTotalMatrix());
canvas = fGpuCanvas;
} else {
if (fSaveToPdf) {
const SkBitmap& bmp = canvas->getDevice()->accessBitmap(false);
SkISize size = SkISize::Make(bmp.width(), bmp.height());
SkPDFDevice* pdfDevice = new SkPDFDevice(size, size,
canvas->getTotalMatrix());
fPdfCanvas = new SkCanvas(pdfDevice);
pdfDevice->unref();
canvas = fPdfCanvas;
} else {
switch (fCanvasType) {
case kRaster_CanvasType:
canvas = this->INHERITED::beforeChildren(canvas);
break;
case kPicture_CanvasType:
fPicture = new SkPicture;
canvas = fPicture->beginRecording(9999, 9999);
break;
case kGPU_CanvasType: {
if (make3DReady()) {
SkDevice* device = canvas->getDevice();
const SkBitmap& bitmap = device->accessBitmap(true);
GrRenderTarget* renderTarget;
GrPlatformSurfaceDesc desc;
desc.reset();
desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
desc.fWidth = bitmap.width();
desc.fHeight = bitmap.height();
desc.fConfig = kRGBA_8888_GrPixelConfig;
desc.fStencilBits = 8;
GrGLint buffer;
GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, &buffer);
desc.fPlatformRenderTarget = buffer;
renderTarget = static_cast<GrRenderTarget*>(
fGrContext->createPlatformSurface(desc));
fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
renderTarget->unref();
device = new SkGpuDevice(fGrContext, renderTarget);
fGpuCanvas->setDevice(device)->unref();
fGpuCanvas->concat(canvas->getTotalMatrix());
canvas = fGpuCanvas;
} else {
canvas = this->INHERITED::beforeChildren(canvas);
}
break;
}
break;
}
}
@ -738,6 +762,34 @@ static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
}
void SampleWindow::afterChildren(SkCanvas* orig) {
if (fSaveToPdf) {
fSaveToPdf = false;
if (fShowZoomer) {
showZoomer(fPdfCanvas);
}
SkString name;
name.printf("%s.pdf", this->getTitle());
SkPDFDocument doc;
SkPDFDevice* device = static_cast<SkPDFDevice*>(fPdfCanvas->getDevice());
doc.appendPage(device);
#ifdef ANDROID
name.prepend("/sdcard/");
#endif
SkFILEWStream stream(name.c_str());
if (stream.isValid()) {
doc.emitPDF(&stream);
const char* desc = "File saved from Skia SampleApp";
this->onPDFSaved(this->getTitle(), desc, name.c_str());
}
delete fPdfCanvas;
fPdfCanvas = NULL;
// We took over the draw calls in order to create the PDF, so we need
// to redraw.
this->inval(NULL);
return;
}
if (fRequestGrabImage) {
fRequestGrabImage = false;
@ -1005,6 +1057,9 @@ bool SampleWindow::onHandleChar(SkUnichar uni) {
case 'd':
SkGraphics::SetFontCacheUsed(0);
return true;
case 'e':
this->saveToPdf();
break;
case 'f':
this->toggleFPS();
break;

View File

@ -60,6 +60,7 @@ public:
bool previousSample();
bool handleTouch(int ownerId, float x, float y,
SkView::Click::State state);
void saveToPdf();
protected:
virtual void onDraw(SkCanvas* canvas);
@ -98,6 +99,9 @@ private:
};
CanvasType fCanvasType;
bool fSaveToPdf;
SkCanvas* fPdfCanvas;
bool fUseClip;
bool fNClip;
bool fRepeatDrawing;