ImagePrint/ImagePrintEngine/DeviceProtocols/xhtmlfilecomposer/src/cxhtmlfilecomposer.cpp
changeset 0 d11fb78c4374
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ImagePrint/ImagePrintEngine/DeviceProtocols/xhtmlfilecomposer/src/cxhtmlfilecomposer.cpp	Thu Dec 17 08:45:53 2009 +0200
@@ -0,0 +1,992 @@
+/*
+* Copyright (c) 2002-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Defines the CXhtmlFileComposer class.
+*
+*/
+
+
+#include <imageconversion.h>
+
+#ifdef _DEBUG
+#include <driveinfo.h>
+#include <pathinfo.h>
+#endif
+
+#include "cxhtmlfilecomposer.h"
+#include "printcapabilitycodes.h"
+#include "cxfclogger.h"
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::NewL
+//
+//--------------------------------------------------------------------------------------------
+EXPORT_C CXhtmlFileComposer* CXhtmlFileComposer::NewL(const TDesC& aPath)
+	{
+		CXhtmlFileComposer *self = NewLC(aPath);
+		CleanupStack::Pop();	// self
+
+		return self;
+	}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::NewLC
+//
+//--------------------------------------------------------------------------------------------
+EXPORT_C CXhtmlFileComposer* CXhtmlFileComposer::NewLC(const TDesC& aPath)
+	{
+		CXhtmlFileComposer *self = new (ELeave) CXhtmlFileComposer();
+		CleanupStack::PushL(self);
+
+		if(0 >= aPath.Length())
+		{
+			self->ConstructL(KXFCDefaultResultPath());
+		}
+		else
+		{
+			self->ConstructL(aPath);
+		}
+
+		return self;
+	}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::CreateXhtmlFileL
+//
+//--------------------------------------------------------------------------------------------
+EXPORT_C void CXhtmlFileComposer::CreateXhtmlFileL(const RArray<CImageInfo>& aImages, const TInt aLayout,
+								  const TInt aPaperSize, const TInt /*aQuality*/,
+								  const TDesC& aXhtmlPrintFile,TInt& aPageCount, TBool aDataFile)
+{
+	LOG("[CXhtmlFileComposer]\t WriteJobControlFileL");
+
+	// Get page and layout related data
+	PageData(aPaperSize);
+
+	RArray<TSizeReal> positions;
+	CleanupClosePushL(positions);
+	LayoutData(aLayout, positions);
+
+	ReadTemplateFileL();
+
+	// init counter variables
+	aPageCount = 0;
+	TInt posIx = 0;
+	TInt copies = 0;
+	TInt currentImgNum = 0;
+	TInt imageCount = aImages.Count();
+
+	// loop for images
+	for(TInt imgIx = 0; imgIx < aImages.Count(); imgIx++)
+	{
+		/**** Handle copies ****/
+		copies = aImages[imgIx].Copies();
+		imageCount += copies - 1; // decrease current image from copies
+
+		// Create template blocks for each copy
+		while(1 <= copies && imageCount > currentImgNum)
+		{
+			AddPageL(currentImgNum, posIx, aPageCount);
+			AddTemplateStringL(iFrameTemplate, KFrame());
+
+			// add frame position template once per position for all pages
+			if(1 == aPageCount)
+			{
+				AddTemplateStringL(iPositionTemplate, KFramePosition());
+				ComposePositionL(posIx, positions);
+			}
+			ComposeTemplateL(posIx+1, KPosId());
+			--copies;
+			++currentImgNum;
+		}
+
+		// add image details
+		AddTemplateStringL(iImageTemplate, KImgDetails());
+		ComposeTemplateL(1+imgIx, KDetId());
+
+		// Get correct name for the image
+		TFileName8 imageName;
+		GetImageNameL(aImages[imgIx], imageName, aDataFile);
+
+		/**** Image size and orientation ****/
+		TSizeReal imageSize(0,0);
+		TBool framePortrait = EFalse;
+
+		SizeAndOrientationL(aImages[imgIx], imageSize, framePortrait);
+
+		/**** Image scaling & cropping ****/
+		TSizeReal scaledSize;
+		GetRatioL(scaledSize, imageSize);
+
+		// Turn frame and scaled size in correct orientation again
+		if(framePortrait != iImagePortrait)
+		{
+			scaledSize.Reverse();
+			iImageFrame.Reverse();
+		}
+
+		ComposeFileL(imageName, scaledSize, aDataFile);
+
+	}// End of loop for images
+	CleanupStack::PopAndDestroy( &positions );
+
+	// Compose the correct unit in file
+	ComposeUnitL();
+
+	/**** Create result file ****/
+	RFile newFile;
+	CleanupClosePushL( newFile );
+	User::LeaveIfError( newFile.Replace( iFsSession, aXhtmlPrintFile, EFileWrite) );
+	newFile.Write( FinalizeBufferL() );
+	CleanupStack::PopAndDestroy( &newFile );
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::~CXhtmlFileComposer
+//
+//--------------------------------------------------------------------------------------------
+EXPORT_C CXhtmlFileComposer::~CXhtmlFileComposer()
+{
+	iFsSession.Close();
+	if(iFileBuf)
+		delete iFileBuf;
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::UnitToPixel
+//
+//--------------------------------------------------------------------------------------------
+EXPORT_C TReal CXhtmlFileComposer::UnitToPixel(TReal aValue)
+{
+	TReal tmp = aValue;
+	if(EUAMillis == iPaperType)
+		tmp = aValue/(TReal)KInchDivider;
+
+	tmp = tmp*(TReal)KDpiDivider;
+
+	return tmp;
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::UnitToPixel
+//
+//--------------------------------------------------------------------------------------------
+EXPORT_C TSizeReal CXhtmlFileComposer::UnitToPixel(TSizeReal aValue)
+{
+	TSizeReal tmp = aValue;
+	if(EUAMillis == iPaperType)
+		tmp = aValue/(TReal)KInchDivider;
+
+	tmp = tmp*(TReal)KDpiDivider;
+
+	return tmp;
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::PixelToUnit
+//
+//--------------------------------------------------------------------------------------------
+EXPORT_C TReal CXhtmlFileComposer::PixelToUnit(TReal aValue)
+{
+	TReal tmp = aValue/(TReal)KDpiDivider;
+	if(EUAMillis == iPaperType)
+		tmp = tmp*(TReal)KInchDivider;
+
+	return tmp;
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::PixelToUnit
+//
+//--------------------------------------------------------------------------------------------
+EXPORT_C TSizeReal CXhtmlFileComposer::PixelToUnit(TSizeReal aValue)
+{
+	TSizeReal tmp = aValue/(TReal)KDpiDivider;
+	if(EUAMillis == iPaperType)
+		tmp = tmp*(TReal)KInchDivider;
+
+	return tmp;
+}
+
+// PROTECTED
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::ConstructL
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::ConstructL(const TDesC& aPath)
+{
+	LOG("[CXhtmlFileComposer::ConstructL]\t");
+
+	User::LeaveIfError( iFsSession.Connect() );
+	iFsSession.SetSessionPath( aPath );
+	iFsSession.MkDirAll( aPath );
+
+	iPaperSize.SetSize(0,0);
+	iPaperType = 0;
+	iPageMargin = 0;
+	iImageFrame.SetSize(0,0);
+	iFileBuf = NULL;
+	iImagesPerPage = 0;
+	iImagePortrait=EFalse;
+	iPagePortrait = ETrue;
+	iPageTemplate.Copy(KNullDesC8());
+	iFrameTemplate.Copy(KNullDesC8());
+	iPositionTemplate.Copy(KNullDesC8());
+	iImageTemplate.Copy(KNullDesC8());
+
+	LOG("[CXhtmlFileComposer::ConstructL]\t Done.");
+}
+
+// PRIVATE
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::CXhtmlFileComposer
+//
+//--------------------------------------------------------------------------------------------
+CXhtmlFileComposer::CXhtmlFileComposer()
+{
+}
+
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::GetRatioL
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::GetRatioL(TSizeReal &aNewSize, TSizeReal aImageSize)
+{
+	LOG("[CXhtmlFileComposer::GetRatioL]\t ********************************");
+
+	TRealX margin = 0;
+	TXhtmlSetting marginStr, tmpStr;
+
+	LOG2("[CXhtmlFileComposer::GetRatioL]\t aImageSize: %fx%f", PixelToUnit(aImageSize.iWidth), PixelToUnit(aImageSize.iHeight));
+	LOG2("[CXhtmlFileComposer::GetRatioL]\t iImageFrame: %fx%f", PixelToUnit(iImageFrame.iWidth), PixelToUnit(iImageFrame.iHeight));
+	LOG2("[CXhtmlFileComposer::GetRatioL]\t image ratio: %f vs. frame ratio %f", aImageSize.Ratio(), iImageFrame.Ratio());
+
+	TReal relativeRatio = aImageSize.Ratio() / iImageFrame.Ratio();
+	LOG2("[CXhtmlFileComposer::GetRatioL]\t relativeRatio: %f, iPageMargin %f", relativeRatio, iPageMargin);
+
+	// crop borderless: if iPageMargin == 0, the margin must be negative
+	if((1 < relativeRatio && iPageMargin) || (1 > relativeRatio && !iPageMargin))
+	{
+		LOG("[CXhtmlFileComposer::GetRatioL]\t *Match width*");
+		aNewSize.SetSize(iImageFrame.iWidth, iImageFrame.iWidth/aImageSize.Ratio());
+		margin = (iImageFrame.iHeight-aNewSize.iHeight)/2;
+
+	    if((!iPagePortrait && !iPageMargin && iImagePortrait) || iPagePortrait)
+	    	marginStr.Copy(KTop());
+		else
+	    	marginStr.Copy(KLeft());
+	}
+	else
+	{
+		LOG("[CXhtmlFileComposer::GetRatioL]\t *Match height*");
+		aNewSize.SetSize(iImageFrame.iHeight*aImageSize.Ratio(), iImageFrame.iHeight);
+		margin = (iImageFrame.iWidth-aNewSize.iWidth)/2;
+
+	    if((!iPagePortrait && !iPageMargin && iImagePortrait) || iPagePortrait)
+	    	marginStr.Copy(KLeft());
+		else
+	    	marginStr.Copy(KTop());
+	}
+
+	FormatReal(PixelToUnit(margin), tmpStr);
+	marginStr.Append(tmpStr);
+
+	LOG2("[CXhtmlFileComposer::GetRatioL]\t aNewSize: %fx%f", PixelToUnit(aNewSize.iWidth), PixelToUnit(aNewSize.iHeight));
+	LOG81("[CXhtmlFileComposer::GetRatioL]\t \"%S\"", &marginStr);
+
+	// margin not needed anymore: compose margin into file buffer
+	ComposeTemplateL(marginStr, KImgMargin());
+	LOG("[CXhtmlFileComposer::GetRatioL]\t ********************************");
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::ComposeUnitL
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::ComposeUnitL()
+{
+	LOG("[CXhtmlFileComposer]\t ComposeUnit");
+
+	if(EUAMillis == iPaperType)
+	{
+		_LIT8(KMm, "mm");
+		ComposeTemplateL(KMm(), KUnit());
+	}
+	else
+	{
+		_LIT8(KIn, "in");
+		ComposeTemplateL(KIn(), KUnit());
+	}
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::ComposeFile
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::ComposeFileL(const TDes8 &aImageName, TSizeReal aImgSize, TBool aDataFile)
+{
+	LOG("[CXhtmlFileComposer]\t ComposeFile");
+
+	// Format page settings in file
+	TXhtmlSetting pageWidthStr, pageHeightStr, pageMarginStr;
+
+	FormatReal(PixelToUnit(iPaperSize.iWidth), pageWidthStr);
+	ComposeTemplateL(pageWidthStr, KPageWidth());
+
+	FormatReal(PixelToUnit(iPaperSize.iHeight), pageHeightStr);
+	ComposeTemplateL(pageHeightStr, KPageHeight());
+
+	FormatReal(iPageMargin, pageMarginStr);
+	ComposeTemplateL(pageMarginStr, KPageMargin());
+
+	// Format image frame settings in file
+	TXhtmlSetting imgFrameWidthStr, imgFrameHeightStr;
+
+	FormatReal(PixelToUnit(iImageFrame.iWidth), imgFrameWidthStr);
+	ComposeTemplateL(imgFrameWidthStr, KImgFrameWidth());
+
+	FormatReal(PixelToUnit(iImageFrame.iHeight), imgFrameHeightStr);
+	ComposeTemplateL(imgFrameHeightStr, KImgFrameHeight());
+
+	// Format image settings in file
+	TXhtmlSetting imgWidthStr, imgHeightStr;
+
+	FormatReal(PixelToUnit(aImgSize.iWidth), imgWidthStr);
+	ComposeTemplateL(imgWidthStr, KImgWidth());
+
+	FormatReal(PixelToUnit(aImgSize.iHeight), imgHeightStr);
+	ComposeTemplateL(imgHeightStr, KImgHeight());
+
+///////////
+	HBufC8* data = NULL;
+	if(aDataFile)
+	{
+
+		TFileName imgFile;
+		imgFile.Copy(aImageName);
+
+		LOG("[CXhtmlFileComposer]\t ComposeFileL - read image data");
+		// Open the template file and read it into buffer
+		RFile file;
+		CleanupClosePushL(file);
+
+		User::LeaveIfError( file.Open( iFsSession, imgFile, EFileRead | EFileShareReadersOnly ) );
+		LOG("[CXhtmlFileComposer]\t ComposeFileL - file opened");
+
+		TInt fileSize = 0;
+		User::LeaveIfError( file.Size(fileSize) );
+		LOG1("[CXhtmlFileComposer]\t ComposeFileL - file size %d",fileSize);
+
+		_LIT8(KDataUrl, "data:image/jpeg;base64,");
+
+		data = HBufC8::NewLC(fileSize + KDataUrl().Length());
+		TPtr8 dataPtr( data->Des() );
+
+		dataPtr.Zero();
+		file.Read(dataPtr);
+
+		dataPtr.Insert(0, KDataUrl());
+
+		ComposeTemplateL(dataPtr, KImgName());
+		LOG("[CXhtmlFileComposer]\t ComposeFileL - file composed");
+
+		CleanupStack::PopAndDestroy(2); // data, file
+	}
+///////////
+	else
+	{
+		// Format image name in file
+		ComposeTemplateL(aImageName, KImgName());
+	}
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::ComposeTemplateL
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::ComposeTemplateL(const TInt aValue, const TDesC8 &aTemplate)
+{
+//	LOG("[CXhtmlFileComposer]\t ComposeTemplateL");
+
+	TBuf8<KDefaultRealWidth> valueStr;
+	valueStr.Zero();
+	valueStr.AppendNum(aValue);
+
+	ComposeTemplateL(valueStr, aTemplate);
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::ComposeTemplateL
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::ComposeTemplateL(const TDesC8 &aStr, const TDesC8 &aTemplate)
+{
+//	LOG("[CXhtmlFileComposer]\t ComposeTemplateL");
+
+	User::LeaveIfNull(iFileBuf);
+
+	TInt pos = iFileBuf->Find(aTemplate);
+	while(KErrNotFound != pos)
+	{
+		TInt requiredSize = iFileBuf->Des().Length() + aStr.Length();
+		if(iFileBuf->Des().MaxLength() < requiredSize)
+		{
+			iFileBuf = iFileBuf->ReAllocL(requiredSize);
+		}
+		iFileBuf->Des().Replace(pos, aTemplate.Length(), aStr);
+		pos = iFileBuf->Find(aTemplate);
+	}
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::SetPageTypeL
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::SetPageTypeL()
+{
+	LOG("[CXhtmlFileComposer]\t SetPageTypeL");
+
+	User::LeaveIfNull(iFileBuf);
+
+	TXhtmlSetting pageType(KPageFirsts());
+
+	TInt pos = iFileBuf->Find(KPageType());
+	if(KErrNotFound >= pos)
+		User::Leave(KErrCorrupt);
+
+	while(KErrNotFound != pos)
+	{
+		// check if next exists to assign correct page type in template
+		TPtrC8 tmpBuf;
+		tmpBuf.Set(iFileBuf->Mid(pos+KPageType().Length()));
+
+		if(KErrNotFound == tmpBuf.Find(KPageType()))
+			pageType.Copy(KPageLast());
+
+		// replace correct page type in first found position
+		TInt requiredSize = iFileBuf->Des().Length() + pageType.Length();
+		if(iFileBuf->Des().MaxLength() < requiredSize)
+		{
+			iFileBuf = iFileBuf->ReAllocL(requiredSize);
+		}
+		iFileBuf->Des().Replace(pos, KPageType().Length(), pageType);
+		pos = iFileBuf->Find(KPageType());
+	}
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::FinalizeBufferL
+//
+//--------------------------------------------------------------------------------------------
+TPtrC8 CXhtmlFileComposer::FinalizeBufferL()
+{
+	LOG("[CXhtmlFileComposer]\t FinalizeBufferL");
+
+	User::LeaveIfNull(iFileBuf);
+
+	SetPageTypeL();
+
+	// Remove markers from the buffer
+	TInt pos = iFileBuf->Find(KPage());
+	if(KErrNotFound != pos)
+		iFileBuf->Des().Delete(pos, KPage().Length());
+
+	pos = iFileBuf->Find(KFrame());
+	if(KErrNotFound != pos)
+		iFileBuf->Des().Delete(pos, KFrame().Length());
+
+	pos = iFileBuf->Find(KImgDetails());
+	if(KErrNotFound != pos)
+		iFileBuf->Des().Delete(pos, KImgDetails().Length());
+
+	pos = iFileBuf->Find(KFramePosition());
+	if(KErrNotFound != pos)
+		iFileBuf->Des().Delete(pos, KFramePosition().Length());
+
+	// Cut the template to the end tag
+	pos = iFileBuf->Find(KEndTag());
+	if(KErrNotFound == pos)
+		User::Leave(KErrCorrupt);
+
+	TInt dataLen = pos + KEndTag().Length();
+	TPtrC8 tail = iFileBuf->Des().Left(dataLen);
+
+	return tail;
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::PageData
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::PageData(TInt aPaperSize)
+{
+	LOG("[CXhtmlFileComposer]\t PageData");
+
+	const TSizeReal KSizeA4(210.0, 297.0);
+	const TSizeReal KSizeA6(105.0, 148.5);
+	const TSizeReal KSizeLetter(8.5, 11.0);
+	const TSizeReal KSize4x6(4.0, 6.0);
+	const TSizeReal KSize5x7(5.0, 7.0);
+
+	switch(aPaperSize)
+	{
+		case EPrintCapabPaperSizeA4:
+			iPaperType = CXhtmlFileComposer::EUAMillis;
+			iPaperSize = UnitToPixel(KSizeA4);
+			iPageMargin = 3.0;
+			break;
+		case EPrintCapabPaperSizeA6:
+			iPaperType = CXhtmlFileComposer::EUAMillis;
+			iPaperSize = UnitToPixel(KSizeA6);
+			iPageMargin = 3.0;
+			break;
+		case EPrintCapabPaperSizeLetter:
+			iPaperType = CXhtmlFileComposer::EUAInches;
+			iPaperSize = UnitToPixel(KSizeLetter);
+			iPageMargin = 0.12;
+			break;
+		case EPrintCapabPaperSize5x7:
+			iPaperType = CXhtmlFileComposer::EUAInches;
+			iPaperSize = UnitToPixel(KSize5x7);
+			iPageMargin = 0.12;
+			break;
+		case EPrintCapabPaperSizeAuto:
+		case EPrintCapabPaperSizeSticker:
+		case EPrintCapabPaperSize4x6:
+		default:
+			iPaperType = CXhtmlFileComposer::EUAInches;
+			iPaperSize = UnitToPixel(KSize4x6);
+			iPageMargin = 0.12;
+			break;
+	}
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::LayoutData
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::LayoutData(TInt aLayout, RArray<TSizeReal>& aPositions)
+{
+	LOG1("[CXhtmlFileComposer::LayoutData]\t aLayout: %d", aLayout);
+
+	TSizeReal pos(0,0);
+
+	switch(aLayout)
+	{
+		case EPrintCapabLayout1UpBorder:
+			iImagesPerPage = 1;
+			iPagePortrait = EFalse;
+			CreateMatrix(1/*rows*/, 1/*columns*/, aPositions);
+			break;
+		case EPrintCapabLayout2Up:
+			iImagesPerPage = 2;
+			iPagePortrait = ETrue;
+			CreateMatrix(2, 1, aPositions);
+			break;
+		case EPrintCapabLayout4Up:
+			iImagesPerPage = 4;
+			iPagePortrait = EFalse;
+			CreateMatrix(2, 2, aPositions);
+			break;
+		case EPrintCapabLayout6Up:
+			iImagesPerPage = 6;
+			iPagePortrait = ETrue;
+			CreateMatrix(3, 2, aPositions);
+			break;
+		case EPrintCapabLayout9Up:
+			iImagesPerPage = 9;
+			iPagePortrait = EFalse;
+			CreateMatrix(3, 3, aPositions);
+			break;
+		case EPrintCapabLayout12Up:
+			iImagesPerPage = 12;
+			iPagePortrait = ETrue;
+			CreateMatrix(4, 3, aPositions);
+			break;
+		case EPrintCapabLayout16Up:
+			iImagesPerPage = 16;
+			iPagePortrait = EFalse;
+			CreateMatrix(4, 4, aPositions);
+			break;
+		case EPrintCapabLayout1Up:
+		case EPrintCapabLayout1UpBorderless:
+		default:
+			iImagesPerPage = 1;
+			iPageMargin = 0;
+			iImageFrame = iPaperSize;
+			iPagePortrait = EFalse;
+			aPositions.Append(pos);
+			break;
+	}
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::CreateMatrix
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::CreateMatrix(TInt aRows, TInt aColumns, RArray<TSizeReal>& aPositions)
+{
+	LOG("[CXhtmlFileComposer]\t CreateMatrix");
+
+	TSizeReal pos;
+	TSizeReal matrix(aColumns,aRows);
+	TSizeReal relativeSize(KFrameRatio, 1);
+
+	if(!iPagePortrait)
+	{
+		matrix.Reverse();
+		relativeSize.Reverse();
+	}
+
+	// count print area: paper size - margins
+	TSizeReal margins(matrix);
+	margins += 1; 
+	margins *= UnitToPixel(iPageMargin);
+	LOG2("[CXhtmlFileComposer::CreateMatrix]\t margins: %fx%f", PixelToUnit(margins.iWidth), PixelToUnit(margins.iHeight));
+
+	TSizeReal printArea = (iPaperSize - margins);
+	LOG2("[CXhtmlFileComposer::CreateMatrix]\t printArea: %fx%f", PixelToUnit(printArea.iWidth), PixelToUnit(printArea.iHeight));
+
+	// Count frame size
+
+	iImageFrame = printArea/matrix;
+	LOG2("[CXhtmlFileComposer::CreateMatrix]\t iImageFrame bef. ratio: %fx%f", PixelToUnit(iImageFrame.iWidth), PixelToUnit(iImageFrame.iHeight));
+
+	LOG1("[CXhtmlFileComposer::CreateMatrix]\t frame ratio: %f", iImageFrame.Ratio());
+
+	// force frame ratio to KFrameRatio ratio
+	LOG1("[CXhtmlFileComposer::CreateMatrix]\t relativeRatio: %f", relativeSize.Ratio());
+
+	TReal relativeRatio = relativeSize.Ratio()/iImageFrame.Ratio();
+	if(1 < relativeRatio)
+	{
+		iImageFrame.iHeight /= relativeRatio;
+	}
+	else if(1 > relativeRatio)
+	{
+		iImageFrame.iWidth *= relativeRatio;
+	}
+
+	LOG2("[CXhtmlFileComposer::CreateMatrix]\t iImageFrame aft. ratio: %fx%f", PixelToUnit(iImageFrame.iWidth), PixelToUnit(iImageFrame.iHeight));
+	LOG1("[CXhtmlFileComposer::CreateMatrix]\t --> ratio: %f (1.3325/0.7505)", iImageFrame.Ratio());
+
+	// Count the empty space on page to centerise the frame set
+	TSizeReal frameSetSize(iImageFrame*matrix);
+	TSizeReal emptySpace = (printArea - frameSetSize) / 2;
+
+	LOG2("[CXhtmlFileComposer::CreateMatrix]\t frameSetSize:\t %fx%f", PixelToUnit(frameSetSize.iWidth), PixelToUnit(frameSetSize.iHeight));
+	LOG2("[CXhtmlFileComposer::CreateMatrix]\t emptySpace:\t %fx%f", PixelToUnit(emptySpace.iWidth), PixelToUnit(emptySpace.iHeight));
+
+	// if only one image/page, no need to calculate positions.
+	if(0 >= aColumns || 0 >= aRows)
+	{
+		aPositions.Append(pos);
+		return;
+	}
+
+	emptySpace.Reverse();
+	
+	for(TInt row = 0; row < aRows; ++row)
+	{
+		LOG1("[CXhtmlFileComposer::CreateMatrix]\t row: %d", row);
+		pos.iWidth = (iImageFrame.iHeight+UnitToPixel(iPageMargin)) * row;
+		pos.iWidth += emptySpace.iWidth;
+		for(TInt col = 0; col < aColumns; ++col)
+		{
+			pos.iHeight = (iImageFrame.iWidth+UnitToPixel(iPageMargin)) * col;
+			pos.iHeight += emptySpace.iHeight;
+			LOG2("[CXhtmlFileComposer::CreateMatrix]\t col: %fx%f", PixelToUnit(pos.iWidth), PixelToUnit(pos.iHeight));
+			aPositions.Append(pos);
+		}
+	}
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::ReadTemplateL
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::ReadTemplateFileL()
+{
+	LOG("[CXhtmlFileComposer]\t ReadTemplateL");
+	// Open the template file and read it into buffer
+	RFile templateFile;
+	CleanupClosePushL(templateFile);
+
+#ifdef _DEBUG
+	//_LIT(KFile, "e:\\UPnPXHTMLTemplate.xhtml");
+	_LIT(KFileName, "UPnPXHTMLTemplate.xhtml");
+	TInt drive;
+  TFileName path;
+
+  DriveInfo::GetDefaultDrive(DriveInfo::EDefaultRemovableMassStorage, drive);
+  PathInfo::GetRootPath(path, drive);
+  path.Append(KFileName());
+    
+  TInt e = templateFile.Open( iFsSession, path, EFileRead);
+	if(KErrNone != e)
+#endif
+	{
+		User::LeaveIfError( templateFile.Open( iFsSession, KXHTMLTemplate(), EFileRead) );
+	}
+	TInt fileSize = 0;
+	TInt err = templateFile.Size(fileSize);
+	if(KErrNone != err)
+		fileSize = KXFCMaxFileSize;
+
+	iFileBuf = HBufC8::NewL(fileSize);
+	TPtr8 bufferPtr( iFileBuf->Des() );
+
+	bufferPtr.Zero();
+	templateFile.Read(bufferPtr);
+
+	CleanupStack::PopAndDestroy(&templateFile);
+
+	// Separate page, frame position, image details and frame
+	// template elements from the template buffer
+	GetTemplateStringL(KPageStart(), KPageEnd(), iPageTemplate);
+	GetTemplateStringL(KFrameStart(), KFrameEnd(), iFrameTemplate);
+	GetTemplateStringL(KPositionStart(), KPositionEnd(),iPositionTemplate);
+	GetTemplateStringL(KImgStart(), KImgEnd(), iImageTemplate);
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::GetTemplateStringL
+//
+//--------------------------------------------------------------------------------------------
+TPtrC8 CXhtmlFileComposer::GetTemplateStringL(const TDesC8 &aStart, const TDesC8 &aEnd, TDes8 &aTemplate)
+{
+	User::LeaveIfNull(iFileBuf);
+
+	TInt start = iFileBuf->Find(aStart);
+	if(KErrNotFound == start)
+		User::Leave(KErrCorrupt);
+
+	TInt end = iFileBuf->Find(aEnd);
+	if(KErrNotFound == end)
+		User::Leave(KErrCorrupt);
+
+	TPtrC8 ptr = iFileBuf->Des().Mid(start+aStart.Length(), end-start-aStart.Length());
+
+	if(aTemplate.MaxLength() < ptr.Length())
+		User::Leave(KErrOverflow);
+
+	aTemplate = ptr;
+	iFileBuf->Des().Delete(start, ptr.Length()+aStart.Length()+aEnd.Length());
+	return ptr;
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::AddTemplateStringL
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::AddTemplateStringL(const TDesC8 &aTemplate,const TDesC8 &aTag)
+{
+	User::LeaveIfNull(iFileBuf);
+
+	TInt pos = iFileBuf->Find(aTag);
+	if(KErrNotFound == pos)
+		User::Leave(KErrCorrupt);
+
+	TInt requiredSize = iFileBuf->Des().Length() + aTemplate.Length();
+	if(iFileBuf->Des().MaxLength() < requiredSize)
+	{
+		iFileBuf = iFileBuf->ReAllocL(requiredSize);
+	}
+	iFileBuf->Des().Insert(pos, aTemplate);
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::GetImageDataL
+//
+//--------------------------------------------------------------------------------------------
+TSizeReal CXhtmlFileComposer::GetImageSizeL(CImageInfo aImage)
+{
+	TSizeReal imageSize(0,0);
+	TFileName name;
+	aImage.GetFilePathL(name);
+	if(name.Compare(KNullDesC()))
+	{
+		// Test file existing
+		TEntry data;
+		TInt err = iFsSession.Entry(name, data);
+		User::LeaveIfError(err);
+
+		// Get image size in pixels
+		CImageDecoder *id = NULL;
+		TRAP(err, id = CImageDecoder::FileNewL(iFsSession, name, KMimeJpeg()));
+
+		if(KErrNone == err)
+		{
+			TFrameInfo frameInfo;
+			frameInfo = id->FrameInfo();
+			imageSize = frameInfo.iOverallSizeInPixels;
+		}
+
+		if(id)
+			delete id;
+	}
+	LOG2("[CXhtmlFileComposer]\t Image size: %fx%f", imageSize.iWidth, imageSize.iHeight);
+	return imageSize;
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::AddPageL
+//
+//--------------------------------------------------------------------------------------------
+TBool CXhtmlFileComposer::AddPageL(TInt aCurrentImage, TInt& aPositionIndex, TInt& aPageCount)
+{
+	TBool ret = EFalse;
+	// increase position index by default and reset it in case of new page
+	++aPositionIndex;
+
+	User::LeaveIfNull(iFileBuf);
+	if(0 >= iImagesPerPage)
+		User::Leave(KErrArgument);
+
+	TInt modulo = aCurrentImage % iImagesPerPage;
+
+	if(0 == modulo)
+	{
+		//delete current page's frame marker before...
+		TInt pos = iFileBuf->Find(KFrame());
+		if(KErrNotFound != pos)
+			iFileBuf->Des().Delete(pos, KFrame().Length());
+
+		// ...add the new page template and reset position index
+		AddTemplateStringL(iPageTemplate, KPage());
+		aPositionIndex = 0;
+		++aPageCount;
+		ret = ETrue;
+	}
+	return ret;
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::GetImageName
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::GetImageNameL(CImageInfo aImageInfo, TDes8 &aImageName, TBool aDataFile)
+{
+	aImageInfo.GetEncodedUriL(aImageName);
+	if(0 >= aImageName.Length() || aDataFile)
+	{
+		aImageInfo.GetFilePath(aImageName);
+		if(0 >= aImageName.Length())
+			User::Leave(KErrArgument);
+	}
+	
+	LOG81("[CXhtmlFileComposer]\t Image: %S", &aImageName);
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::SizeAndOrientationL
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::SizeAndOrientationL(const CImageInfo aImageInfo, TSizeReal& aImageSize, TBool& aFramePortrait)
+{
+	aImageSize = GetImageSizeL(aImageInfo);
+
+	// If the size of any of the sides is zero, set the size as frame size
+	if(0 >= aImageSize.iWidth)
+		aImageSize = iImageFrame;
+
+	// orientations
+	iImagePortrait = (aImageSize.iWidth < aImageSize.iHeight ? ETrue : EFalse);
+	aFramePortrait = (iImageFrame.iWidth < iImageFrame.iHeight ? ETrue : EFalse);
+
+	// Set orientation in degrees
+	TInt orientation = KXFCZeroDeg;
+	if(aFramePortrait != iImagePortrait)
+		orientation = KXFC90Deg;
+
+	// Set orientation in template
+	TXhtmlSetting orientationStr;
+	orientationStr.Format(KDeg(), orientation);
+	ComposeTemplateL(orientationStr, KImgOrientation());
+
+	// Set image and image frame temporarily in same orientation
+	if(aFramePortrait != iImagePortrait)
+		iImageFrame.Reverse();
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::GetImageName
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::ComposePositionL(TInt aPositionIndex, RArray<TSizeReal>& aPositions)
+{
+	TSizeReal position(0,0);
+	if(aPositions.Count() <= aPositionIndex)
+		aPositionIndex = 0;
+
+	if(0 < aPositions.Count())
+		position = aPositions[aPositionIndex];
+
+	// Format position
+	TXhtmlSetting  positionTopStr, positionLeftStr;
+
+	FormatReal(PixelToUnit(position.iWidth), positionTopStr);
+	ComposeTemplateL(positionTopStr, KPositionTop());
+
+	FormatReal(PixelToUnit(position.iHeight), positionLeftStr);
+	ComposeTemplateL(positionLeftStr, KPositionLeft());
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// CXhtmlFileComposer::FormatReal
+//
+//--------------------------------------------------------------------------------------------
+void CXhtmlFileComposer::FormatReal(TRealX aNumber, TDes8& aString)
+{
+	TRealFormat form;
+	form.iPlaces = 4;
+	form.iPoint = TChar('.');
+	form.iType = KDoNotUseTriads | KRealFormatFixed;
+
+	aString.Num(aNumber, form);
+	aString.Append(KUnit());
+}
+
+// End of file