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 + -
显示快捷键?