Skip to content
Commits on Source (9)
......@@ -7,14 +7,10 @@ before_install:
before_script: mvn javadoc:javadoc -DskipTests=true -B -V
script: mvn clean install
jdk:
- oraclejdk8
- openjdk8
cache:
directories:
- $HOME/.m2
addons:
apt:
packages:
- oracle-java8-installer
env:
global:
#GPG_PASSPHRASE
......
libsejda-java (3.2.75-1) unstable; urgency=medium
* New upstream version 3.2.75.
* Switch to debhelper-compat = 12.
* Declare compliance with Debian Policy 4.4.0.
* Remove get-orig-source target.
* Tighten build-dependency on libsambox-java.
* Use canonical VCS URI.
-- Markus Koschany <apo@debian.org> Sun, 21 Jul 2019 17:24:59 +0200
libsejda-java (3.2.66-1) unstable; urgency=medium
* New upstream version 3.2.66.
......
......@@ -5,7 +5,7 @@ Maintainer: Debian Java Maintainers <pkg-java-maintainers@lists.alioth.debian.or
Uploaders:
Markus Koschany <apo@debian.org>
Build-Depends:
debhelper (>= 11),
debhelper-compat (= 12),
default-jdk,
default-jdk-doc,
junit4,
......@@ -19,15 +19,15 @@ Build-Depends:
libimgscalr-java,
libmaven-javadoc-plugin-java,
libmetadata-extractor-java (>= 2.10.1),
libsambox-java (>= 1.1.41),
libsambox-java (>= 1.1.53),
libsejda-java,
libslf4j-java,
libtwelvemonkeys-java,
libxmlgraphics-commons-java,
maven-debian-helper (>= 2.1)
Standards-Version: 4.2.1
Vcs-Git: https://anonscm.debian.org/git/pkg-java/libsejda-java.git
Vcs-Browser: https://anonscm.debian.org/git/pkg-java/libsejda-java.git
Standards-Version: 4.4.0
Vcs-Git: https://salsa.debian.org/java-team/libsejda-java.git
Vcs-Browser: https://salsa.debian.org/java-team/libsejda-java
Homepage: http://sejda.org/
Package: libsejda-java
......
......@@ -28,7 +28,7 @@ Copyright: Google, Inc.
License: OFL-1.1
Files: debian/*
Copyright: 2017-2018, Markus Koschany <apo@debian.org>
Copyright: 2017-2019, Markus Koschany <apo@debian.org>
License: AGPL-3+
License: LGPL-2.1+
......
......@@ -5,6 +5,3 @@
override_dh_auto_test:
# Do nothing here
get-orig-source:
uscan --download-current-version --force-download
......@@ -6,7 +6,7 @@
<artifactId>sejda-parent</artifactId>
<packaging>pom</packaging>
<name>sejda</name>
<version>3.2.66</version>
<version>3.2.75</version>
<description>An extendible and configurable PDF manipulation layer library. A ready to use java library to perform PDF documents manipulation without having to deal with the low level API. Sejda offers many "ready to go" manipulations implemented using the SAMBox but it can be extended to use other implementations.</description>
<organization>
......@@ -32,7 +32,7 @@
<connection>scm:git:git@github.com:torakiki/sejda.git</connection>
<developerConnection>scm:git:git@github.com:torakiki/sejda.git</developerConnection>
<url>scm:git:git@github.com:torakiki/sejda.git</url>
<tag>v3.2.66</tag>
<tag>v3.2.75</tag>
</scm>
<developers>
......@@ -330,17 +330,17 @@
<properties>
<junit.version>4.12</junit.version>
<slf4j.version>1.7.25</slf4j.version>
<commons.lang.version>3.5</commons.lang.version>
<commons.lang.version>3.9</commons.lang.version>
<commons.io.version>2.6</commons.io.version>
<validation.api.version>1.0.0.GA</validation.api.version>
<mockito.version>1.10.19</mockito.version>
<logback.version>1.2.2</logback.version>
<logback.version>1.2.3</logback.version>
<jdepend.version>2.9.1</jdepend.version>
<hibernate-validator.version>4.2.0.Final</hibernate-validator.version>
<hamcrest.version>1.3</hamcrest.version>
<sambox.version>1.1.46</sambox.version>
<bouncycastle.version>1.56</bouncycastle.version>
<twelvemonkeys.version>3.3.1</twelvemonkeys.version>
<sambox.version>1.1.53</sambox.version>
<bouncycastle.version>1.61</bouncycastle.version>
<twelvemonkeys.version>3.4.1</twelvemonkeys.version>
<apache.poi.version>3.15</apache.poi.version>
<tess4j.version>3.2.1</tess4j.version>
<apache.commons.csv.version>1.5</apache.commons.csv.version>
......
......@@ -10,7 +10,7 @@
<parent>
<groupId>org.sejda</groupId>
<artifactId>sejda-parent</artifactId>
<version>3.2.66</version>
<version>3.2.75</version>
<relativePath>../pom.xml</relativePath>
</parent>
......
......@@ -239,14 +239,14 @@ public enum StandardCliCommand implements CliCommand {
protected CommandCliArgumentsTransformer<PdfToSingleTiffTaskCliArguments, PdfToSingleTiffParameters> getArgumentsTransformer() {
return new PdfToSingleTiffCliArgumentsTransformer();
}
}, "Converts a PDF document to a single TIFF image (TIFF format supports multiple images written to a single file).", "pdftosingletiff -f /tmp/file1.pdf -o /tmp/output.tiff --compressionType ccitt_group_3_2d --colorType gray_scale"),
}, "Converts a PDF document to a single TIFF image (TIFF format supports multiple images written to a single file).", "pdftosingletiff -f /tmp/file1.pdf -o /tmp/output.tiff --compressionType ccitt_group_3_2d --colorType black_and_white"),
PDF_TO_MULTIPLE_TIFF("pdftomultipletiff", new CliInterfacedTask<PdfToMultipleTiffTaskCliArguments, PdfToMultipleTiffParameters>() {
@Override
protected CommandCliArgumentsTransformer<PdfToMultipleTiffTaskCliArguments, PdfToMultipleTiffParameters> getArgumentsTransformer() {
return new PdfToMultipleTiffCliArgumentsTransformer();
}
}, "Converts a PDF document to multiple TIFF images (one image per page).", "pdftomultipletiff -f /tmp/file1.pdf -o /tmp --compressionType ccitt_group_3_2d --colorType gray_scale"),
}, "Converts a PDF document to multiple TIFF images (one image per page).", "pdftomultipletiff -f /tmp/file1.pdf -o /tmp --compressionType ccitt_group_3_2d --colorType black_and_white"),
SET_HEADER_FOOTER("setheaderfooter", new CliInterfacedTask<SetHeaderFooterTaskCliArguments, SetHeaderFooterParameters>() {
@Override
......
......@@ -50,7 +50,7 @@ target/assembled/bin/sejda-console splitbypages -f ../sejda-core/src/test/resour
target/assembled/bin/sejda-console splitbypages -h
target/assembled/bin/sejda-console splitbypages --help
target/assembled/bin/sejda-console splitbyevery -f ../sejda-core/src/test/resources/pdf/large_enc_test.pdf:secret123 -p [PAGENUMBER#####] -o /tmp/sejda-smoketest/ -j overwrite -n 5
target/assembled/bin/sejda-console splitbyevery -f ../sejda-core/src/test/resources/pdf/large_test.pdf -o /tmp/sejda-smoketest/ -p [FILENUMBER###-20] -n 10 -j overwrite
target/assembled/bin/sejda-console splitbyevery -f ../sejda-core/src/test/resources/pdf/large_test.pdf -o /tmp/sejda-smoketest/ -p [FILENUMBER###1]_of_[TOTAL_FILESNUMBER] -n 10 -j overwrite
target/assembled/bin/sejda-console splitbyevery -f ../sejda-core/src/test/resources/pdf/large_test.pdf -o /tmp/sejda-smoketest/ -p [FILENUMBER###-20] -n 10 -j overwrite --discardOutline --lenient
target/assembled/bin/sejda-console splitbyevery -h
target/assembled/bin/sejda-console splitbyevery --help
......
......@@ -26,7 +26,7 @@ function run_tests {
local exit_code=0
while read cmd; do
# echo "RUNNING: $cmd"
echo "RUNNING: $cmd"
if eval "$cmd"; then
echo "PASSED: $cmd"
else
......
......@@ -10,7 +10,7 @@
<parent>
<groupId>org.sejda</groupId>
<artifactId>sejda-parent</artifactId>
<version>3.2.66</version>
<version>3.2.75</version>
<relativePath>../pom.xml</relativePath>
</parent>
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>org.sejda</groupId>
<artifactId>sejda-parent</artifactId>
<version>3.2.66</version>
<version>3.2.75</version>
<relativePath>../pom.xml</relativePath>
</parent>
......
......@@ -20,6 +20,10 @@
*/
package org.sejda.core.support.io;
import static java.lang.String.format;
import static java.util.Objects.nonNull;
import static org.apache.commons.io.FilenameUtils.getBaseName;
import static org.apache.commons.io.FilenameUtils.getExtension;
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
import java.io.File;
......@@ -80,7 +84,18 @@ class DefaultMultipleOutputWriter implements MultipleOutputWriter {
*/
@Override
public void addOutput(PopulatedFileOutput fileOutput) {
multipleFiles.put(fileOutput.getName(), fileOutput.getFile());
if (nonNull(multipleFiles.putIfAbsent(fileOutput.getName(), fileOutput.getFile()))) {
// we already have a file with the same name, this shouldn't happen but could happen in split by text or bookmarks
int count = 1;
String basename = getBaseName(fileOutput.getName());
String extension = getExtension(fileOutput.getName());
while (nonNull(
multipleFiles.putIfAbsent(format("%s(%d).%s", basename, count, extension), fileOutput.getFile()))
&& count < 100) {
count++;
}
}
}
}
......@@ -19,10 +19,16 @@
*/
package org.sejda.core.support.io;
import static org.apache.commons.io.FilenameUtils.getBaseName;
import static org.apache.commons.io.FilenameUtils.getExtension;
import static org.apache.commons.lang3.SystemUtils.IS_OS_MAC;
import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
import static org.apache.commons.lang3.SystemUtils.JAVA_IO_TMPDIR;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
......@@ -70,7 +76,13 @@ public final class IOUtils {
buffer.deleteOnExit();
return buffer;
} catch (TaskOutputVisitException | IOException e) {
throw new TaskIOException("Unable to create temporary buffer", e);
// sometimes the above fails, eg: java.nio.file.AccessDeniedException: C:\\Users\\edi\\OneDrive\\Docs\\.sejdaTmp123124312312312.tmp
// so try again this time in the temp dir
try {
return createTemporaryBuffer();
} catch (TaskIOException ex) {
throw new TaskIOException("Unable to create temporary buffer", ex);
}
}
}
......@@ -101,7 +113,8 @@ public final class IOUtils {
File tmpDir = createTemporaryFolder();
File buffer = new File(tmpDir, filename);
boolean created = buffer.createNewFile();
if(!created) throw new IOException("Could not create new file: " + buffer.getAbsolutePath());
if (!created)
throw new IOException("Could not create new file: " + buffer.getAbsolutePath());
buffer.deleteOnExit();
return buffer;
} catch (IllegalStateException | IOException e) {
......@@ -147,6 +160,46 @@ public final class IOUtils {
return newNamedOutput;
}
public static String shortenFilename(String name) {
if (IS_OS_WINDOWS || IS_OS_MAC) {
// char based max length
return shortenFilenameCharLength(name, 255);
}
// bytes based max length
return shortenFilenameBytesLength(name, 254, StandardCharsets.UTF_8);
}
static String shortenFilenameCharLength(String input, int maxCharLength) {
if (input.length() > maxCharLength) {
String baseName = getBaseName(input);
String ext = getExtension(input);
baseName = baseName.substring(0, maxCharLength - 1 - ext.length());
return String.format("%s.%s", baseName, ext);
}
return input;
}
static String shortenFilenameBytesLength(String input, int maxBytesLength, Charset charset) {
if (input.getBytes(charset).length > maxBytesLength) {
String baseName = getBaseName(input);
String ext = getExtension(input);
// drop last char from basename, try again
baseName = baseName.substring(0, baseName.length() - 1);
String shorterFilename = String.format("%s.%s", baseName, ext);
while (shorterFilename.getBytes(charset).length > maxBytesLength) {
baseName = baseName.substring(0, baseName.length() - 1);
shorterFilename = String.format("%s.%s", baseName, ext);
}
return shorterFilename;
}
return input;
}
/**
* Component trying to find the best location for the temporary buffer based on the task output location
*
......
......@@ -23,6 +23,7 @@ package org.sejda.core.support.io;
import static java.util.Optional.of;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.sejda.core.support.io.IOUtils.findNewNameThatDoesNotExist;
import static org.sejda.core.support.io.IOUtils.shortenFilename;
import static org.sejda.model.output.ExistingOutputPolicy.FAIL;
import static org.sejda.model.output.ExistingOutputPolicy.SKIP;
......@@ -112,7 +113,8 @@ final class OutputWriterHelper {
throw new IOException(String.format(
"Unable to move %s to the output directory, no output name specified.", entry.getValue()));
}
moveFile(entry.getValue(), new File(outputDirectory, entry.getKey()), existingOutputPolicy,
moveFile(entry.getValue(), new File(outputDirectory, finalName(entry.getKey(), files.size())),
existingOutputPolicy,
executionContext);
}
}
......@@ -173,6 +175,10 @@ final class OutputWriterHelper {
}
}
private static String finalName(String filename, int totalFilesNumber) {
return shortenFilename(filename.replace("[TOTAL_FILESNUMBER]", Integer.toString(totalFilesNumber)));
}
/**
* Copy the populated file map to a zip output stream
*
......@@ -181,24 +187,22 @@ final class OutputWriterHelper {
* @throws IOException
*/
static void copyToStreamZipped(Map<String, File> files, OutputStream out) throws IOException {
ZipOutputStream zipOut = new ZipOutputStream(out);
try (ZipOutputStream zipOut = new ZipOutputStream(out)) {
for (Entry<String, File> entry : files.entrySet()) {
FileInputStream input = null;
if (isBlank(entry.getKey())) {
throw new IOException(String.format("Unable to copy %s to the output stream, no output name specified.",
entry.getValue()));
throw new IOException(String.format(
"Unable to copy %s to the output stream, no output name specified.", entry.getValue()));
}
try {
input = new FileInputStream(entry.getValue());
try (FileInputStream input = new FileInputStream(entry.getValue())) {
zipOut.putNextEntry(new ZipEntry(entry.getKey()));
LOG.debug("Copying {} to zip stream {}.", entry.getValue(), entry.getKey());
IOUtils.copy(input, zipOut);
} finally {
IOUtils.closeQuietly(input);
delete(entry.getValue());
}
}
IOUtils.closeQuietly(zipOut);
}
}
/**
......@@ -209,12 +213,9 @@ final class OutputWriterHelper {
* @throws IOException
*/
static void copyToStream(File file, OutputStream out) throws IOException {
InputStream in = null;
try {
in = new FileInputStream(file);
try (InputStream in = new FileInputStream(file)) {
IOUtils.copy(in, out);
} finally {
IOUtils.closeQuietly(in);
delete(file);
}
}
......
......@@ -20,8 +20,7 @@
*/
package org.sejda.core.support.prefix;
import static org.apache.commons.io.FilenameUtils.getBaseName;
import static org.apache.commons.io.FilenameUtils.getExtension;
import static java.util.Optional.ofNullable;
import static org.sejda.core.support.prefix.model.NameGenerationRequest.nameRequest;
import static org.sejda.core.support.prefix.processor.PrefixUtils.toSafeFilename;
......@@ -29,9 +28,6 @@ import org.apache.commons.lang3.StringUtils;
import org.sejda.core.support.prefix.model.NameGenerationRequest;
import org.sejda.core.support.prefix.processor.PrefixTypesChain;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* Component used to generate the output name for a manipulation given the input prefix (if any);
*
......@@ -64,63 +60,7 @@ public final class NameGenerator {
if (request == null) {
throw new IllegalArgumentException("Unable to generate a name for a null request.");
}
String result = toSafeFilename(prefixTypesChain.process(prefix, preProcessRequest(request)));
String osName = System.getProperty("os.name").toLowerCase();
if(osName.contains("win") || osName.contains("mac")) {
// char based max length
result = shortenFilenameCharLength(result, 255);
} else {
// bytes based max length
result = shortenFilenameBytesLength(result, 255, StandardCharsets.UTF_8);
}
return result;
}
static String shortenFilenameCharLength(String input, int maxCharLength) {
if (input.length() > 255) {
String baseName = getBaseName(input);
String ext = getExtension(input);
baseName = baseName.substring(0, 254 - ext.length());
return String.format("%s.%s", baseName, ext);
} else {
return input;
}
}
static String shortenFilenameBytesLength(String input, int maxBytesLength, Charset charset) {
if(input.getBytes(charset).length > maxBytesLength) {
String baseName = getBaseName(input);
String ext = getExtension(input);
// drop last char from basename, try again
baseName = baseName.substring(0, baseName.length() - 1);
String shorterFilename = String.format("%s.%s", baseName, ext);
while(shorterFilename.getBytes(charset).length > maxBytesLength) {
baseName = baseName.substring(0, baseName.length() - 1);
shorterFilename = String.format("%s.%s", baseName, ext);
}
return shorterFilename;
} else {
return input;
}
return toSafeFilename(prefixTypesChain.process(prefix, ofNullable(request).orElseGet(() -> nameRequest())));
}
/**
* pre process the request ensuring a not null request is returned
*
* @param request
* @return a not null request.
*/
private NameGenerationRequest preProcessRequest(NameGenerationRequest request) {
NameGenerationRequest retVal = request;
if (request == null) {
retVal = nameRequest();
}
return retVal;
}
}
......@@ -36,20 +36,21 @@ import org.slf4j.LoggerFactory;
* Ex: <b>[FILENUMBER]_BLA_[FILENUMBERE###]_LAB_[FILENUMBER####100]</b> and given file number <b>2</b> will produce <b>2_BLA_002_LAB_0102</b>
* <p>
* </p>
* <b>[FILENUMBER-3]_BLA_LAB_[FILENUMBER####100]</b> and given file number <b>2</b> will produce <b>-1_BLA_002_LAB_0102</b> </p>
* <b>[FILENUMBER-3]_BLA_LAB_[FILENUMBER####100]</b> and given file number <b>2</b> will produce <b>-1_BLA_002_LAB_0102</b>
* </p>
*
* @author Andrea Vacondio
*
*/
abstract class NumberPrefixProcessor implements PrefixProcessor {
private static final Logger LOG = LoggerFactory.getLogger(NumberPrefixProcessor.class);
private final String findRegexp;
private final Pattern pattern;
NumberPrefixProcessor(String prefix) {
if (StringUtils.isBlank(prefix)) {
throw new IllegalArgumentException("Prefix cannot be blank");
}
findRegexp = String.format("\\[%s(#*)(-?[0-9]*)\\]", prefix);
pattern = Pattern.compile(String.format("\\[%s(#*)(-?[0-9]*)\\]", prefix));
}
/**
......@@ -61,7 +62,7 @@ abstract class NumberPrefixProcessor implements PrefixProcessor {
*/
protected String findAndReplace(String inputString, Integer num) {
StringBuffer sb = new StringBuffer();
Matcher m = Pattern.compile(findRegexp).matcher(inputString);
Matcher m = pattern.matcher(inputString);
while (m.find()) {
String replacement = getReplacement(m.group(1), m.group(2), num);
m.appendReplacement(sb, replacement);
......@@ -77,14 +78,11 @@ abstract class NumberPrefixProcessor implements PrefixProcessor {
* @return the string the processor will use to perform replacement
*/
private String getReplacement(String numberPatter, String startingNumber, Integer num) {
String replacement = "";
Integer number = getReplacementNumber(startingNumber, num);
if (StringUtils.isNotBlank(numberPatter)) {
replacement = formatter(numberPatter).format(number);
} else {
replacement = number.toString();
return formatter(numberPatter).format(number);
}
return replacement;
return number.toString();
}
/**
......
......@@ -19,8 +19,6 @@
*/
package org.sejda.core.service;
import java.io.IOException;
import org.junit.Ignore;
import org.junit.Test;
import org.sejda.model.image.ImageColorType;
......@@ -28,15 +26,20 @@ import org.sejda.model.image.TiffCompressionType;
import org.sejda.model.output.ExistingOutputPolicy;
import org.sejda.model.parameter.image.PdfToMultipleTiffParameters;
import org.sejda.model.pdf.page.PageRange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* @author Andrea Vacondio
*
*/
@Ignore
public abstract class PdfToMltipleTiffTaskTest
public abstract class PdfToMultipleTiffTaskTest
extends MultipleImageConversionTaskTest<PdfToMultipleTiffParameters> {
private static final Logger LOG = LoggerFactory.getLogger(PdfToMultipleTiffTaskTest.class);
@Override
PdfToMultipleTiffParameters getMultipleImageParametersWithoutSource(ImageColorType type) {
PdfToMultipleTiffParameters parameters = new PdfToMultipleTiffParameters(type);
......@@ -51,6 +54,22 @@ public abstract class PdfToMltipleTiffTaskTest
public void colorAndCompressionCombinations() throws IOException {
for (ImageColorType type : ImageColorType.values()) {
for (TiffCompressionType compression : TiffCompressionType.values()) {
LOG.debug("Testing compression: {} and color type: {}", compression, type);
boolean unsupportedCombo = false;
if (compression == TiffCompressionType.CCITT_GROUP_3_1D ||
compression == TiffCompressionType.CCITT_GROUP_3_2D ||
compression == TiffCompressionType.CCITT_GROUP_4) {
if (type != ImageColorType.BLACK_AND_WHITE) {
unsupportedCombo = true;
}
}
if (unsupportedCombo) {
LOG.debug("Unsupported combination: compression: {} and color type: {}", compression, type);
continue;
}
PdfToMultipleTiffParameters parameters = getMultipleImageParametersWithoutSource(type);
parameters.addSource(shortInput());
parameters.addPageRange(new PageRange(1, 1));
......
......@@ -109,6 +109,20 @@ public abstract class SetHeaderFooterTaskTest extends BaseTaskTest<SetHeaderFoot
});
}
@Test
public void testLargeFontSize() throws Exception {
parameters = basicWithSources();
parameters.setVerticalAlign(VerticalAlign.TOP);
parameters.setPattern("This is a large font");
parameters.setFontSize(35);
execute(parameters);
testContext.assertTaskCompleted();
testContext.forEachPdfOutput(d -> {
assertHeaderHasText(d.getPage(0), "This is a large font");
});
}
@Test
public void testUnsupportedUnicodeCharacters() throws Exception {
parameters = basicWithSources();
......