First submission to Symbian Foundation staging server.
// grabscreen.cpp
//
// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Accenture - Initial contribution
//
#include <fshell/ioutils.h>
#include <w32std.h>
#include <fbs.h>
#include <bitdev.h>
#include <imageconversion.h>
using namespace IoUtils;
class CCmdGrabscreen : public CCommandBase
{
public:
static CCommandBase* NewLC();
~CCmdGrabscreen();
private:
enum TFormat
{
EJpeg,
EGif,
EBmp,
EPng,
ERaw
};
private:
CCmdGrabscreen();
void WriteEncodedL(TUid aEncodingUid);
void WriteRawL();
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual void DoRunL();
virtual void ArgumentsL(RCommandArgumentList& aArguments);
virtual void OptionsL(RCommandOptionList& aOptions);
virtual void RunL();
private:
TFileName2 iFileName;
CImageEncoder* iImageEncoder;
HBufC8* iImageData;
CFrameImageData* iFrameImageData;
RFile iFile;
TFormat iFormat;
RArray<TInt> iRect;
TInt iScreen;
CFbsBitmap* iBitMap;
CWsScreenDevice* iDev;
RWsSession iWsSession;
TInt iQuality;
TBool iGreyscale;
};
CCommandBase* CCmdGrabscreen::NewLC()
{
CCmdGrabscreen* self = new(ELeave) CCmdGrabscreen();
CleanupStack::PushL(self);
self->BaseConstructL();
return self;
}
CCmdGrabscreen::~CCmdGrabscreen()
{
delete iImageEncoder;
delete iFrameImageData;
delete iDev;
delete iBitMap;
delete iImageData;
iFile.Close();
iRect.Close();
iWsSession.Close();
REComSession::FinalClose();
}
CCmdGrabscreen::CCmdGrabscreen()
: CCommandBase(EManualComplete), iQuality(100)
{
}
const TDesC& CCmdGrabscreen::Name() const
{
_LIT(KName, "grabscreen");
return KName;
}
void CCmdGrabscreen::DoRunL()
{
if ((iFormat == ERaw) && (!iArguments.IsPresent(0)))
{
PrintError(KErrArgument, _L("STDOUT writing is not supported for raw format; please specify a filename"));
DisplayHelp();
User::Leave(KErrArgument);
}
LeaveIfErr(iWsSession.Connect(), _L("Couldn't connect to windowserver"));
iDev = new(ELeave) CWsScreenDevice(iWsSession);
#ifdef SYMBIAN_WSERV_AND_CONE_MULTIPLE_SCREENS
const TInt numScreens = iWsSession.NumberOfScreens();
if (iScreen >= numScreens)
{
if (numScreens == 1)
{
LeaveIfErr(KErrArgument, _L("Invalid screen number - there is only 1 screen"));
}
else
{
LeaveIfErr(KErrArgument, _L("Invalid screen number - there are only %d screens"));
}
}
#endif
LeaveIfErr(iDev->Construct(iScreen), _L("Couldn't construct CWsScreenDevice for screen %d"), iScreen);
iBitMap = new(ELeave) CFbsBitmap();
TRect rect;
if (iOptions.IsPresent(&iRect))
{
if (iRect.Count() != 4)
{
LeaveIfErr(KErrArgument, _L("Invalid --rect option - four integers must be specifed"));
}
rect.SetRect(iRect[0], iRect[1], iRect[2], iRect[3]);
}
else
{
rect.SetRect(TPoint(0, 0), iDev->SizeInPixels());
}
LeaveIfErr(iBitMap->Create(rect.Size(), iDev->DisplayMode()), _L("Couldn't create fbsbitmap of size (%d,%d) for display mode %d"), rect.Width(), rect.Height(), iDev->DisplayMode());
User::LeaveIfError(iDev->CopyScreenToBitmap(iBitMap, rect));
switch (iFormat)
{
case EJpeg:
WriteEncodedL(KImageTypeJPGUid);
break;
case EGif:
WriteEncodedL(KImageTypeGIFUid);
break;
case EBmp:
WriteEncodedL(KImageTypeBMPUid);
break;
case EPng:
WriteEncodedL(KImageTypePNGUid);
break;
case ERaw:
WriteRawL();
break;
}
}
void CCmdGrabscreen::WriteEncodedL(TUid aEncodingUid)
{
if (aEncodingUid == KImageTypeJPGUid)
{
TJpegImageData* imageData = new(ELeave) TJpegImageData();
CleanupStack::PushL(imageData);
imageData->iSampleScheme = iGreyscale ? TJpegImageData::EMonochrome : TJpegImageData::EColor444;
imageData->iQualityFactor = iQuality;
iFrameImageData = CFrameImageData::NewL();
User::LeaveIfError(iFrameImageData->AppendImageData(imageData));
CleanupStack::Pop(imageData);
}
else if (aEncodingUid == KImageTypeGIFUid)
{
if (iGreyscale)
{
PrintWarning(_L("Greyscale not supported for GIF images."));
}
if (iOptions.IsPresent(&iQuality))
{
PrintWarning(_L("Quality control not supported for GIF images."));
}
}
else if (aEncodingUid == KImageTypeBMPUid)
{
if (iGreyscale)
{
PrintWarning(_L("Greyscale not supported for BMP images."));
}
if (iOptions.IsPresent(&iQuality))
{
PrintWarning(_L("Quality control not supported for BMP images."));
}
}
else if (aEncodingUid == KImageTypePNGUid)
{
if (iOptions.IsPresent(&iQuality))
{
PrintWarning(_L("Quality control not supported for PNG images."));
}
TPngEncodeData* imageData = new(ELeave) TPngEncodeData();
CleanupStack::PushL(imageData);
imageData->iBitsPerPixel = iGreyscale ? 4 : 8;
imageData->iColor = !iGreyscale;
imageData->iLevel = TPngEncodeData::EBestCompression;
imageData->iPaletted = EFalse;
iFrameImageData = CFrameImageData::NewL();
User::LeaveIfError(iFrameImageData->AppendFrameData(imageData));
CleanupStack::Pop(imageData);
}
if (iArguments.IsPresent(0))
{
LeaveIfErr(iFile.Replace(FsL(), iFileName, EFileWrite), _L("Unable to open \"%S\" for writing"), &iFileName);
iImageEncoder = CImageEncoder::FileNewL(iFile, CImageEncoder::EOptionNone, aEncodingUid);
}
else
{
iImageEncoder = CImageEncoder::DataNewL(iImageData, CImageEncoder::EOptionNone, aEncodingUid);
}
iImageEncoder->Convert(&iStatus, *iBitMap, iFrameImageData);
SetActive();
}
void CCmdGrabscreen::RunL()
{
User::LeaveIfError(iStatus.Int());
if (!iArguments.IsPresent(0))
{
User::LeaveIfNull(iImageData);
Stdout().SetModeL(RIoReadWriteHandle::EBinary);
// we need to expand the 8 bit data when writing to stdout
static const TInt KBufferSize = 0x100;
TBuf<KBufferSize> buf;
TPtr8 imageData(iImageData->Des());
while (imageData.Length())
{
TInt thisCopyLen = Min(KBufferSize, imageData.Length());
buf.Copy(imageData.Left(thisCopyLen));
imageData.Set(imageData.MidTPtr(thisCopyLen));
Stdout().WriteL(buf);
}
}
Complete(KErrNone);
}
void CCmdGrabscreen::WriteRawL()
{
if (iGreyscale)
{
PrintWarning(_L("Greyscale not supported for raw images."));
}
if (iOptions.IsPresent(&iQuality))
{
PrintWarning(_L("Quality control not supported for raw images."));
}
LeaveIfErr(iBitMap->Save(iFileName), _L("Unable to write \"%S\""), &iFileName);
Complete(KErrNone);
}
void CCmdGrabscreen::ArgumentsL(RCommandArgumentList& aArguments)
{
_LIT(KArg, "file_name");
aArguments.AppendFileNameL(iFileName, KArg);
}
void CCmdGrabscreen::OptionsL(RCommandOptionList& aOptions)
{
_LIT(KOptFormat, "format");
aOptions.AppendEnumL((TInt&)iFormat, KOptFormat);
_LIT(KOptRect, "rect");
aOptions.AppendIntL(iRect, KOptRect);
_LIT(KOptScreen, "screen");
aOptions.AppendIntL(iScreen, KOptScreen);
_LIT(KOptQuality, "quality");
aOptions.AppendIntL(iQuality, KOptQuality);
_LIT(KOptGreyscale, "greyscale");
aOptions.AppendBoolL(iGreyscale, KOptGreyscale);
}
EXE_BOILER_PLATE(CCmdGrabscreen)