commands/grabscreen/grabscreen.cpp
changeset 0 7f656887cf89
child 30 35cb3fe43f60
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/grabscreen/grabscreen.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,290 @@
+// 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)
+