screenshot.cpp
来自「Symbian_OS_code 初学Symbian_OS学习代码, 屏幕截图软」· C++ 代码 · 共 739 行 · 第 1/2 页
CPP
739 行
/*
* Screenshot.cpp
*
* Copyright 2005 - 2008, Antony Pranata
* http://www.antonypranata.com
*
* Project: Screenshot for Symbian OS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// INCLUDE FILES
#include <symbianvariant.h>
#include <coemain.h> // CCoeEnv
#include <bitdev.h> // CFbsScreenDevice
#include <bautils.h> // BaflUtils, to check file exists
#include <PathInfo.h>
#if (__S60__ >= 200)
#include <icl\ImageData.h>
#include <icl\ImageCodecData.h>
#endif
#include "ScreenShot.h"
#include "FakeOverlay.h"
// CONSTANTS
_LIT(KExtensionJpg, ".jpg");
_LIT(KExtensionPng, ".png");
_LIT(KExtensionBmp, ".bmp");
_LIT(KExtensionGif, ".gif");
_LIT(KExtensionMbm, ".mbm");
const TInt KOneSecond = 1000 * 1000;
const TInt KDelayContinuous = 4;
#if (__S60__ >= 200) // These MIME type declarations are needed if
// we are using S60 2.0 or greater because
// it is declared in our custom ImageConversion.h.
_LIT8(KMimeTypeJpg, "image/jpeg");
_LIT8(KMimeTypePng, "image/png");
_LIT8(KMimeTypeBmp, "image/bmp");
_LIT8(KMimeTypeMbm, "image/x-epoc-mbm");
_LIT8(KMimeTypeUnknown, "");
#endif
// --------------------------------------------------------------------------
// Two-phase constructor.
// --------------------------------------------------------------------------
CScreenShot* CScreenShot::NewL(MScreenShotObserver& aObserver,
CCoeEnv& aCoeEnv, CScreenShotData& aScreenShotData)
{
CScreenShot* self = new (ELeave) CScreenShot(aObserver, aCoeEnv,
aScreenShotData);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(); // self
return self;
}
// --------------------------------------------------------------------------
// Destructor.
// --------------------------------------------------------------------------
CScreenShot::~CScreenShot()
{
Cancel();
iTimer.Close();
delete iImageEncoder;
delete iBitmap;
delete iCurrentFileName;
}
// --------------------------------------------------------------------------
// Captures screenshot.
// --------------------------------------------------------------------------
void CScreenShot::CaptureL()
{
// If this still active, it means the active object is still busy.
// Tell the users to retry again in a few seconds.
if (IsActive())
{
User::Leave(KErrNotReady);
}
TInt additionalDelay = 0;
// For continuous mode, we have to give 4 seconds delay because we
// display dialog box at the beginning.
if (CScreenShotData::EModeOneShot != iScreenShotData.Mode())
{
additionalDelay = KDelayContinuous;
}
// Tells this active object there is an outstanding request.
switch (iScreenShotData.Delay())
{
case CScreenShotData::ENoDelay:
iScreenShotStatus = EWaiting;
iTimer.After(iStatus, TTimeIntervalMicroSeconds32(
additionalDelay * KOneSecond));
SetActive();
break;
case CScreenShotData::EOneSecond:
iScreenShotStatus = EWaiting;
iTimer.After(iStatus, TTimeIntervalMicroSeconds32(
(additionalDelay + 1) * KOneSecond));
SetActive();
break;
case CScreenShotData::EFiveSeconds:
iScreenShotStatus = EWaiting;
iTimer.After(iStatus, TTimeIntervalMicroSeconds32(
(additionalDelay + 5) * KOneSecond));
SetActive();
break;
case CScreenShotData::ETenSeconds:
iScreenShotStatus = EWaiting;
iTimer.After(iStatus, TTimeIntervalMicroSeconds32(
(additionalDelay + 10) * KOneSecond));
SetActive();
break;
case CScreenShotData::EThirtySeconds:
iScreenShotStatus = EWaiting;
iTimer.After(iStatus, TTimeIntervalMicroSeconds32(
(additionalDelay + 30) * KOneSecond));
SetActive();
break;
default:
User::Invariant();
}
iIsCapturing = ETrue;
}
// --------------------------------------------------------------------------
// Stops capturing in the continuous mode.
// --------------------------------------------------------------------------
void CScreenShot::StopCapture()
{
iIsCapturing = EFalse;
// If it is still waiting for the timer, then cancel it.
// If we are capturing or saving, we cannot cancel it immediately,
// because of 2 reasons:
// 1) the bitmap and file name might be out of sync.
// 2) the file might be corrupted if we cancel it.
// That's why if we're capturing or saving, we just signal iIsCapturing
// to EFalse and then wait until all the capturing processes finished.
if (EWaiting == iScreenShotStatus)
{
Cancel();
}
}
// --------------------------------------------------------------------------
// Gets the next file name.
// --------------------------------------------------------------------------
HBufC* CScreenShot::GetNextFileNameLC() const
{
const TInt KNumberLength = 4; // this is to indicate the file numbering,
// e.g. 0001, 0002, etc.
const TInt KMaxIndex = 10000;
// currently we use the maximum index of 10 thousand
// assuming that the users won't have 10 thousand screenshots.
TPtrC fileDrivePtr;
TPtrC filePathPtr;
// Gets the drive letter.
TDriveNumber drive;
if (CScreenShotData::EPhoneMemory == iScreenShotData.MemoryLocation())
{
fileDrivePtr.Set(PathInfo::PhoneMemoryRootPath());
drive = EDriveC;
}
else
{
fileDrivePtr.Set(PathInfo::MemoryCardRootPath());
drive = EDriveD;
}
// Gets the path for images.
#ifdef __S60__
filePathPtr.Set(PathInfo::ImagesPath());
#else
filePathPtr.Set(PathInfo::ImagesPath(drive));
#endif
// In UIQ, we can create file name using CQikMediaFileFolderUtils class
// However, we don't use it here because we have to maintain compatibility
// with S60 too.
/*
_LIT(KNoFile, "");
CQikMediaFile* mediaFile = CQikMediaFile::NewL(
drive, KMimeTypeImage, iScreenShotData.Directory(), KNoFile, 0);
CleanupStack::PushL(mediaFile);
CQikMediaFileFolderUtils* folderUtils = CQikMediaFileFolderUtils::NewL(
CEikonEnv::Static());
CleanupStack::PushL(folderUtils);
TFileName path = foldersUtils->CreateFileNameL(*mediaFile);
iEikonEnv->InfoMsg(path);
CleanupStack::Pop(2);
*/
// Gets the file name. If iDefaultFileName is zero then use KDefaultFileName.
TPtrC fileNamePtr(iScreenShotData.FileName());
// Gets the file extension.
TPtrC fileExtension;
switch (iScreenShotData.ImageFormat())
{
case CScreenShotData::EFormatJpgHigh:
case CScreenShotData::EFormatJpgNormal:
case CScreenShotData::EFormatJpgLow:
fileExtension.Set(KExtensionJpg);
break;
case CScreenShotData::EFormatPngDefault:
case CScreenShotData::EFormatPngSpeed:
case CScreenShotData::EFormatPngSize:
fileExtension.Set(KExtensionPng);
break;
case CScreenShotData::EFormatBmp:
case CScreenShotData::EFormatBmp8bpp:
fileExtension.Set(KExtensionBmp);
break;
case CScreenShotData::EFormatGif:
fileExtension.Set(KExtensionGif);
break;
case CScreenShotData::EFormatMbm:
case CScreenShotData::EFormatMbm8bpp:
fileExtension.Set(KExtensionMbm);
break;
default:
User::Invariant(); // panic if the format is not known
}
//
// Creates a new buffer. This has the following format:
//
// c:\documents\media files\image\unfiled\screenshot001.jpg
//
// where
// c:\ is fileDrivePtr
// documents\media files\image is filePathPtr
// unfiled is iScreenShotData.Directory()
// 001 is the image number
// .jpg is fileExtension
//
HBufC* newFileName = HBufC::NewLC(
fileDrivePtr.Length() + filePathPtr.Length()
+ iScreenShotData.Directory().Length() + fileNamePtr.Length()
+ KNumberLength + fileExtension.Length() + 1);
TPtr newFileNamePtr(newFileName->Des());
newFileNamePtr.Append(fileDrivePtr);
newFileNamePtr.Append(filePathPtr);
newFileNamePtr.Append(iScreenShotData.Directory());
newFileNamePtr.Append(fileNamePtr);
// Checks whether Screenshotxxx.jpg already exists on the phone or not.
// This is to prevent that the capture override the existing file.
TBool iIsFileExist = ETrue;
TInt index = iScreenShotData.StartingIndexFileName();
HBufC* buffer = HBufC::NewL(newFileNamePtr.MaxLength());
TPtr bufferPtr(buffer->Des());
while ((index < KMaxIndex) && (iIsFileExist))
{
bufferPtr.Copy(newFileNamePtr);
bufferPtr.AppendNumFixedWidth(index, EDecimal, KNumberLength);
bufferPtr.Append(fileExtension);
if (BaflUtils::FileExists(iCoeEnv.FsSession(), *buffer))
{
index++;
}
else
{
iIsFileExist = EFalse;
}
}
delete buffer;
// If the index exceeds KMaxIndex, then we don't need to format the file name.
if (index >= KMaxIndex)
{
newFileNamePtr.AppendNum(index);
}
else
{
newFileNamePtr.AppendNumFixedWidth(index, EDecimal, KNumberLength);
}
newFileNamePtr.Append(fileExtension);
// If the index greated then KMaxIndex, then rollback to 1
if (index >= KMaxIndex)
{
index = 1;
}
// Next time we start from this index, so we don't need to check
// the file one by one from 1 to N.
iScreenShotData.SetStartingIndexFileName(index + 1);
return newFileName;
}
// --------------------------------------------------------------------------
// Default constructor.
// --------------------------------------------------------------------------
CScreenShot::CScreenShot(MScreenShotObserver& aObserver, CCoeEnv& aCoeEnv,
CScreenShotData& aScreenShotData)
:CActive(0),
iObserver(aObserver),
iCoeEnv(aCoeEnv),
iScreenShotData(aScreenShotData),
iIsCapturing(EFalse)
{
}
// --------------------------------------------------------------------------
// Second phase constructor.
// --------------------------------------------------------------------------
void CScreenShot::ConstructL()
{
CActiveScheduler::Add(this);
User::LeaveIfError(iTimer.CreateLocal());
}
// --------------------------------------------------------------------------
// Called by Active Scheduler.
// --------------------------------------------------------------------------
void CScreenShot::RunL()
{
switch (iScreenShotStatus)
{
case EIdle:
iIsCapturing = EFalse;
break;
case EWaiting:
Fire(ECapturing);
break;
// Captures the screen.
case ECapturing:
DoCaptureL();
Fire(ESaving);
break;
// Saves the picture using CImageDecoder.
case ESaving:
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?