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:
parent
ccb74eabcc
commit
8ac0d542b0
@ -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
|
||||
|
@ -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">
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
|
@ -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"', {
|
||||
|
@ -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&);
|
||||
|
@ -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);
|
||||
|
@ -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,6 +689,15 @@ SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
@ -718,6 +741,7 @@ SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fUseClip) {
|
||||
canvas->drawColor(0xFFFF88FF);
|
||||
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user