📄 graphicsmodule.cpp
字号:
/**
* ====================================================================
* graphicsmodule.cpp
*
* Copyright (c) 2005-2008 Nokia Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Python.h"
#include "symbian_python_ext_util.h"
#if SERIES60_VERSION > 12
#define ICL_SUPPORT
#endif
#include <e32std.h>
#include <w32std.h>
#include <eikenv.h>
#include <f32file.h>
#include <s32mem.h>
#include <apmstd.h>
#include <apparc.h>
#include <aknenv.h>
#include <aknappui.h>
#include <aknapp.h>
#include <eikon.hrh> // Form
#include <avkon.hrh>
#include <avkon.rsg>
#include <eikedwin.h> // Form
#include <eikcapc.h> // Form
#include <txtfrmat.h> // Text
#include <txtfmlyr.h> // Text
#include <eikgted.h> // Text
#include <eikrted.h> // RText
#include <txtrich.h>
#include <gdi.h> // RText
#include <aknlists.h>
#include <aknselectionlist.h>
#include <aknquerydialog.h>
#include <akntitle.h>
#include <aknnotewrappers.h>
#include <aknPopup.h>
#include <AknForm.h>
#include <documenthandler.h>
#ifdef ICL_SUPPORT
#include <ImageConversion.h>
#include <BitmapTransforms.h>
#endif
#include "colorspec.cpp"
#include "fontspec.cpp"
//#include <ImageCodecData.h>
#ifdef EKA2
#include <akniconutils.h>
#endif
#define PY_RETURN_NONE do { \
Py_INCREF(Py_None); \
return Py_None; \
} while (0) \
// ******** Image object
/*
* A helper function for the implementation of callbacks
* from C/C++ code to Python callables
*/
static TInt app_callback_handler(void* func, void* arg);
static TInt app_callback_handler(void* func, void* arg)
{
TInt error = KErrNone;
PyObject* rval = PyEval_CallObject((PyObject*)func, (PyObject*)arg);
if (!rval) {
error = KErrPython;
if (PyErr_Occurred() == PyExc_OSError) {
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback);
if (PyInt_Check(value))
error = PyInt_AS_LONG(value);
}
}
else
Py_DECREF(rval);
return error;
}
// Helper function for extracting C API's from objects.
static PyObject *
PyCAPI_GetCAPI(PyObject *object,
const char *apiname)
{
PyObject *capi_func=NULL;
PyObject *capi_cobject=NULL;
if (!(capi_func=PyObject_GetAttrString(object,(char *)apiname)) ||
!PyCallable_Check(capi_func) ||
!(capi_cobject=PyObject_CallObject(capi_func,NULL)) ||
!(PyCObject_Check(capi_cobject))) {
Py_XDECREF(capi_func);
Py_XDECREF(capi_cobject);
return NULL;
}
Py_DECREF(capi_func);
return capi_cobject;
}
/*
* Compute how many coordinate pairs are in the given coordinate sequence.
* Store result in *length.
*
* Return: 1 if successful, 0 if error.
*/
static int
PyCoordSeq_Length(PyObject *coordseq_obj, int *length)
{
#define ERROR(msg) do { PyErr_SetString(PyExc_ValueError,"invalid coordinates: " msg); goto error; } while(0)
PyObject *item=NULL, *subitem=NULL;
int seq_len=0;
if (!PySequence_Check(coordseq_obj))
ERROR("not a sequence");
seq_len=PySequence_Length(coordseq_obj);
item=PySequence_GetItem(coordseq_obj,0);
if (!item)
goto error; // propagate error;
if (PyInt_Check(item)||PyFloat_Check(item)) { // Coordinate sequence style (x,y,x,y,x,y...)
if (seq_len % 2)
ERROR("sequence length is odd");
Py_DECREF(item);
*length=seq_len/2;
return 1;
} else if (PySequence_Check(item)) { // Coordinate sequence style ((x,y),(x,y),(x,y)...)
subitem=PySequence_GetItem(item,0);
if (!subitem)
goto error; // propagate error;
if (!PyInt_Check(subitem) && !PyFloat_Check(subitem))
ERROR("non-number in sequence");
Py_DECREF(subitem);
Py_DECREF(item);
*length=seq_len;
return 1;
} else
ERROR("sequence of numbers or 2-tuples expected");
error:
Py_XDECREF(subitem);
Py_XDECREF(item);
return NULL;
}
/*
* Get a coordinate pair out of the given coordinate sequence.
* Store result in *x, *y.
* Return: 1 if successful, 0 if error.
*/
static int
PyCoordSeq_GetItem(PyObject *coordseq_obj, int index, int *x, int *y)
{
int seq_len=PySequence_Length(coordseq_obj);
PyObject *item=NULL, *x_obj=NULL, *y_obj=NULL;
if (!PySequence_Check(coordseq_obj) || seq_len == 0)
ERROR("not a sequence or empty sequence");
item=PySequence_GetItem(coordseq_obj,0);
if (!item)
goto error; // propagate error
if (PyInt_Check(item)||PyFloat_Check(item)) { // Coordinate sequence style (x,y,x,y,x,y...)
if (!(x_obj=PySequence_GetItem(coordseq_obj,index*2)) ||
!(y_obj=PySequence_GetItem(coordseq_obj,index*2+1)))
goto error; // propagate error
} else if (PySequence_Check(item)) { // Coordinate sequence style ((x,y),(x,y),(x,y)...)
Py_DECREF(item);
if (!(item=PySequence_GetItem(coordseq_obj,index)) ||
!(x_obj=PySequence_GetItem(item,0)) ||
!(y_obj=PySequence_GetItem(item,1)))
goto error;
} else
ERROR("sequence of numbers or 2-tuples expected");
Py_XDECREF(item); item=NULL;
if (PyInt_Check(x_obj))
*x=PyInt_AsLong(x_obj);
else if (PyFloat_Check(x_obj))
*x=(int)PyFloat_AsDouble(x_obj);
else
ERROR("X coordinate non-numeric");
if (PyInt_Check(y_obj))
*y=PyInt_AsLong(y_obj);
else if (PyFloat_Check(y_obj))
*y=(int)PyFloat_AsDouble(y_obj);
else
ERROR("Y coordinate non-numeric");
Py_XDECREF(x_obj);
Py_XDECREF(y_obj);
return 1;
error:
Py_XDECREF(x_obj);
Py_XDECREF(y_obj);
Py_XDECREF(item);
return NULL;
#undef ERROR
}
#define IS_OBJECT(obj,name) ((obj)->ob_type==(name##_type))
static CFbsBitmap *
Bitmap_AsFbsBitmap(PyObject *obj)
{
PyObject *capi_object=PyCAPI_GetCAPI(obj,"_bitmapapi");
if (!capi_object)
return NULL;
CFbsBitmap *bitmap=(CFbsBitmap *)PyCObject_AsVoidPtr(capi_object);
Py_DECREF(capi_object);
return bitmap;
}
static int
Bitmap_Check(PyObject *obj)
{
return Bitmap_AsFbsBitmap(obj)?1:0;
}
#define PANIC(label) User::Panic(_L(label),__LINE__)
#define DEBUG_ASSERT(expr) __ASSERT_DEBUG((expr), User::Panic(_L(#expr), __LINE__))
static void
CloseFbsSession(void)
{
RFbsSession::Disconnect();
}
static void
EnsureFbsSessionIsOpen(void)
{
if (!RFbsSession::GetSession()) {
RFbsSession::Connect();
PyThread_AtExit(CloseFbsSession);
}
}
#define Image_type ((PyTypeObject*)SPyGetGlobalString("ImageType"))
struct ImageObject : public CActive {
enum ImageState {
#ifdef ICL_SUPPORT
EPendingLoad,
EPendingSave,
EPendingScale,
EPendingRotate,
#endif
ENormalIdle,
EInvalid
} iState;
enum ImageFormat {EJpeg,EPng};
ImageObject():
CActive(EPriorityStandard),
iState(EInvalid)
{
CActiveScheduler::Add(this);
}
void ConstructL(CFbsBitmap *aBitmap) {
EnsureFbsSessionIsOpen();
iBitmap=aBitmap;
iState=ENormalIdle;
}
void ConstructL(int xsize, int ysize, int mode)
{
EnsureFbsSessionIsOpen();
iBitmap=new CFbsBitmap();
TSize sz(xsize,ysize);
iBitmap->Create(sz,(enum TDisplayMode) mode);
// iBitmapDevice=CFbsBitmapDevice::NewL(iBitmap);
iState=ENormalIdle;
}
#ifdef ICL_SUPPORT
void ConstructL(TDesC& filename)
{
EnsureFbsSessionIsOpen();
iDecoder=CImageDecoder::FileNewL(FsSession(),filename);
const TFrameInfo *frmInfo=&iDecoder->FrameInfo();
iBitmap=new (ELeave) CFbsBitmap();
User::LeaveIfError(iBitmap->Create(frmInfo->iFrameCoordsInPixels.Size(),EColor64K));
//iBitmapDevice=CFbsBitmapDevice::NewL(iBitmap);
iDecoder->Convert(&iStatus, *iBitmap);
iState=EPendingLoad;
SetActive();
}
int StartLoadL(TDesC& aFilename) {
EnsureFbsSessionIsOpen();
DEBUG_ASSERT(iState == ENormalIdle);
iDecoder=CImageDecoder::FileNewL(FsSession(),aFilename);
const TFrameInfo *frmInfo=&iDecoder->FrameInfo();
if (frmInfo->iFrameCoordsInPixels != iBitmap->SizeInPixels()) {
delete iDecoder;
return 0;
}
iDecoder->Convert(&iStatus, *iBitmap);
iState=EPendingLoad;
SetActive();
return 1;
}
static void InspectFileL(TDesC& aFilename, int &aWidth, int &aHeight, int &aMode) {
EnsureFbsSessionIsOpen();
//RFs *rfs=&graphics_GetRFs();
RFs rfs;
rfs.Connect();
CImageDecoder *decoder=
CImageDecoder::FileNewL(rfs,aFilename);
const TFrameInfo *frmInfo=&decoder->FrameInfo();
aWidth=frmInfo->iFrameCoordsInPixels.Size().iWidth;
aHeight=frmInfo->iFrameCoordsInPixels.Size().iHeight;
aMode=frmInfo->iFrameDisplayMode;
delete decoder;
rfs.Close();
}
#endif // ICL_SUPPORT
~ImageObject() {
Cancel();
//delete iBitmapDevice;
delete iBitmap;
Py_XDECREF(iCompletionCallback);
iCompletionCallback=NULL;
#ifdef ICL_SUPPORT
delete iFrameImageData;
delete iEncoder;
delete iDecoder;
delete iScaler;
delete iRotator;
if (iFsSession) {
iFsSession->Close();
delete iFsSession; iFsSession=NULL;
}
#endif // ICL_SUPPORT
}
TSize Size() {
return iBitmap->SizeInPixels();
}
TSize TwipSize() {
return iBitmap->SizeInTwips();
}
void SetTwipSize(TInt aWidth, TInt aHeight) {
TSize sizeInTwip(aWidth, aHeight);
iBitmap->SetSizeInTwips(sizeInTwip);
}
TDisplayMode DisplayMode() {
return iBitmap->DisplayMode();
}
#ifdef ICL_SUPPORT
void StartSaveL(const TDesC& aFilename, ImageFormat aFormat,
int aQuality,
TPngEncodeData::TPngCompressLevel aCompressionLevel, int aBpp, int aColor) {
DEBUG_ASSERT(iState == ENormalIdle);
EnsureFbsSessionIsOpen();
switch (aFormat) {
case EJpeg: {
// For some reason iFsSession causes a KERN-EXEC 0 panic here. I have no idea why.
iEncoder = CImageEncoder::FileNewL(FsSession(), aFilename,
CImageEncoder::EOptionNone, KImageTypeJPGUid);
TJpegImageData *imageData=new (ELeave) TJpegImageData;
CleanupStack::PushL(imageData);
imageData->iSampleScheme=TJpegImageData::EColor444;
imageData->iQualityFactor=aQuality;
iFrameImageData=CFrameImageData::NewL();
iFrameImageData->AppendImageData(imageData); // assumes ownership of imageData
CleanupStack::Pop(imageData);
break;
}
case EPng: {
// For some reason iFsSession causes a KERN-EXEC 0 panic here. I have no idea why.
iEncoder = CImageEncoder::FileNewL(FsSession(), aFilename,
CImageEncoder::EOptionNone, KImageTypePNGUid);
TPngEncodeData *frameData=new (ELeave) TPngEncodeData;
CleanupStack::PushL(frameData);
frameData->iLevel=aCompressionLevel;
frameData->iBitsPerPixel=aBpp;
frameData->iColor=aColor;
frameData->iPaletted=EFalse;
iFrameImageData=CFrameImageData::NewL();
iFrameImageData->AppendFrameData(frameData); // assumes ownership of frameData
CleanupStack::Pop(frameData);
break;
}
default:
PANIC("ImageObject");
}
iEncoder->Convert(&iStatus, *iBitmap, iFrameImageData);
iState=EPendingSave;
SetActive();
}
void StartScaleL(CFbsBitmap *aTargetBitmap,int aMaintainAspectRatio=EFalse) {
DEBUG_ASSERT(iState == ENormalIdle);
EnsureFbsSessionIsOpen();
iScaler = CBitmapScaler::NewL();
iScaler->Scale(&iStatus, *iBitmap, *aTargetBitmap, aMaintainAspectRatio);
iState=EPendingScale;
SetActive();
}
void StartRotateL(CFbsBitmap *aTargetBitmap, CBitmapRotator::TRotationAngle aDirection) {
DEBUG_ASSERT(iState == ENormalIdle);
EnsureFbsSessionIsOpen();
iRotator = CBitmapRotator::NewL();
iRotator->Rotate(&iStatus, *iBitmap, *aTargetBitmap, aDirection);
iState=EPendingRotate;
SetActive();
}
#endif // ICL_SUPPORT
void RunL() {
// Note: Even if save, rotation or scale fails, the original
// bitmap should still be intact, so we are safe to switch back to
// ENormalIdle state.
switch (iState) {
#ifdef ICL_SUPPORT
case EPendingLoad:
delete iDecoder; iDecoder=NULL;
iState=ENormalIdle;
break;
case EPendingSave:
delete iEncoder; iEncoder=NULL;
delete iFrameImageData; iFrameImageData=NULL;
iState=ENormalIdle;
break;
case EPendingScale:
delete iScaler; iScaler=NULL;
iState=ENormalIdle;
break;
case EPendingRotate:
delete iRotator; iRotator=NULL;
iState=ENormalIdle;
break;
#endif // ICL_SUPPORT
default:
PANIC("ImageObject");
}
PyEval_RestoreThread(PYTHON_TLS->thread_state);
InvokeCompletionCallback();
PyEval_SaveThread();
}
/* Stop the current operation, if any. If a completion callback has
been set, DECREF it. */
void Stop() {
Cancel(); // DoCancel sets the proper state.
// Note that this can indirectly cause this object to be destroyed!
Py_XDECREF(iCompletionCallback);
iCompletionCallback=NULL;
}
void DoCancel() {
switch(iState) {
case ENormalIdle:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -