diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/PngCreator.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/PngCreator.java
new file mode 100755
index 0000000000000000000000000000000000000000..1ba895d140d5de280203ae4ab73fadf8874cb925
--- /dev/null
+++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/PngCreator.java
@@ -0,0 +1,23 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ * <p>
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ * <p>
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 3.0 of the License, or (at your option) any later
+ * version.
+ * <p>
+ * BigBlueButton 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 Lesser General Public License for more details.
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.bigbluebutton.presentation;
+
+public interface PngCreator {
+	public boolean createPng(UploadedPresentation pres);
+}
diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/PdfToSwfSlidesGenerationService.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/PdfToSwfSlidesGenerationService.java
index e645015a536951ac8bb2d4e882a3cfa665f710df..8901806c0bb6e8a0f545f24df3066e0f014a5f2b 100755
--- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/PdfToSwfSlidesGenerationService.java
+++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/PdfToSwfSlidesGenerationService.java
@@ -33,15 +33,8 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import org.bigbluebutton.presentation.ConversionMessageConstants;
-import org.bigbluebutton.presentation.ConversionUpdateMessage;
+import org.bigbluebutton.presentation.*;
 import org.bigbluebutton.presentation.ConversionUpdateMessage.MessageBuilder;
-import org.bigbluebutton.presentation.PageConverter;
-import org.bigbluebutton.presentation.PdfToSwfSlide;
-import org.bigbluebutton.presentation.SvgImageCreator;
-import org.bigbluebutton.presentation.TextFileCreator;
-import org.bigbluebutton.presentation.ThumbnailCreator;
-import org.bigbluebutton.presentation.UploadedPresentation;
 import org.bigbluebutton.presentation.messages.DocPageCountExceeded;
 import org.bigbluebutton.presentation.messages.DocPageCountFailed;
 import org.slf4j.Logger;
@@ -57,12 +50,16 @@ public class PdfToSwfSlidesGenerationService {
   private PageConverter pdfToSwfConverter;
   private ExecutorService executor;
   private ThumbnailCreator thumbnailCreator;
+	private PngCreator pngCreator;
+
   private TextFileCreator textFileCreator;
   private SvgImageCreator svgImageCreator;
   private long MAX_CONVERSION_TIME = 5 * 60 * 1000;
   private String BLANK_SLIDE;
   private int MAX_SWF_FILE_SIZE;
   private boolean svgImagesRequired;
+	private boolean generatePngs;
+
   private final long CONVERSION_TIMEOUT = 20000000000L; // 20s
 
   public PdfToSwfSlidesGenerationService(int numConversionThreads) {
@@ -81,6 +78,11 @@ public class PdfToSwfSlidesGenerationService {
         createSvgImages(pres);
       }
 
+			// only create PNG images if the configuration requires it
+			if (generatePngs) {
+				createPngImages(pres);
+			}
+
       notifier.sendConversionCompletedMessage(pres);
     }
   }
@@ -161,6 +163,10 @@ public class PdfToSwfSlidesGenerationService {
     svgImageCreator.createSvgImages(pres);
   }
 
+	private void createPngImages(UploadedPresentation pres) {
+		pngCreator.createPng(pres);
+	}
+
   private void convertPdfToSwf(UploadedPresentation pres) {
     int numPages = pres.getNumberOfPages();
     List<PdfToSwfSlide> slides = setupSlides(pres, numPages);
@@ -318,14 +324,22 @@ public class PdfToSwfSlidesGenerationService {
     this.MAX_SWF_FILE_SIZE = size;
   }
 
-  public void setSvgImagesRequired(boolean svg) {
-    this.svgImagesRequired = svg;
+  public void setGeneratePngs(boolean generatePngs) {
+    this.generatePngs = generatePngs;
   }
 
+	public void setSvgImagesRequired(boolean svg) {
+		this.svgImagesRequired = svg;
+	}
+
   public void setThumbnailCreator(ThumbnailCreator thumbnailCreator) {
     this.thumbnailCreator = thumbnailCreator;
   }
 
+  public void setPngCreator(PngCreator pngCreator) {
+    this.pngCreator = pngCreator;
+  }
+
   public void setTextFileCreator(TextFileCreator textFileCreator) {
     this.textFileCreator = textFileCreator;
   }
diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/PngCreatorImp.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/PngCreatorImp.java
new file mode 100755
index 0000000000000000000000000000000000000000..9ae9c14825c4fa51933ed99110752bc6836fd761
--- /dev/null
+++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/PngCreatorImp.java
@@ -0,0 +1,173 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ * <p>
+ * Copyright (c) 2014 BigBlueButton Inc. and by respective authors (see below).
+ * <p>
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 3.0 of the License, or (at your option) any later
+ * version.
+ * <p>
+ * BigBlueButton 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 Lesser General Public License for more details.
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.bigbluebutton.presentation.imp;
+
+import com.google.gson.Gson;
+import org.apache.commons.io.FileUtils;
+import org.bigbluebutton.presentation.PngCreator;
+import org.bigbluebutton.presentation.UploadedPresentation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PngCreatorImp implements PngCreator {
+	private static Logger log = LoggerFactory.getLogger(PngCreatorImp.class);
+
+	private static final Pattern PAGE_NUMBER_PATTERN = Pattern.compile("(.+-png)-([0-9]+)(.png)");
+
+	private String BLANK_PNG;
+	private int slideWidth = 800;
+
+	private static String TEMP_PNG_NAME = "temp-png";
+
+	public boolean createPng(UploadedPresentation pres) {
+		boolean success = false;
+		File pngDir = determinePngDirectory(pres.getUploadedFile());
+
+		if (!pngDir.exists())
+			pngDir.mkdir();
+
+		cleanDirectory(pngDir);
+
+		try {
+			success = generatePngs(pngDir, pres);
+		} catch (InterruptedException e) {
+			log.warn("Interrupted Exception while generating png.");
+			success = false;
+		}
+
+		// Create blank thumbnails for pages that failed to generate a thumbnail.
+		createBlankPngs(pngDir, pres.getNumberOfPages());
+
+		renamePng(pngDir);
+
+		return success;
+	}
+
+	private boolean generatePngs(File pngsDir, UploadedPresentation pres)
+					throws InterruptedException {
+		String source = pres.getUploadedFile().getAbsolutePath();
+		String dest;
+		String COMMAND = "";
+		dest = pngsDir.getAbsolutePath() + File.separator + TEMP_PNG_NAME;
+		COMMAND = "pdftocairo -png -scale-to " + slideWidth + " " + source + " " + dest;
+
+		boolean done = new ExternalProcessExecutor().exec(COMMAND, 60000);
+
+		if (done) {
+			return true;
+		} else {
+			Map<String, Object> logData = new HashMap<String, Object>();
+			logData.put("meetingId", pres.getMeetingId());
+			logData.put("presId", pres.getId());
+			logData.put("filename", pres.getName());
+			logData.put("message", "Failed to create png.");
+
+			Gson gson = new Gson();
+			String logStr = gson.toJson(logData);
+			log.warn("-- analytics -- " + logStr);
+		}
+
+		return false;
+	}
+
+	private File determinePngDirectory(File presentationFile) {
+		return new File(presentationFile.getParent() + File.separatorChar + "pngs");
+	}
+
+	private void renamePng(File dir) {
+		/*
+		 * If more than 1 file, filename like 'temp-png-X.png' else filename is
+		 * 'temp-png.png'
+		 */
+		if (dir.list().length > 1) {
+			File[] files = dir.listFiles();
+			Matcher matcher;
+			for (int i = 0; i < files.length; i++) {
+				matcher = PAGE_NUMBER_PATTERN.matcher(files[i].getAbsolutePath());
+				if (matcher.matches()) {
+					// Path should be something like
+					// 'c:/temp/bigluebutton/presname/pngs/temp-png-1.png'
+					// Extract the page number. There should be 4 matches.
+					// 0. c:/temp/bigluebutton/presname/pngs/temp-png-1.png
+					// 1. c:/temp/bigluebutton/presname/pngs/temp-png
+					// 2. 1 ---> what we are interested in
+					// 3. .png
+					// We are interested in the second match.
+					int pageNum = Integer.valueOf(matcher.group(2).trim()).intValue();
+					String newFilename = "slide-" + (pageNum) + ".png";
+					File renamedFile = new File(
+									dir.getAbsolutePath() + File.separator + newFilename);
+					files[i].renameTo(renamedFile);
+				}
+			}
+		} else if (dir.list().length == 1) {
+			File oldFilename = new File(
+							dir.getAbsolutePath() + File.separator + dir.list()[0]);
+			String newFilename = "slide-1.png";
+			File renamedFile = new File(
+							oldFilename.getParent() + File.separator + newFilename);
+			oldFilename.renameTo(renamedFile);
+		}
+	}
+
+	private void createBlankPngs(File pngsDir, int pageCount) {
+		File[] pngs = pngsDir.listFiles();
+
+		if (pngs.length != pageCount) {
+			for (int i = 0; i < pageCount; i++) {
+				File png = new File(pngsDir.getAbsolutePath() + File.separator + TEMP_PNG_NAME + "-" + i + ".png");
+				if (!png.exists()) {
+					log.info("Copying blank png for slide " + i);
+					copyBlankPng(png);
+				}
+			}
+		}
+	}
+
+	private void copyBlankPng(File png) {
+		try {
+			FileUtils.copyFile(new File(BLANK_PNG), png);
+		} catch (IOException e) {
+			log.error("IOException while copying blank thumbnail.");
+		}
+	}
+
+	private void cleanDirectory(File directory) {
+		File[] files = directory.listFiles();
+		for (int i = 0; i < files.length; i++) {
+			files[i].delete();
+		}
+	}
+
+	public void setBlankPng(String blankPng) {
+		BLANK_PNG = blankPng;
+	}
+
+	public void setSlideWidth(int width) {
+		slideWidth = width;
+	}
+
+}
diff --git a/bigbluebutton-web/grails-app/conf/UrlMappings.groovy b/bigbluebutton-web/grails-app/conf/UrlMappings.groovy
index ef1cf7959287072a346f42b2264c9ec9353a5441..e7d2eba07111ebe601b1bf67efeef393c45c22c0 100755
--- a/bigbluebutton-web/grails-app/conf/UrlMappings.groovy
+++ b/bigbluebutton-web/grails-app/conf/UrlMappings.groovy
@@ -29,6 +29,10 @@ class UrlMappings {
 			action = [GET:'showThumbnail']
 		}
 
+		"/presentation/$conference/$room/$presentation_name/png/$id"(controller:"presentation") {
+			action = [GET:'showPng']
+		}
+
 		"/presentation/$conference/$room/$presentation_name/svgs"(controller:"presentation") {
 			action = [GET:'numberOfSvgs']
 		}
diff --git a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties
index 6916bdb3e94b667cfb1baae585fff30ee9839a14..4bb688af3f495dfbe703f22ec49e50425f5c8308 100755
--- a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties
+++ b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties
@@ -50,6 +50,7 @@ presCheckExec=/usr/share/prescheck/prescheck.sh
 BLANK_SLIDE=/var/bigbluebutton/blank/blank-slide.swf
 BLANK_PRESENTATION=/var/bigbluebutton/blank/blank-presentation.pdf
 BLANK_THUMBNAIL=/var/bigbluebutton/blank/blank-thumb.png
+BLANK_PNG=/var/bigbluebutton/blank/blank-png.png
 
 #----------------------------------------------------
 # Number of minutes the conversion should take. If it takes
@@ -88,6 +89,12 @@ numConversionThreads=2
 # to be used in the HTML5 client
 svgImagesRequired=false
 
+#----------------------------------------------------
+# Additional conversion of the presentation slides to PNG
+# to be used in the IOS mobile client
+generatePngs=true
+pngSlideWidth=1200
+
 # Default number of digits for voice conference users joining through the PSTN.
 defaultNumDigitsForTelVoice=5
 
diff --git a/bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml b/bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml
index 1a053f0b7def608749d8b9a2c52c9da87be011a6..d649f48bc10482f7bf567360e917f9c990eb3c79 100755
--- a/bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml
+++ b/bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml
@@ -70,6 +70,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         <property name="blankThumbnail" value="${BLANK_THUMBNAIL}"/>
     </bean>
 
+    <bean id="pngCreator" class="org.bigbluebutton.presentation.imp.PngCreatorImp">
+        <property name="blankPng" value="${BLANK_PNG}"/>
+        <property name="slideWidth" value="${pngSlideWidth}"/>
+    </bean>
+
     <bean id="textFileCreator" class="org.bigbluebutton.presentation.imp.TextFileCreatorImp"/>
 
     <bean id="svgImageCreator" class="org.bigbluebutton.presentation.imp.SvgImageCreatorImp">
@@ -84,6 +89,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         <property name="counterService" ref="pageCounterService"/>
         <property name="pageConverter" ref="pdf2SwfPageConverter"/>
         <property name="thumbnailCreator" ref="thumbCreator"/>
+        <property name="pngCreator" ref="pngCreator"/>
         <property name="textFileCreator" ref="textFileCreator"/>
         <property name="svgImageCreator" ref="svgImageCreator"/>
         <property name="blankSlide" value="${BLANK_SLIDE}"/>
@@ -91,6 +97,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         <property name="maxConversionTime" value="${maxConversionTime}"/>
         <property name="swfSlidesGenerationProgressNotifier" ref="swfSlidesGenerationProgressNotifier"/>
         <property name="svgImagesRequired" value="${svgImagesRequired}"/>
+        <property name="generatePngs" value="${generatePngs}"/>
     </bean>
 
     <bean id="imageToSwfSlidesGenerationService"
diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy
index d47df65d9a9f564fe248740342c589db52104906..69ae7a25a41934b83a4450b6940a4431993f9d36 100755
--- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy
+++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy
@@ -224,6 +224,29 @@ class PresentationController {
     
     return null;
   }
+
+  def showPng = {
+    def presentationName = params.presentation_name
+    def conf = params.conference
+    def rm = params.room
+    def png = params.id
+
+    InputStream is = null;
+    try {
+      def pres = presentationService.showPng(conf, rm, presentationName, png)
+      if (pres.exists()) {
+
+        def bytes = pres.readBytes()
+        response.addHeader("Cache-Control", "no-cache")
+        response.contentType = 'image'
+        response.outputStream << bytes;
+      }
+    } catch (IOException e) {
+      log.error("Error reading file.\n" + e.getMessage());
+    }
+
+    return null;
+  }
   
   def showTextfile = {
     def presentationName = params.presentation_name
@@ -340,7 +363,7 @@ class PresentationController {
             }
           }
         }
-      }		
+      }
   }
 
   def numberOfSvgs = {
diff --git a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy
index 1f45e8f1e49e160377f06980a6067b6c3041a018..88f765f9901ead73c5cd10221b5a9097a614361a 100755
--- a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy
+++ b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy
@@ -109,6 +109,14 @@ class PresentationService {
 		new File(thumbFile)
 	}
 
+	def showPng = {conf, room, presentationName, page ->
+		def pngFile = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
+				"pngs" + File.separatorChar + "slide-${page}.png"
+		log.debug "showing $pngFile"
+
+		new File(pngFile)
+	}
+
 	def showTextfile = {conf, room, presentationName, textfile ->
 		def txt = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
 					"textfiles" + File.separatorChar + "slide-${textfile}.txt"