MNT-14316 2013/2014 iWork Transformation Failure

* Support the creation of thumbnails for 2008/9 and 2013/14 iWorks file types.
* Support the preview of 2008/9 and 2013/14 iWorks file types. It should be noted that the
  embedded PDF files from 2008/9 no longer are used for the preview, so the quality is not
  as good as it was in the past. It is however using the embedded JPEG and quality is reasonable.   
* AppleIWorksContentTransformer no longer supports PDF as an target mimetype, as the newer
  iWoks 2013/14 formats no longer includes an embedded PDF file. Having PDF supported by the
  transformer resulted in Share always trying PDF which was one of the reasons that the newer
  formats did not preview. The other reason was that the embedded JPEG filename also changed.
* Added 'quick' files for testing.
* Also modified the exception message thrown when the iWorks file did not contain an embedded
  preview file, which is optional. An example would is "The source numbers file did not contain
  a jpg preview", rather than "Unable to transform numbers file to jpg". This should reduce the
  number of issues raised with support.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@135869 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2017-03-15 13:46:22 +00:00
parent 4fc7f98618
commit 61686ffd6a
7 changed files with 177 additions and 138 deletions

BIN
config/quick/quick.key Normal file

Binary file not shown.

BIN
config/quick/quick.numbers Normal file

Binary file not shown.

BIN
config/quick/quick.pages Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,35 +1,30 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 of the License, or
* (at your option) any later version.
*
* Alfresco 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 of the License, or
* (at your option) any later version.
*
* Alfresco 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.repository.ContentReader;
@@ -40,10 +35,16 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* Converts Apple iWorks files to PDFs or JPEGs for thumbnailing & previewing.
* The transformer will only work for iWorks 09 files and later as previous versions of those files
* were actually saved as directories.
* Converts Apple iWorks files to JPEGs for thumbnailing & previewing.
* The transformer will only work for iWorks 2013/14 files. Support for iWorks 2008/9 has been dropped as we cannot
* support both, because the newer format does not contain a PDF. If we say this transformer supports PDF, Share will
* assume incorrectly that we can convert to PDF and we would only get a preview for the older format and never the
* newer one. Both formats have the same mimetype.
*
* @author Neil Mc Erlean
* @since 4.0
@@ -51,23 +52,29 @@ import org.apache.commons.logging.LogFactory;
public class AppleIWorksContentTransformer extends AbstractContentTransformer2
{
private static final Log log = LogFactory.getLog(AppleIWorksContentTransformer.class);
// Apple's zip entry names for the front-page and all-doc previews in iWorks.
// We don't attempt to parse the XML 'manifest' (index.xml) within the iWorks file.
private static final String QUICK_LOOK_PREVIEW_PDF = "QuickLook/Preview.pdf";
private static final String QUICK_LOOK_THUMBNAIL_JPG = "QuickLook/Thumbnail.jpg";
private static final List<String> IWORKS_MIMETYPES = Arrays.asList(new String[]{MimetypeMap.MIMETYPE_IWORK_KEYNOTE,
MimetypeMap.MIMETYPE_IWORK_NUMBERS,
MimetypeMap.MIMETYPE_IWORK_PAGES});
private static final List<String> TARGET_MIMETYPES = Arrays.asList(new String[]{MimetypeMap.MIMETYPE_IMAGE_JPEG,
MimetypeMap.MIMETYPE_PDF});
// Apple's zip entry names for previews in iWorks have changed over time.
private static final List<String> PDF_PATHS = Arrays.asList(
"QuickLook/Preview.pdf"); // iWorks 2008/9
private static final List<String> JPG_PATHS = Arrays.asList(
"QuickLook/Thumbnail.jpg", // iWorks 2008/9
"preview.jpg"); // iWorks 2013/14 (720 x 552) We use the best quality image. Others are:
// (225 x 173) preview-web.jpg
// (53 x 41) preview-micro.jpg
private static final List<String> IWORKS_MIMETYPES = Arrays.asList(MimetypeMap.MIMETYPE_IWORK_KEYNOTE,
MimetypeMap.MIMETYPE_IWORK_NUMBERS,
MimetypeMap.MIMETYPE_IWORK_PAGES);
private static final List<String> TARGET_MIMETYPES = Arrays.asList(MimetypeMap.MIMETYPE_IMAGE_JPEG
// Commented out rather than removed, in case we can get SHARE to fall back to using JPEG when a PDF is not available
// ,MimetypeMap.MIMETYPE_PDF
);
@Override
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
// only support [iWorks] -> JPEG | PDF
// This is because iWorks 09+ files are zip files containing embedded jpeg/pdf previews.
// only support [iWorks] -> JPEG but only if these are embedded in the file.
// This is because iWorks 13+ files are zip files containing embedded jpeg previews.
return TARGET_MIMETYPES.contains(targetMimetype) && IWORKS_MIMETYPES.contains(sourceMimetype);
}
@@ -85,8 +92,8 @@ public class AppleIWorksContentTransformer extends AbstractContentTransformer2
final String sourceMimetype = reader.getMimetype();
final String sourceExtension = getMimetypeService().getExtension(sourceMimetype);
final String targetMimetype = writer.getMimetype();
final String targetExtension = getMimetypeService().getExtension(targetMimetype);
if (log.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
@@ -94,45 +101,37 @@ public class AppleIWorksContentTransformer extends AbstractContentTransformer2
.append(" to ").append(targetMimetype);
log.debug(msg.toString());
}
ZipArchiveInputStream iWorksZip = null;
try
try
{
// iWorks files are zip files (at least in recent versions, iWork 09).
// iWorks files are zip (or package) files.
// If it's not a zip file, the resultant ZipException will be caught as an IOException below.
iWorksZip = new ZipArchiveInputStream(reader.getContentInputStream());
ZipArchiveEntry entry = null;
// Look through the zip file entries for the preview/thumbnail.
List<String> paths = MimetypeMap.MIMETYPE_IMAGE_JPEG.equals(targetMimetype) ? JPG_PATHS : PDF_PATHS;
ZipArchiveEntry entry;
boolean found = false;
while ( !found && (entry = iWorksZip.getNextZipEntry()) != null )
while ((entry=iWorksZip.getNextZipEntry()) != null)
{
if (MimetypeMap.MIMETYPE_IMAGE_JPEG.equals(targetMimetype) &&
entry.getName().equals(QUICK_LOOK_THUMBNAIL_JPG))
{
writer.putContent( iWorksZip );
found = true;
}
else if (MimetypeMap.MIMETYPE_PDF.equals(targetMimetype) &&
entry.getName().equals(QUICK_LOOK_PREVIEW_PDF))
String name = entry.getName();
if (paths.contains(name))
{
writer.putContent( iWorksZip );
found = true;
break;
}
}
if (! found)
{
throw new AlfrescoRuntimeException("Unable to transform " + sourceExtension + " file to " + targetMimetype);
throw new AlfrescoRuntimeException("The source " + sourceExtension + " file did not contain a " + targetExtension + " preview");
}
}
catch (FileNotFoundException e1)
catch (IOException e)
{
throw new AlfrescoRuntimeException("Unable to transform " + sourceExtension + " file.", e1);
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Unable to transform " + sourceExtension + " file.", e);
throw new AlfrescoRuntimeException("Unable to transform " + sourceExtension + " file. It should have been a zip format file.", e);
}
finally
{

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 of the License, or
* (at your option) any later version.
*
* Alfresco 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 of the License, or
* (at your option) any later version.
*
* Alfresco 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
import java.io.File;
@@ -256,11 +256,15 @@ public abstract class AbstractContentTransformerTest extends TestCase
// attempt to convert to every other mimetype
for (String targetMimetype : mimetypes)
{
if (sourceMimetype.equals(targetMimetype))
{
// Don't test like-to-like transformations
continue;
}
if (sourceMimetype.equals(targetMimetype))
{
// Don't test like-to-like transformations
continue;
}
if (!doTestTransformation(quickFile, sourceMimetype, targetMimetype))
{
continue;
}
ContentWriter targetWriter = null;
// construct a reader onto the source file
String targetExtension = mimetypeService.getExtension(targetMimetype);
@@ -373,7 +377,19 @@ public abstract class AbstractContentTransformerTest extends TestCase
outputWriter.setEncoding("UTF8");
outputWriter.putContent(sb.toString());
}
/**
* Allows a subclass to skip selected transformations.
* @param quickFile name
* @param sourceMimetype of the quickFile
* @param targetMimetype of the transformation
* @return false to skip the transformation.
*/
protected boolean doTestTransformation(String quickFile, String sourceMimetype, String targetMimetype)
{
return false;
}
/**
* Allows implementations to do some extra checks on the
* results of the content as found by

View File

@@ -1,33 +1,36 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 of the License, or
* (at your option) any later version.
*
* Alfresco 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 of the License, or
* (at your option) any later version.
*
* Alfresco 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.transform;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.repository.TransformationOptions;
import java.util.Arrays;
import java.util.List;
/**
* Test case for {@link AppleIWorksContentTransformer} content transformer.
*
@@ -36,7 +39,7 @@ import org.alfresco.service.cmr.repository.TransformationOptions;
*/
public class AppleIWorksContentTransformerTest extends AbstractContentTransformerTest
{
private ContentTransformer transformer;
private AppleIWorksContentTransformer transformer;
@Override
public void setUp() throws Exception
@@ -45,9 +48,9 @@ public class AppleIWorksContentTransformerTest extends AbstractContentTransforme
transformer = new AppleIWorksContentTransformer();
// Ugly cast just to set the MimetypeService
((ContentTransformerHelper)transformer).setMimetypeService(mimetypeService);
((ContentTransformerHelper)transformer).setTransformerConfig(transformerConfig);
transformer.setMimetypeService(mimetypeService);
transformer.setTransformerDebug(transformerDebug);
transformer.setTransformerConfig(transformerConfig);
}
@Override
@@ -55,17 +58,38 @@ public class AppleIWorksContentTransformerTest extends AbstractContentTransforme
{
return transformer;
}
// Commented out rather than removed, in case we can get SHARE to fall back to using JPEG when a PDF is not available
// @Override
// protected String[] getQuickFilenames(String sourceMimetype)
// {
// List<String> filenames = Arrays.asList(super.getQuickFilenames(sourceMimetype));
// filenames.add("quick2009.pages");
// return (String[])filenames.toArray();
// }
//
// @Override
// protected boolean doTestTransformation(String quickFile, String sourceMimetype, String targetMimetype)
// {
// // This transformer can only do transforms to PDF when a iWorks 2008/9 file (rather than 2013/14) file is used.
// return !MimetypeMap.MIMETYPE_PDF.equals(targetMimetype) || !"quick2009.pages".endsWith(quickFile);
// }
//
// @Override
// protected boolean isTransformationExcluded(String sourceExtension, String targetExtension)
// {
// return "pdf".equals(targetExtension); // Our quick files are 2013/14 format so don't include a pdf, only jpgs.
// }
public void testIsTransformable() throws Exception
{
// thumbnails
assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_IWORK_KEYNOTE, MimetypeMap.MIMETYPE_IMAGE_JPEG, new TransformationOptions()));
assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_IWORK_NUMBERS, MimetypeMap.MIMETYPE_IMAGE_JPEG, new TransformationOptions()));
assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_IWORK_PAGES, MimetypeMap.MIMETYPE_IMAGE_JPEG, new TransformationOptions()));
// previews
assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_IWORK_KEYNOTE, MimetypeMap.MIMETYPE_PDF, new TransformationOptions()));
assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_IWORK_NUMBERS, MimetypeMap.MIMETYPE_PDF, new TransformationOptions()));
assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_IWORK_PAGES, MimetypeMap.MIMETYPE_PDF, new TransformationOptions()));
// Commented out rather than removed, in case we can get SHARE to fall back to using JPEG when a PDF is not available
// assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_IWORK_KEYNOTE, MimetypeMap.MIMETYPE_PDF, new TransformationOptions()));
// assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_IWORK_NUMBERS, MimetypeMap.MIMETYPE_PDF, new TransformationOptions()));
// assertTrue(transformer.isTransformable(MimetypeMap.MIMETYPE_IWORK_PAGES, MimetypeMap.MIMETYPE_PDF, new TransformationOptions()));
}
}