├── settings.gradle ├── src ├── test │ ├── resources │ │ └── in │ │ │ ├── test.doc │ │ │ ├── test.docx │ │ │ ├── test.ppt │ │ │ ├── test.pptx │ │ │ ├── test.txt │ │ │ └── test.csv │ └── java │ │ └── com │ │ └── chiragji │ │ └── docuconverter │ │ ├── AbstractTest.java │ │ └── api │ │ └── DocuConverterTest.java └── main │ └── java │ └── com │ └── chiragji │ └── docuconverter │ ├── api │ ├── ConvertToType.java │ ├── DocumentType.java │ └── DocuConverter.java │ ├── utils │ └── TextUtils.java │ ├── exceptions │ ├── DocuConverterException.java │ └── UnsupportedTypeException.java │ ├── enums │ ├── FontStyle.java │ └── PageSize.java │ ├── logic │ ├── DocToPdf.java │ ├── DocXtoPdf.java │ ├── PDFConverter.java │ ├── DocuConverterFactory.java │ ├── TextToPdf.java │ ├── AbstractDocuConverter.java │ ├── PptXToPdf.java │ ├── PptToPdf.java │ └── CsvToXml.java │ ├── console │ └── ConsoleValues.java │ └── Bootstrap.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── .gitattributes ├── LICENSE ├── .github └── workflows │ └── gradle.yml ├── gradlew.bat ├── README.md └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'DocuConverter' 2 | -------------------------------------------------------------------------------- /src/test/resources/in/test.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chirag-ji/DocuConverter/HEAD/src/test/resources/in/test.doc -------------------------------------------------------------------------------- /src/test/resources/in/test.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chirag-ji/DocuConverter/HEAD/src/test/resources/in/test.docx -------------------------------------------------------------------------------- /src/test/resources/in/test.ppt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chirag-ji/DocuConverter/HEAD/src/test/resources/in/test.ppt -------------------------------------------------------------------------------- /src/test/resources/in/test.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chirag-ji/DocuConverter/HEAD/src/test/resources/in/test.pptx -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chirag-ji/DocuConverter/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Gradle project-specific cache directory 2 | .gradle 3 | 4 | # Ignore Gradle build output directory 5 | build 6 | .idea/ 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/api/ConvertToType.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.api; 2 | 3 | /** 4 | * Denotes the designating document type 5 | * 6 | * @author Chirag Gupta (chirag-ji) 7 | */ 8 | public enum ConvertToType { 9 | PDF, XML 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/api/DocumentType.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.api; 2 | 3 | /** 4 | * Denotes the source document type 5 | * 6 | * @author Chirag Gupta (chirag-ji) 7 | */ 8 | public enum DocumentType { 9 | DOCX, PPTX, TXT, PPT, CSV 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/utils/TextUtils.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.utils; 2 | 3 | import java.util.Objects; 4 | 5 | public interface TextUtils { 6 | static boolean isEmpty(CharSequence data) { 7 | return Objects.isNull(data) || data.toString().trim().isEmpty(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/exceptions/DocuConverterException.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.exceptions; 2 | 3 | /** 4 | * @author Chirag Gupta (chirag-ji) 5 | */ 6 | public class DocuConverterException extends Exception { 7 | 8 | public DocuConverterException() { 9 | } 10 | 11 | public DocuConverterException(String message) { 12 | super(message); 13 | } 14 | 15 | public DocuConverterException(Throwable cause) { 16 | super(cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/exceptions/UnsupportedTypeException.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.exceptions; 2 | 3 | /** 4 | * @author Chirag Gupta (chirag-ji) 5 | */ 6 | public class UnsupportedTypeException extends Exception { 7 | public UnsupportedTypeException() { 8 | } 9 | 10 | public UnsupportedTypeException(String message) { 11 | super(message); 12 | } 13 | 14 | public UnsupportedTypeException(Throwable cause) { 15 | super(cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/enums/FontStyle.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.enums; 2 | 3 | import com.itextpdf.text.Font; 4 | 5 | /** 6 | * @author Chirag Gupta (chirag-ji) 7 | */ 8 | public enum FontStyle { 9 | NORMAL(Font.NORMAL), 10 | BOLD(Font.BOLD), 11 | ITALIC(Font.ITALIC), 12 | UNDERLINE(Font.UNDERLINE), 13 | STRIKETHRU(Font.STRIKETHRU), 14 | BOLDITALIC(Font.BOLDITALIC), 15 | UNDEFINED(Font.UNDEFINED), 16 | DEFAULTSIZE(Font.DEFAULTSIZE); 17 | 18 | private final int style; 19 | 20 | FontStyle(int style) { 21 | this.style = style; 22 | } 23 | 24 | public int getStyle() { 25 | return style; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/logic/DocToPdf.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.logic; 2 | 3 | import org.docx4j.Docx4J; 4 | import org.docx4j.openpackaging.packages.WordprocessingMLPackage; 5 | 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | 9 | /** 10 | * @author Chirag Gupta (chirag-ji) 11 | */ 12 | public final class DocToPdf extends AbstractDocuConverter { 13 | DocToPdf(InputStream inputStream) { 14 | super(inputStream); 15 | } 16 | 17 | @Override 18 | public void convertIn(OutputStream outputStream) throws Exception { 19 | setOutputStream(outputStream); 20 | onStart(); 21 | WordprocessingMLPackage aPackage = Docx4J.load(this.inputStream); 22 | onProcessing(); 23 | Docx4J.toPDF(aPackage, outputStream); 24 | onCompleted(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Chirag Gupta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/logic/DocXtoPdf.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.logic; 2 | 3 | import com.chiragji.docuconverter.enums.PageSize; 4 | import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions; 5 | import org.apache.poi.xwpf.usermodel.XWPFDocument; 6 | 7 | import java.io.InputStream; 8 | import java.io.OutputStream; 9 | 10 | /** 11 | * @author Chirag Gupta (chirag-ji) 12 | */ 13 | public final class DocXtoPdf extends AbstractDocuConverter { 14 | 15 | DocXtoPdf(InputStream inputStream) { 16 | super(inputStream); 17 | } 18 | 19 | @Override 20 | public void convertIn(OutputStream outputStream) throws Exception { 21 | setOutputStream(outputStream); 22 | onStart(); 23 | XWPFDocument xwpfDocument = new XWPFDocument(this.inputStream); 24 | PdfOptions pdfOptions = PdfOptions.create(); 25 | onProcessing(); 26 | PDFConverter.convert(xwpfDocument, this.outputStream, pdfOptions); 27 | onCompleted(); 28 | } 29 | 30 | @Override 31 | public void setPageSize(PageSize pageSize) { 32 | throw new UnsupportedOperationException(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/console/ConsoleValues.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.console; 2 | 3 | import org.kohsuke.args4j.Option; 4 | 5 | /** 6 | * This class defines the command line arguments 7 | * 8 | * @author Chirag Gupta (chirag-ji) 9 | */ 10 | public class ConsoleValues { 11 | @Option(name = "-input", aliases = {"-i", "-in"}, metaVar = "", 12 | usage = "Specifies input file path") 13 | private String inputPath; 14 | 15 | @Option(name = "-output", aliases = {"-o", "-out"}, metaVar = "", 16 | usage = "Specifies output file path") 17 | private String outPath; 18 | 19 | @Option(name = "-verbose", aliases = "-v", usage = "To see intermediate processing messages.") 20 | private boolean verbose; 21 | 22 | @Option(name = "-version", aliases = "-ver", usage = "View current Library Version") 23 | private boolean showVersion; 24 | 25 | @Option(name = "-help", aliases = "-h", usage = "Shows this message") 26 | private boolean showHelp; 27 | 28 | public String getInputPath() { 29 | return inputPath; 30 | } 31 | 32 | public String getOutPath() { 33 | return outPath; 34 | } 35 | 36 | public boolean isVerbose() { 37 | return verbose; 38 | } 39 | 40 | public boolean isShowVersion() { 41 | return showVersion; 42 | } 43 | 44 | public boolean isShowHelp() { 45 | return showHelp; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java Build 2 | 3 | on: 4 | push: { } 5 | pull_request: 6 | types: [ opened, synchronize, reopened ] 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | - name: Set up JDK 11 19 | uses: actions/setup-java@v3 20 | with: 21 | java-version: '11' 22 | distribution: 'temurin' 23 | 24 | - name: Make gradlew executable 25 | run: chmod +x ./gradlew 26 | 27 | - name: Build with Gradle 28 | uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 29 | with: 30 | arguments: build 31 | 32 | - name: Cache SonarCloud packages 33 | uses: actions/cache@v1 34 | with: 35 | path: ~/.sonar/cache 36 | key: ${{ runner.os }}-sonar 37 | restore-keys: ${{ runner.os }}-sonar 38 | 39 | - name: Cache Gradle packages 40 | uses: actions/cache@v1 41 | with: 42 | path: ~/.gradle/caches 43 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 44 | restore-keys: ${{ runner.os }}-gradle 45 | 46 | - name: Build And Analyse 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 49 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 50 | run: ./gradlew build sonarqube --info 51 | -------------------------------------------------------------------------------- /src/test/java/com/chiragji/docuconverter/AbstractTest.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter; 2 | 3 | import org.apache.commons.io.FileUtils; 4 | import org.checkerframework.checker.nullness.qual.NonNull; 5 | import org.junit.jupiter.api.AfterAll; 6 | import org.junit.jupiter.api.BeforeAll; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertTrue; 12 | 13 | public abstract class AbstractTest { 14 | 15 | private static final String TEST_DIR = "src/test/resources/"; 16 | private static final String TEST_IN_DIR = TEST_DIR + "in"; 17 | private static final String TEST_OUT_DIR = TEST_DIR + "out"; 18 | 19 | protected File getTestInFile(@NonNull String name) { 20 | return new File(TEST_IN_DIR, name); 21 | } 22 | 23 | protected File getTestOutFile(@NonNull String name) { 24 | return new File(TEST_OUT_DIR, name); 25 | } 26 | 27 | @BeforeAll 28 | private static void initTests() { 29 | File dir = new File(TEST_OUT_DIR); 30 | dir.mkdirs(); 31 | } 32 | 33 | @AfterAll 34 | private static void cleanupCtx() { 35 | try { 36 | FileUtils.forceDelete(new File(TEST_OUT_DIR)); 37 | } catch (IOException e) { 38 | System.out.println("Fail to delete file: " + TEST_OUT_DIR); 39 | } 40 | } 41 | 42 | protected void assertFileExists(File outFile) { 43 | assertTrue(outFile.exists(), "Assert that out file exists"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/logic/PDFConverter.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.logic; 2 | 3 | import com.chiragji.docuconverter.exceptions.DocuConverterException; 4 | import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions; 5 | import fr.opensagres.poi.xwpf.converter.pdf.internal.PdfMapper; 6 | import org.apache.poi.xwpf.usermodel.XWPFDocument; 7 | 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.OutputStream; 10 | import java.util.Objects; 11 | 12 | /** 13 | * @author Chirag Gupta (chirag-ji) 14 | */ 15 | interface PDFConverter { 16 | 17 | static void convert(XWPFDocument xwpfDocument, OutputStream outputStream, PdfOptions pdfOptions) 18 | throws DocuConverterException { 19 | try { 20 | Objects.requireNonNull(xwpfDocument, "Type is null"); 21 | Objects.requireNonNull(outputStream, "OutputStream is null"); 22 | ByteArrayOutputStream temp = new ByteArrayOutputStream(); 23 | PdfMapper mapper = new PdfMapper(xwpfDocument, temp, pdfOptions, null); 24 | mapper.start(); 25 | if (mapper.useTotalPageField()) { 26 | int pageCount = mapper.getPageCount(); 27 | mapper = new PdfMapper(xwpfDocument, outputStream, pdfOptions, pageCount); 28 | mapper.start(); 29 | } else 30 | outputStream.write(temp.toByteArray()); 31 | } catch (Exception e) { 32 | throw new DocuConverterException(e); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/logic/DocuConverterFactory.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.logic; 2 | 3 | import com.chiragji.docuconverter.api.ConvertToType; 4 | import com.chiragji.docuconverter.api.DocuConverter; 5 | import com.chiragji.docuconverter.api.DocumentType; 6 | import com.chiragji.docuconverter.exceptions.UnsupportedTypeException; 7 | 8 | import java.io.InputStream; 9 | import java.util.Objects; 10 | 11 | /** 12 | * This class will generate the implementer according to parameters 13 | * 14 | * @author Chirag Gupta (chirag-ji) 15 | */ 16 | public interface DocuConverterFactory { 17 | /** 18 | * This will initiate the implementers of the {@link DocuConverter} to perform the related conversion 19 | * 20 | * @param inputStream The stream in which the source document exists 21 | * @param from Type of source document 22 | * @param to Type of designating document 23 | * @return The type implementor of the related conversion method 24 | * @throws UnsupportedTypeException if no implementation found for the documents 25 | */ 26 | static DocuConverter getConverter(InputStream inputStream, DocumentType from, ConvertToType to) 27 | throws UnsupportedTypeException { 28 | Objects.requireNonNull(from, "DocumentType Type is null"); 29 | Objects.requireNonNull(to, "ConvertTo type document to is null"); 30 | if (to == ConvertToType.PDF) { 31 | switch (from) { 32 | case DOCX: 33 | return new DocXtoPdf(inputStream); 34 | case PPTX: 35 | return new PptXToPdf(inputStream); 36 | case TXT: 37 | return new TextToPdf(inputStream); 38 | case PPT: 39 | return new PptToPdf(inputStream); 40 | } 41 | } else if (to == ConvertToType.XML) { 42 | if (from == DocumentType.CSV) { 43 | return new CsvToXml(inputStream); 44 | } 45 | } 46 | throw new UnsupportedTypeException("Conversion from '" + from.name() + "' to '" + to.name() + "' is not currently supported"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/api/DocuConverter.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.api; 2 | 3 | import com.chiragji.docuconverter.enums.PageSize; 4 | import com.chiragji.docuconverter.exceptions.UnsupportedTypeException; 5 | import com.chiragji.docuconverter.logic.DocuConverterFactory; 6 | 7 | import java.io.InputStream; 8 | import java.io.OutputStream; 9 | 10 | /** 11 | * API for converting Document from one from to another format 12 | * 13 | * @author Chirag Gupta (chirag-ji) 14 | * @see com.chiragji.docuconverter.logic.AbstractDocuConverter 15 | */ 16 | public interface DocuConverter { 17 | 18 | /** 19 | * This will start the conversion of the document 20 | * 21 | * @param outputStream The stream to which the converted document will be hold on 22 | * @throws Exception if any error occur in the document conversion 23 | */ 24 | void convertIn(OutputStream outputStream) throws Exception; 25 | 26 | /** 27 | * This will set the document size 28 | * 29 | * @param pageSize document size 30 | * @apiNote This is only effective in some conversions 31 | */ 32 | void setPageSize(PageSize pageSize); 33 | 34 | /** 35 | * This will set the convert to print processing info 36 | * 37 | * @param verbose true to enable verbose 38 | */ 39 | void setVerbose(boolean verbose); 40 | 41 | /** 42 | * This will initiate the implementers of the {@link DocuConverter} to perform the related conversion 43 | * 44 | * @param inputStream The stream in which the source document exists 45 | * @param from Type of source document 46 | * @param to Type of designating document 47 | * @return The type implementor of the related conversion method 48 | * @throws UnsupportedTypeException if no implementation found for the documents 49 | * @see DocuConverterFactory#getConverter(InputStream, DocumentType, ConvertToType) 50 | */ 51 | static DocuConverter getConverter(InputStream inputStream, DocumentType from, ConvertToType to) 52 | throws UnsupportedTypeException { 53 | return DocuConverterFactory.getConverter(inputStream, from, to); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/logic/TextToPdf.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.logic; 2 | 3 | import com.chiragji.docuconverter.enums.FontStyle; 4 | import com.itextpdf.text.Document; 5 | import com.itextpdf.text.Element; 6 | import com.itextpdf.text.Font; 7 | import com.itextpdf.text.Paragraph; 8 | import com.itextpdf.text.pdf.PdfWriter; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.InputStream; 12 | import java.io.InputStreamReader; 13 | import java.io.OutputStream; 14 | import java.util.Objects; 15 | 16 | /** 17 | * @author Chirag Gupta (chirag-ji) 18 | */ 19 | public final class TextToPdf extends AbstractDocuConverter { 20 | private FontStyle fontStyle = FontStyle.NORMAL; 21 | private int fontSize = 11; 22 | 23 | TextToPdf(InputStream inputStream) { 24 | super(inputStream); 25 | } 26 | 27 | public void setFontSize(int fontSize) { 28 | if (fontSize <= 0) 29 | throw new IllegalArgumentException("Invalid font size: " + fontSize); 30 | this.fontSize = fontSize; 31 | } 32 | 33 | public void setFontStyle(FontStyle fontStyle) { 34 | this.fontStyle = Objects.requireNonNull(fontStyle, "Font style is undefined"); 35 | } 36 | 37 | @Override 38 | public void convertIn(OutputStream outputStream) throws Exception { 39 | setOutputStream(outputStream); 40 | onStart(); 41 | Document document = new Document(pageSize.getPageDimension()); 42 | PdfWriter.getInstance(document, this.outputStream).setPdfVersion(PdfWriter.PDF_VERSION_1_7); 43 | document.open(); 44 | onProcessing(); 45 | Font font = new Font(); 46 | font.setStyle(this.fontStyle.getStyle()); 47 | font.setSize(this.fontSize); 48 | document.add(new Paragraph("\n")); 49 | try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(this.inputStream))) { 50 | String line; 51 | while ((line = bufferedReader.readLine()) != null) { 52 | Paragraph para = new Paragraph(line + "\n", font); 53 | para.setAlignment(Element.ALIGN_JUSTIFIED); 54 | document.add(para); 55 | } 56 | } 57 | document.close(); 58 | onCompleted(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/logic/AbstractDocuConverter.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.logic; 2 | 3 | import com.chiragji.docuconverter.api.DocuConverter; 4 | import com.chiragji.docuconverter.enums.PageSize; 5 | 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.util.Date; 9 | import java.util.Objects; 10 | import java.util.logging.Level; 11 | 12 | /** 13 | * This class contains the common methods used by the implementors 14 | * 15 | * @author Chirag Gupta (chirag-ji) 16 | */ 17 | public abstract class AbstractDocuConverter implements DocuConverter, AutoCloseable { 18 | 19 | protected final InputStream inputStream; 20 | protected OutputStream outputStream; 21 | private boolean verbose; 22 | private boolean autoClose; 23 | protected PageSize pageSize = PageSize.A4; 24 | 25 | protected AbstractDocuConverter(InputStream inputStream) { 26 | Objects.requireNonNull(inputStream, "InputStream is null"); 27 | this.inputStream = inputStream; 28 | } 29 | 30 | public void setOutputStream(OutputStream outputStream) { 31 | this.outputStream = Objects.requireNonNull(outputStream, "OutputStream is null"); 32 | } 33 | 34 | @Override 35 | public void setVerbose(boolean verbose) { 36 | this.verbose = verbose; 37 | } 38 | 39 | public boolean isVerbose() { 40 | return verbose; 41 | } 42 | 43 | protected void onStart() { 44 | log("Loading File", Level.INFO); 45 | } 46 | 47 | protected void onProcessing() { 48 | log("Processing file", Level.INFO); 49 | } 50 | 51 | protected void onCompleted() { 52 | log("File processed", Level.INFO); 53 | if (this.autoClose) { 54 | try { 55 | close(); 56 | } catch (Exception e) { 57 | //ignore, no exception might occur here 58 | } 59 | } 60 | } 61 | 62 | protected void log(String message, Level level) { 63 | if (isVerbose()) 64 | System.out.println(level + ": " + new Date() + ": " + message); 65 | } 66 | 67 | public void setAutoCloseResourceOnComplete(boolean autoClose) { 68 | this.autoClose = autoClose; 69 | } 70 | 71 | public boolean isAutoCloseResourceOnComplete() { 72 | return autoClose; 73 | } 74 | 75 | @Override 76 | public void setPageSize(PageSize pageSize) { 77 | this.pageSize = Objects.requireNonNull(pageSize, "PageSize is undefined"); 78 | } 79 | 80 | @Override 81 | public void close() throws Exception { 82 | this.inputStream.close(); 83 | this.outputStream.flush(); 84 | this.outputStream.close(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/test/java/com/chiragji/docuconverter/api/DocuConverterTest.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.api; 2 | 3 | import com.chiragji.docuconverter.AbstractTest; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.extension.ExtendWith; 6 | import org.junit.platform.commons.annotation.Testable; 7 | import org.mockito.junit.jupiter.MockitoExtension; 8 | 9 | import java.io.File; 10 | import java.nio.file.Files; 11 | 12 | @Testable 13 | @ExtendWith(MockitoExtension.class) 14 | class DocuConverterTest extends AbstractTest { 15 | 16 | @Test 17 | void txtToPdf() throws Exception { 18 | File inFile = getTestInFile("test.txt"); 19 | File outFile = getTestOutFile("testTxt.pdf"); 20 | DocuConverter docuConverter = DocuConverter.getConverter(Files.newInputStream(inFile.toPath()), 21 | DocumentType.TXT, ConvertToType.PDF); 22 | docuConverter.setVerbose(true); //optional 23 | docuConverter.convertIn(Files.newOutputStream(outFile.toPath())); 24 | assertFileExists(outFile); 25 | } 26 | 27 | // @Test 28 | void docXToPdf() throws Exception { 29 | File inFile = getTestInFile("test.docx"); 30 | File outFile = getTestOutFile("testDocx.pdf"); 31 | DocuConverter docuConverter = DocuConverter.getConverter(Files.newInputStream(inFile.toPath()), 32 | DocumentType.DOCX, ConvertToType.PDF); 33 | docuConverter.setVerbose(true); //optional 34 | docuConverter.convertIn(Files.newOutputStream(outFile.toPath())); 35 | assertFileExists(outFile); 36 | } 37 | 38 | @Test 39 | void pptToPdf() throws Exception { 40 | File inFile = getTestInFile("test.ppt"); 41 | File outFile = getTestOutFile("testPpt.pdf"); 42 | DocuConverter docuConverter = DocuConverter.getConverter(Files.newInputStream(inFile.toPath()), 43 | DocumentType.PPT, ConvertToType.PDF); 44 | docuConverter.setVerbose(true); //optional 45 | docuConverter.convertIn(Files.newOutputStream(outFile.toPath())); 46 | assertFileExists(outFile); 47 | } 48 | 49 | @Test 50 | void pptXToPdf() throws Exception { 51 | File inFile = getTestInFile("test.pptx"); 52 | File outFile = getTestOutFile("testPptx.pdf"); 53 | DocuConverter docuConverter = DocuConverter.getConverter(Files.newInputStream(inFile.toPath()), 54 | DocumentType.PPTX, ConvertToType.PDF); 55 | docuConverter.setVerbose(true); //optional 56 | docuConverter.convertIn(Files.newOutputStream(outFile.toPath())); 57 | assertFileExists(outFile); 58 | } 59 | 60 | @Test 61 | void csvToXml() throws Exception { 62 | File inFile = getTestInFile("test.csv"); 63 | File outFile = getTestOutFile("testCsv.xml"); 64 | DocuConverter docuConverter = DocuConverter.getConverter(Files.newInputStream(inFile.toPath()), 65 | DocumentType.CSV, ConvertToType.XML); 66 | docuConverter.setVerbose(true); //optional 67 | docuConverter.convertIn(Files.newOutputStream(outFile.toPath())); 68 | assertFileExists(outFile); 69 | } 70 | } -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/enums/PageSize.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.enums; 2 | 3 | import com.itextpdf.text.Rectangle; 4 | 5 | /** 6 | * This enum defines major available sizes for document 7 | * 8 | * @author Chirag Gupta (chirag-ji) 9 | */ 10 | public enum PageSize { 11 | 12 | LETTER(com.itextpdf.text.PageSize.LETTER), 13 | NOTE(com.itextpdf.text.PageSize.NOTE), 14 | LEGAL(com.itextpdf.text.PageSize.LEGAL), 15 | TABLOID(com.itextpdf.text.PageSize.TABLOID), 16 | EXECUTIVE(com.itextpdf.text.PageSize.EXECUTIVE), 17 | POSTCARD(com.itextpdf.text.PageSize.POSTCARD), 18 | A0(com.itextpdf.text.PageSize.A0), 19 | A1(com.itextpdf.text.PageSize.A1), 20 | A2(com.itextpdf.text.PageSize.A2), 21 | A3(com.itextpdf.text.PageSize.A3), 22 | A4(com.itextpdf.text.PageSize.A4), 23 | A5(com.itextpdf.text.PageSize.A5), 24 | A6(com.itextpdf.text.PageSize.A6), 25 | A7(com.itextpdf.text.PageSize.A7), 26 | A8(com.itextpdf.text.PageSize.A8), 27 | A9(com.itextpdf.text.PageSize.A9), 28 | A10(com.itextpdf.text.PageSize.A10), 29 | B0(com.itextpdf.text.PageSize.B0), 30 | B1(com.itextpdf.text.PageSize.B1), 31 | B2(com.itextpdf.text.PageSize.B2), 32 | B3(com.itextpdf.text.PageSize.B3), 33 | B4(com.itextpdf.text.PageSize.B4), 34 | B5(com.itextpdf.text.PageSize.B5), 35 | B6(com.itextpdf.text.PageSize.B6), 36 | B7(com.itextpdf.text.PageSize.B7), 37 | B8(com.itextpdf.text.PageSize.B8), 38 | B9(com.itextpdf.text.PageSize.B9), 39 | B10(com.itextpdf.text.PageSize.B10), 40 | ARCH_E(com.itextpdf.text.PageSize.ARCH_E), 41 | ARCH_D(com.itextpdf.text.PageSize.ARCH_D), 42 | ARCH_C(com.itextpdf.text.PageSize.ARCH_C), 43 | ARCH_B(com.itextpdf.text.PageSize.ARCH_B), 44 | ARCH_A(com.itextpdf.text.PageSize.ARCH_A), 45 | FLSA(com.itextpdf.text.PageSize.FLSA), 46 | FLSE(com.itextpdf.text.PageSize.FLSE), 47 | HALFLETTER(com.itextpdf.text.PageSize.HALFLETTER), 48 | _11X17(com.itextpdf.text.PageSize._11X17), 49 | ID_1(com.itextpdf.text.PageSize.ID_1), 50 | ID_2(com.itextpdf.text.PageSize.ID_2), 51 | ID_3(com.itextpdf.text.PageSize.ID_3), 52 | LEDGER(com.itextpdf.text.PageSize.LEDGER), 53 | CROWN_QUARTO(com.itextpdf.text.PageSize.CROWN_QUARTO), 54 | LARGE_CROWN_QUARTO(com.itextpdf.text.PageSize.LARGE_CROWN_QUARTO), 55 | DEMY_QUARTO(com.itextpdf.text.PageSize.DEMY_QUARTO), 56 | ROYAL_QUARTO(com.itextpdf.text.PageSize.ROYAL_QUARTO), 57 | CROWN_OCTAVO(com.itextpdf.text.PageSize.CROWN_OCTAVO), 58 | LARGE_CROWN_OCTAVO(com.itextpdf.text.PageSize.LARGE_CROWN_OCTAVO), 59 | DEMY_OCTAVO(com.itextpdf.text.PageSize.DEMY_OCTAVO), 60 | ROYAL_OCTAVO(com.itextpdf.text.PageSize.ROYAL_OCTAVO), 61 | SMALL_PAPERBACK(com.itextpdf.text.PageSize.SMALL_PAPERBACK), 62 | PENGUIN_SMALL_PAPERBACK(com.itextpdf.text.PageSize.PENGUIN_SMALL_PAPERBACK), 63 | PENGUIN_LARGE_PAPERBACK(com.itextpdf.text.PageSize.PENGUIN_LARGE_PAPERBACK), 64 | A4_LANDSCAPE(com.itextpdf.text.PageSize.A4_LANDSCAPE); 65 | 66 | private final Rectangle pageDimension; 67 | 68 | PageSize(Rectangle dimension) { 69 | this.pageDimension = dimension; 70 | } 71 | 72 | public Rectangle getPageDimension() { 73 | return pageDimension; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DocuConverter 2 | [![](https://jitpack.io/v/chirag-ji/DocuConverter.svg)](https://jitpack.io/#chirag-ji/DocuConverter) 3 | 4 | 5 | A standalone Java Library and API to convert the Microsoft Office Documents to other format very quickly. 6 | 7 | ***Note**: This API is build on JDK 1.8 and hence it requires JRE 8 or above to run.* 8 | 9 | ## Features 10 | - Light Weight process 11 | - Quick Conversion 12 | - Less fail rates 13 | 14 | 15 | ## Why I wrote this API 16 | I faced many problem in converting files from one format to another format from, say, *DOCX* to *PDF* and to do that simple task, any one have to look to many sources to get the working code, otherwise have to use other properity software or heavy softwares to convert them. For many developers, this was the headache to code and test and so on... so to solve this problem and keeping in mind the headache of this searching, I created this API which is very handy to use, and can be also used in your Applications too 17 | 18 | 19 | ## API Uses in your program 20 | 21 | ```java 22 | File inFile = new File("test/test.docx"); 23 | File outFile = new File("test/testDocX.pdf"); 24 | DocuConverter docuConverter = DocuConverter.getConverter(new FileInputStream(inFile), 25 | DocumentType.DOCX, ConvertToType.PDF); 26 | docuConverter.setVerbose(true); //optional, only if you want the log output 27 | docuConverter.convertIn(new FileOutputStream(outFile)); 28 | ``` 29 | 30 | Any **OutputStream** and **InputStream** can be used here, 31 | Like to get the code in ***ByteArrayOutputStream***, we can write 32 | 33 | ```java 34 | File inFile = new File("test/test.docx"); 35 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 36 | DocuConverter docuConverter = DocuConverter.getConverter(new FileInputStream(inFile), 37 | DocumentType.DOCX, ConvertToType.PDF); 38 | docuConverter.setVerbose(true); //optional, only if you want the log output 39 | docuConverter.convertIn(byteArrayOutputStream); 40 | System.out.println(byteArrayOutputStream); 41 | ``` 42 | 43 | ### Including API in your project 44 | See [Adding Dependency to project](https://jitpack.io/#chirag-ji/DocuConverter) 45 | 46 | ## Use from System Console 47 | > Console Parameters 48 | 49 | -help (-h) : Shows this message 50 | -input (-i, -in) : Specifies input file path 51 | -output (-o, -out) : Specifies output file path 52 | -verbose (-v) : To see intermediate processing messages. 53 | -version (-ver) : View current Library Version 54 | 55 | > Console Usage 56 | 57 | java -jar .\DocuConverter.jar -in < path > -out < path > -v 58 | java -jar .\DocuConverter.jar -in .\test.docx -out .\test.pdf -v 59 | java -jar .\DocuConverter.jar -in .\test.pptx -out .\test.pdf 60 | 61 | 62 | ### Included Libraries 63 | - Apache POI 64 | - Args4j 65 | - Apache Commons Collection 66 | - DocX4J 67 | - iTextPDF 68 | - And others, please see [lib folder](https://github.com/chirag-ji/DocuConverter/tree/master/lib) 69 | 70 | ## Current Supported Conversion Types 71 | - *DOCX* to *PDF* 72 | - *PPTX* to *PDF* 73 | - *TXT* to *PDF* 74 | - *PPT* to *PDF* 75 | - *CSV* to *XML* 76 | 77 | ***Copyright © 2019 Chirag Gupta (https://github.com/chirag-ji) under MIT Licence*** 78 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/logic/PptXToPdf.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.logic; 2 | 3 | import com.itextpdf.text.Document; 4 | import com.itextpdf.text.Image; 5 | import com.itextpdf.text.Rectangle; 6 | import com.itextpdf.text.pdf.PdfWriter; 7 | import org.apache.poi.xslf.usermodel.XMLSlideShow; 8 | import org.apache.poi.xslf.usermodel.XSLFSlide; 9 | 10 | import java.awt.*; 11 | import java.awt.geom.AffineTransform; 12 | import java.awt.geom.Rectangle2D; 13 | import java.awt.image.BufferedImage; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.io.OutputStream; 17 | import java.util.List; 18 | 19 | 20 | /** 21 | * @author Chirag Gupta (chirag-ji) 22 | */ 23 | public final class PptXToPdf extends AbstractDocuConverter { 24 | private List slides; 25 | private Dimension size; 26 | private double zoomLevel = 1; 27 | 28 | public void setZoomLevel(double zoomLevel) { 29 | if (zoomLevel <= 0) 30 | throw new IllegalArgumentException("Invalid zoo level: " + zoomLevel + 31 | ", A non zero positive number is only acceptable"); 32 | this.zoomLevel = zoomLevel; 33 | } 34 | 35 | PptXToPdf(InputStream inputStream) { 36 | super(inputStream); 37 | } 38 | 39 | @Override 40 | public void convertIn(OutputStream outputStream) throws Exception { 41 | setOutputStream(outputStream); 42 | onStart(); 43 | init(); 44 | if (slides == null || slides.isEmpty()) 45 | throw new IllegalArgumentException("Invalid file to convert to pdf from pptx. No slides found"); 46 | onProcessing(); 47 | AffineTransform affineTransform = new AffineTransform(); 48 | affineTransform.setToScale(zoomLevel, zoomLevel); 49 | Document document = new Document(this.pageSize.getPageDimension()); 50 | PdfWriter pdfWriter = PdfWriter.getInstance(document, outputStream); 51 | document.open(); 52 | int width = (int) Math.ceil(this.size.width * zoomLevel); 53 | int height = (int) Math.ceil(this.size.height * zoomLevel); 54 | for (XSLFSlide slide : slides) { 55 | BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 56 | Graphics2D g = image.createGraphics(); 57 | g.setTransform(affineTransform); 58 | g.setPaint(getBackgroundColor(slide)); 59 | g.fill(new Rectangle2D.Float(0, 0, this.size.width, this.size.height)); 60 | try { 61 | slide.draw(g); 62 | } catch (Exception e) { 63 | // ignore 64 | } 65 | Image img = Image.getInstance(image, null); 66 | document.setPageSize(new Rectangle(img.getScaledWidth(), img.getScaledHeight())); 67 | document.newPage(); 68 | img.setAbsolutePosition(0, 0); 69 | document.add(img); 70 | } 71 | document.close(); 72 | pdfWriter.close(); 73 | onCompleted(); 74 | } 75 | 76 | private void init() throws IOException { 77 | XMLSlideShow slideShow = new XMLSlideShow(this.inputStream); 78 | this.size = slideShow.getPageSize(); 79 | this.slides = slideShow.getSlides(); 80 | } 81 | 82 | private Color getBackgroundColor(XSLFSlide xslfSlide) { 83 | return xslfSlide.getBackground().getFillColor(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/logic/PptToPdf.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.logic; 2 | 3 | import com.itextpdf.text.Document; 4 | import com.itextpdf.text.Rectangle; 5 | import com.itextpdf.text.pdf.PdfWriter; 6 | import org.apache.poi.hslf.usermodel.HSLFSlide; 7 | import org.apache.poi.hslf.usermodel.HSLFSlideShow; 8 | 9 | import java.awt.*; 10 | import java.awt.geom.AffineTransform; 11 | import java.awt.geom.Rectangle2D; 12 | import java.awt.image.BufferedImage; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.io.OutputStream; 16 | import java.util.List; 17 | 18 | /** 19 | * @author Chirag Gupta (chirag-ji) 20 | */ 21 | public final class PptToPdf extends AbstractDocuConverter { 22 | private List slides; 23 | private Dimension size; 24 | private double zoomLevel = 2; 25 | 26 | public void setZoomLevel(double zoomLevel) { 27 | if (zoomLevel <= 0) 28 | throw new IllegalArgumentException("Invalid zoo level: " + zoomLevel + 29 | ", A non zero positive number is only acceptable"); 30 | this.zoomLevel = zoomLevel; 31 | } 32 | 33 | PptToPdf(InputStream inputStream) { 34 | super(inputStream); 35 | } 36 | 37 | @Override 38 | public void convertIn(OutputStream outputStream) throws Exception { 39 | setOutputStream(outputStream); 40 | onStart(); 41 | init(); 42 | ensureSlides(); 43 | onProcessing(); 44 | AffineTransform affineTransform = new AffineTransform(); 45 | affineTransform.setToScale(zoomLevel, zoomLevel); 46 | Document document = new Document(this.pageSize.getPageDimension()); 47 | PdfWriter pdfWriter = PdfWriter.getInstance(document, outputStream); 48 | document.open(); 49 | int width = (int) Math.ceil(this.size.width * zoomLevel); 50 | int height = (int) Math.ceil(this.size.height * zoomLevel); 51 | for (HSLFSlide slide : slides) { 52 | BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 53 | Graphics2D g = image.createGraphics(); 54 | g.setTransform(affineTransform); 55 | g.setPaint(getBackgroundColor(slide)); 56 | g.fill(new Rectangle2D.Float(0, 0, this.size.width, this.size.height)); 57 | try { 58 | slide.draw(g); 59 | } catch (Exception e) { 60 | // ignore 61 | } 62 | com.itextpdf.text.Image img = com.itextpdf.text.Image.getInstance(image, null); 63 | document.setPageSize(new Rectangle(img.getScaledWidth(), img.getScaledHeight())); 64 | document.newPage(); 65 | img.setAbsolutePosition(0, 0); 66 | document.add(img); 67 | } 68 | document.close(); 69 | pdfWriter.close(); 70 | onCompleted(); 71 | } 72 | 73 | private void ensureSlides() { 74 | if (slides == null || slides.isEmpty()) 75 | throw new IllegalArgumentException("Invalid file to convert to pdf from pptx. No slides found"); 76 | } 77 | 78 | private void init() throws IOException { 79 | HSLFSlideShow slideShow = new HSLFSlideShow(this.inputStream); 80 | this.size = slideShow.getPageSize(); 81 | slides = slideShow.getSlides(); 82 | } 83 | 84 | private Color getBackgroundColor(HSLFSlide hslfSlide) { 85 | return hslfSlide.getBackground().getFill().getForegroundColor(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/test/resources/in/test.txt: -------------------------------------------------------------------------------- 1 | Quod equidem non reprehendo; 2 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quibus natura iure responderit non esse verum aliunde finem beate vivendi, a se principia rei gerendae peti; Quae enim adhuc protulisti, popularia sunt, ego autem a te elegantiora desidero. Duo Reges: constructio interrete. Tum Lucius: Mihi vero ista valde probata sunt, quod item fratri puto. Bestiarum vero nullum iudicium puto. Nihil enim iam habes, quod ad corpus referas; Deinde prima illa, quae in congressu solemus: Quid tu, inquit, huc? Et homini, qui ceteris animantibus plurimum praestat, praecipue a natura nihil datum esse dicemus? 3 | 4 | Iam id ipsum absurdum, maximum malum neglegi. Quod ea non occurrentia fingunt, vincunt Aristonem; Atqui perspicuum est hominem e corpore animoque constare, cum primae sint animi partes, secundae corporis. Fieri, inquam, Triari, nullo pacto potest, ut non dicas, quid non probes eius, a quo dissentias. Equidem e Cn. An dubium est, quin virtus ita maximam partem optineat in rebus humanis, ut reliquas obruat? 5 | 6 | Quis istum dolorem timet? 7 | Summus dolor plures dies manere non potest? Dicet pro me ipsa virtus nec dubitabit isti vestro beato M. Tubulum fuisse, qua illum, cuius is condemnatus est rogatione, P. Quod si ita sit, cur opera philosophiae sit danda nescio. 8 | 9 | Ex eorum enim scriptis et institutis cum omnis doctrina liberalis, omnis historia. 10 | Quod si ita est, sequitur id ipsum, quod te velle video, omnes semper beatos esse sapientes. Cum enim fertur quasi torrens oratio, quamvis multa cuiusque modi rapiat, nihil tamen teneas, nihil apprehendas, nusquam orationem rapidam coerceas. Ita redarguitur ipse a sese, convincunturque scripta eius probitate ipsius ac moribus. At quanta conantur! Mundum hunc omnem oppidum esse nostrum! Incendi igitur eos, qui audiunt, vides. Vide, ne magis, inquam, tuum fuerit, cum re idem tibi, quod mihi, videretur, non nova te rebus nomina inponere. Qui-vere falsone, quaerere mittimus-dicitur oculis se privasse; Si ista mala sunt, in quae potest incidere sapiens, sapientem esse non esse ad beate vivendum satis. At vero si ad vitem sensus accesserit, ut appetitum quendam habeat et per se ipsa moveatur, quid facturam putas? 11 | 12 | Quem si tenueris, non modo meum Ciceronem, sed etiam me ipsum abducas licebit. 13 | Stulti autem malorum memoria torquentur, sapientes bona praeterita grata recordatione renovata delectant. 14 | Esse enim quam vellet iniquus iustus poterat inpune. 15 | Quae autem natura suae primae institutionis oblita est? 16 | Verum tamen cum de rebus grandioribus dicas, ipsae res verba rapiunt; 17 | Hoc est non modo cor non habere, sed ne palatum quidem. 18 | Voluptatem cum summum bonum diceret, primum in eo ipso parum vidit, deinde hoc quoque alienum; Sed tu istuc dixti bene Latine, parum plane. Nam haec ipsa mihi erunt in promptu, quae modo audivi, nec ante aggrediar, quam te ab istis, quos dicis, instructum videro. Fatebuntur Stoici haec omnia dicta esse praeclare, neque eam causam Zenoni desciscendi fuisse. Non autem hoc: igitur ne illud quidem. Ratio quidem vestra sic cogit. Cum audissem Antiochum, Brute, ut solebam, cum M. An quod ita callida est, ut optime possit architectari voluptates? 19 | 20 | Idemne, quod iucunde? 21 | Haec mihi videtur delicatior, ut ita dicam, molliorque ratio, quam virtutis vis gravitasque postulat. Sed quoniam et advesperascit et mihi ad villam revertendum est, nunc quidem hactenus; Cuius ad naturam apta ratio vera illa et summa lex a philosophis dicitur. Neque solum ea communia, verum etiam paria esse dixerunt. Sed nunc, quod agimus; A mene tu? -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/logic/CsvToXml.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter.logic; 2 | 3 | import com.chiragji.docuconverter.utils.TextUtils; 4 | import org.w3c.dom.Document; 5 | import org.w3c.dom.Element; 6 | 7 | import javax.xml.parsers.DocumentBuilderFactory; 8 | import javax.xml.parsers.ParserConfigurationException; 9 | import javax.xml.transform.OutputKeys; 10 | import javax.xml.transform.Transformer; 11 | import javax.xml.transform.TransformerConfigurationException; 12 | import javax.xml.transform.TransformerFactory; 13 | import javax.xml.transform.dom.DOMSource; 14 | import javax.xml.transform.stream.StreamResult; 15 | import java.io.*; 16 | 17 | /** 18 | * @author Chirag Gupta (chirag-ji) 19 | */ 20 | public class CsvToXml extends AbstractDocuConverter { 21 | protected CsvToXml(InputStream inputStream) { 22 | super(inputStream); 23 | } 24 | 25 | @Override 26 | public void convertIn(OutputStream outputStream) throws Exception { 27 | Document document = getNewDocument(); 28 | Element rootElement = document.createElement("data"); 29 | document.appendChild(rootElement); 30 | 31 | parseData(document, rootElement); 32 | 33 | getTransformer().transform(new DOMSource(document), new StreamResult(outputStream)); 34 | } 35 | 36 | private void parseData(final Document document, final Element rootElement) throws IOException { 37 | boolean headerParsed = false; 38 | String[] headers = null; 39 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { 40 | String line; 41 | while ((line = reader.readLine()) != null) { 42 | if (TextUtils.isEmpty(line)) { 43 | continue; 44 | } 45 | if (!headerParsed) { 46 | headers = getData(line); 47 | headerParsed = true; 48 | } else { 49 | Element rowElement = document.createElement("row"); 50 | rootElement.appendChild(rowElement); 51 | String[] row = getData(line); 52 | for (int i = 0; i < headers.length; i++) { 53 | Element dataElem = document.createElement(headers[i]); 54 | String data = i >= row.length ? "" : row[i]; 55 | dataElem.appendChild(document.createTextNode(data)); 56 | rowElement.appendChild(dataElem); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | private String[] getData(String line) { 64 | String[] parts = line.split(","); 65 | return enhanceHeaders(parts); 66 | } 67 | 68 | private String[] enhanceHeaders(String[] heads) { 69 | String[] res = new String[heads.length]; 70 | for (int i = 0; i < res.length; i++) { 71 | String p = heads[i]; 72 | if (p.startsWith("\"") || p.contains(" ")) { 73 | res[i] = p.replace("\"", "").replace(" ", ""); 74 | } else { 75 | res[i] = p; 76 | } 77 | } 78 | return res; 79 | } 80 | 81 | private Document getNewDocument() throws ParserConfigurationException { 82 | return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 83 | } 84 | 85 | private Transformer getTransformer() throws TransformerConfigurationException { 86 | Transformer transformer = TransformerFactory.newInstance().newTransformer(); 87 | transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 88 | transformer.setOutputProperty(OutputKeys.METHOD, "xml"); 89 | transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); 90 | return transformer; 91 | } 92 | } -------------------------------------------------------------------------------- /src/main/java/com/chiragji/docuconverter/Bootstrap.java: -------------------------------------------------------------------------------- 1 | package com.chiragji.docuconverter; 2 | 3 | import com.chiragji.docuconverter.api.ConvertToType; 4 | import com.chiragji.docuconverter.api.DocuConverter; 5 | import com.chiragji.docuconverter.api.DocumentType; 6 | import com.chiragji.docuconverter.console.ConsoleValues; 7 | import com.chiragji.docuconverter.exceptions.DocuConverterException; 8 | import org.kohsuke.args4j.CmdLineParser; 9 | 10 | import java.io.File; 11 | import java.nio.file.Files; 12 | 13 | /** 14 | * This is the entry point for the application that interprets the console arguments 15 | * 16 | * @author Chirag Gupta (chirag-ji) 17 | */ 18 | public class Bootstrap { 19 | public static void main(String... args) throws Exception { 20 | processConsoleArgs(args); 21 | } 22 | 23 | private static void processConsoleArgs(String... cmdArgs) throws Exception { 24 | ConsoleValues consoleValues = new ConsoleValues(); 25 | CmdLineParser cmdLineParser = new CmdLineParser(consoleValues); 26 | if (cmdArgs.length == 0) { 27 | printVersion(); 28 | cmdLineParser.printUsage(System.out); 29 | System.exit(0); 30 | } 31 | cmdLineParser.parseArgument(cmdArgs); 32 | if (consoleValues.isShowVersion()) { 33 | printVersion(); 34 | System.exit(0); 35 | } else if (consoleValues.isShowHelp()) { 36 | printVersion(); 37 | cmdLineParser.printUsage(System.out); 38 | System.exit(0); 39 | } 40 | long start = System.currentTimeMillis(); 41 | String inputFile = consoleValues.getInputPath(); 42 | String outputFile = consoleValues.getOutPath(); 43 | if (inputFile == null || inputFile.trim().isEmpty()) 44 | throw new IllegalArgumentException("Input file path not defined"); 45 | else if (outputFile == null || outputFile.trim().isEmpty()) 46 | throw new IllegalArgumentException("Output file path not defined"); 47 | File inFile = new File(consoleValues.getInputPath()); 48 | File outFile = new File(consoleValues.getOutPath()); 49 | DocumentType inType = getDocumentType(inFile); 50 | ConvertToType toType = getConvertToType(outFile); 51 | DocuConverter docuConverter = DocuConverter.getConverter(Files.newInputStream(inFile.toPath()), inType, toType); 52 | docuConverter.setVerbose(consoleValues.isVerbose()); 53 | docuConverter.convertIn(Files.newOutputStream(outFile.toPath())); 54 | long total = System.currentTimeMillis() - start; 55 | System.out.println("File conversion succeed in " + total + " ms"); 56 | } 57 | 58 | private static DocumentType getDocumentType(File inFile) throws DocuConverterException { 59 | String extension = getExtension(inFile); 60 | for (DocumentType documentType : DocumentType.values()) { 61 | if (documentType.name().equalsIgnoreCase(extension)) 62 | return documentType; 63 | } 64 | throw new DocuConverterException("Unsupported input type: " + extension); 65 | } 66 | 67 | private static ConvertToType getConvertToType(File outFile) throws DocuConverterException { 68 | String extension = getExtension(outFile); 69 | for (ConvertToType convertToType : ConvertToType.values()) { 70 | if (convertToType.name().equalsIgnoreCase(extension)) 71 | return convertToType; 72 | } 73 | throw new DocuConverterException("Unsupported input type: " + extension); 74 | } 75 | 76 | private static String getExtension(File file) { 77 | if (file.isDirectory()) 78 | throw new IllegalArgumentException("File was expected but directory supplied"); 79 | String fileName = file.getName(); 80 | int idx = fileName.lastIndexOf('.'); 81 | return fileName.substring(idx + 1); 82 | } 83 | 84 | private static void printVersion() { 85 | System.out.println(BuildConfig.APP_NAME + " [Version " + BuildConfig.BUILD + "]\nCopyright (c) " + 86 | BuildConfig.COPYRIGHT_YEAR + " Chirag Gupta (https://github.com/chirag-ji) under MIT Licence\n"); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /src/test/resources/in/test.csv: -------------------------------------------------------------------------------- 1 | Number,Test Length,"Blank Quotes" 2 | 1, 30 3 | 2, 29 4 | 3, 31 5 | 4, 16 6 | 5, 24 7 | 6, 29 8 | 7, 28 9 | 8, 117 10 | 9, 42 11 | 10, 23 12 | 11, 40 13 | 12, 15 14 | 13, 18 15 | 14, 51 16 | 15, 15 17 | 16, 19 18 | 17, 30 19 | 18, 25 20 | 19, 17 21 | 20, 55 22 | 21, 20 23 | 22, 12 24 | 23, 39 25 | 24, 25 26 | 25, 56 27 | 26, 61 28 | 27, 77 29 | 28, 34 30 | 29, 14 31 | 30, 8 32 | 31, 31 33 | 32, 34 34 | 33, 22 35 | 34, 12 36 | 35, 52 37 | 36, 50 38 | 37, 24 39 | 38, 20 40 | 39, 91 41 | 40, 33 42 | 41, 27 43 | 42, 25 44 | 43, 83 45 | 44, 12 46 | 45, 21 47 | 46, 38 48 | 47, 20 49 | 48, 24 50 | 49, 37 51 | 50, 18 52 | 51, 56 53 | 52, 20 54 | 53, 47 55 | 54, 51 56 | 55, 22 57 | 56, 46 58 | 57, 24 59 | 58, 35 60 | 59, 28 61 | 60, 12 62 | 61, 28 63 | 62, 43 64 | 63, 50 65 | 64, 37 66 | 65, 127 67 | 66, 11 68 | 67, 12 69 | 68, 22 70 | 69, 25 71 | 70, 57 72 | 71, 53 73 | 72, 38 74 | 73, 33 75 | 74, 16 76 | 75, 35 77 | 76, 29 78 | 77, 23 79 | 78, 21 80 | 79, 11 81 | 80, 31 82 | 81, 12 83 | 82, 37 84 | 83, 40 85 | 84, 29 86 | 85, 14 87 | 86, 15 88 | 87, 38 89 | 88, 74 90 | 89, 19 91 | 90, 121 92 | 91, 52 93 | 92, 25 94 | 93, 14 95 | 94, 12 96 | 95, 31 97 | 96, 25 98 | 97, 16 99 | 98, 19 100 | 99, 54 101 | 100, 24 102 | 101, 62 103 | 102, 27 104 | 103, 21 105 | 104, 30 106 | 105, 63 107 | 106, 14 108 | 107, 27 109 | 108, 46 110 | 109, 8 111 | 110, 19 112 | 111, 81 113 | 112, 136 114 | 113, 60 115 | 114, 44 116 | 115, 44 117 | 116, 115 118 | 117, 28 119 | 118, 15 120 | 119, 26 121 | 120, 31 122 | 121, 46 123 | 122, 29 124 | 123, 22 125 | 124, 25 126 | 125, 37 127 | 126, 78 128 | 127, 11 129 | 128, 17 130 | 129, 20 131 | 130, 38 132 | 131, 30 133 | 132, 51 134 | 133, 42 135 | 134, 64 136 | 135, 37 137 | 136, 32 138 | 137, 32 139 | 138, 35 140 | 139, 34 141 | 140, 36 142 | 141, 55 143 | 142, 35 144 | 143, 13 145 | 144, 109 146 | 145, 39 147 | 146, 39 148 | 147, 69 149 | 148, 28 150 | 149, 13 151 | 150, 16 152 | 151, 23 153 | 152, 14 154 | 153, 116 155 | 154, 36 156 | 155, 41 157 | 156, 40 158 | 157, 31 159 | 158, 39 160 | 159, 21 161 | 160, 34 162 | 161, 11 163 | 162, 46 164 | 163, 27 165 | 164, 10 166 | 165, 47 167 | 166, 12 168 | 167, 42 169 | 168, 34 170 | 169, 16 171 | 170, 19 172 | 171, 100 173 | 172, 34 174 | 173, 20 175 | 174, 23 176 | 175, 29 177 | 176, 32 178 | 177, 81 179 | 178, 15 180 | 179, 50 181 | 180, 67 182 | 181, 76 183 | 182, 30 184 | 183, 16 185 | 184, 20 186 | 185, 37 187 | 186, 23 188 | 187, 18 189 | 188, 47 190 | 189, 13 191 | 190, 24 192 | 191, 8 193 | 192, 16 194 | 193, 24 195 | 194, 26 196 | 195, 35 197 | 196, 14 198 | 197, 11 199 | 198, 43 200 | 199, 48 201 | 200, 19 202 | 201, 40 203 | 202, 197 204 | 203, 33 205 | 204, 41 206 | 205, 28 207 | 206, 25 208 | 207, 17 209 | 208, 62 210 | 209, 17 211 | 210, 71 212 | 211, 30 213 | 212, 41 214 | 213, 17 215 | 214, 51 216 | 215, 9 217 | 216, 33 218 | 217, 47 219 | 218, 13 220 | 219, 59 221 | 220, 17 222 | 221, 9 223 | 222, 51 224 | 223, 26 225 | 224, 39 226 | 225, 39 227 | 226, 35 228 | 227, 18 229 | 228, 45 230 | 229, 36 231 | 230, 34 232 | 231, 30 233 | 232, 34 234 | 233, 36 235 | 234, 14 236 | 235, 7 237 | 236, 28 238 | 237, 34 239 | 238, 49 240 | 239, 95 241 | 240, 66 242 | 241, 36 243 | 242, 32 244 | 243, 25 245 | 244, 25 246 | 245, 30 247 | 246, 15 248 | 247, 12 249 | 248, 40 250 | 249, 32 251 | 250, 26 252 | 251, 18 253 | 252, 60 254 | 253, 21 255 | 254, 79 256 | 255, 17 257 | 256, 42 258 | 257, 40 259 | 258, 23 260 | 259, 39 261 | 260, 58 262 | 261, 19 263 | 262, 45 264 | 263, 17 265 | 264, 66 266 | 265, 31 267 | 266, 25 268 | 267, 38 269 | 268, 16 270 | 269, 36 271 | 270, 20 272 | 271, 29 273 | 272, 26 274 | 273, 32 275 | 274, 22 276 | 275, 11 277 | 276, 60 278 | 277, 133 279 | 278, 46 280 | 279, 13 281 | 280, 20 282 | 281, 34 283 | 282, 20 284 | 283, 79 285 | 284, 44 286 | 285, 9 287 | 286, 63 288 | 287, 65 289 | 288, 43 290 | 289, 19 291 | 290, 68 292 | 291, 20 293 | 292, 24 294 | 293, 12 295 | 294, 83 296 | 295, 20 297 | 296, 33 298 | 297, 15 299 | 298, 29 300 | 299, 19 301 | 300, 63 302 | 301, 31 303 | 302, 47 304 | 303, 20 305 | 304, 45 306 | 305, 10 307 | 306, 13 308 | 307, 10 309 | 308, 23 310 | 309, 8 311 | 310, 84 312 | 311, 38 313 | 312, 22 314 | 313, 43 315 | 314, 25 316 | 315, 32 317 | 316, 29 318 | 317, 20 319 | 318, 26 320 | 319, 26 321 | 320, 40 322 | 321, 129 323 | 322, 45 324 | 323, 23 325 | 324, 67 326 | 325, 49 327 | 326, 90 328 | 327, 17 329 | 328, 76 330 | 329, 27 331 | 330, 136 332 | 331, 33 333 | 332, 21 334 | 333, 18 335 | 334, 14 336 | 335, 24 337 | 336, 14 338 | 337, 30 339 | 338, 26 340 | 339, 26 341 | 340, 29 342 | 341, 18 343 | 342, 53 344 | 343, 47 345 | 344, 93 346 | 345, 47 347 | 346, 9 348 | 347, 56 349 | 348, 60 350 | 349, 12 351 | 350, 69 352 | 351, 18 353 | 352, 38 354 | 353, 38 355 | 354, 27 356 | 355, 42 357 | 356, 61 358 | 357, 33 359 | 358, 39 360 | 359, 47 361 | 360, 13 362 | 361, 27 363 | 362, 17 364 | 363, 99 365 | 364, 44 366 | 365, 42 367 | 366, 43 368 | 367, 24 369 | 368, 29 370 | 369, 48 371 | 370, 34 372 | 371, 43 373 | 372, 52 374 | 373, 10 375 | 374, 28 376 | 375, 41 377 | 376, 87 378 | 377, 9 379 | 378, 22 380 | 379, 60 381 | 380, 19 382 | 381, 33 383 | 382, 35 384 | 383, 26 385 | 384, 22 386 | 385, 24 387 | 386, 68 388 | 387, 23 389 | 388, 19 390 | 389, 32 391 | 390, 32 392 | 391, 23 393 | 392, 22 394 | 393, 23 395 | 394, 49 396 | 395, 20 397 | 396, 11 398 | 397, 64 399 | 398, 24 400 | 399, 29 401 | 400, 47 402 | 401, 20 403 | 402, 13 404 | 403, 15 405 | 404, 34 406 | 405, 89 407 | 406, 81 408 | 407, 22 409 | 408, 79 410 | 409, 37 411 | 410, 18 412 | 411, 26 413 | 412, 35 414 | 413, 26 415 | 414, 13 416 | 415, 25 417 | 416, 118 418 | 417, 13 419 | 418, 23 420 | 419, 14 421 | 420, 12 422 | 421, 17 423 | 422, 16 424 | 423, 35 425 | 424, 19 426 | 425, 114 427 | 426, 97 428 | 427, 24 429 | 428, 71 430 | 429, 17 431 | 430, 22 432 | 431, 25 433 | 432, 36 434 | 433, 53 435 | 434, 51 436 | 435, 14 437 | 436, 48 438 | 437, 45 439 | 438, 25 440 | 439, 18 441 | 440, 17 442 | 441, 16 443 | 442, 83 444 | 443, 22 445 | 444, 16 446 | 445, 47 447 | 446, 25 448 | 447, 48 449 | 448, 15 450 | 449, 57 451 | 450, 14 452 | 451, 24 453 | 452, 38 454 | 453, 100 455 | 454, 34 456 | 455, 37 457 | 456, 59 458 | 457, 24 459 | 458, 16 460 | 459, 55 461 | 460, 36 462 | 461, 28 463 | 462, 33 464 | 463, 65 465 | 464, 12 466 | 465, 14 467 | 466, 32 468 | 467, 15 469 | 468, 28 470 | 469, 21 471 | 470, 84 472 | 471, 46 473 | 472, 35 474 | 473, 31 475 | 474, 16 476 | 475, 26 477 | 476, 16 478 | 477, 14 479 | 478, 29 480 | 479, 9 481 | 480, 29 482 | 481, 35 483 | 482, 47 484 | 483, 30 485 | 484, 13 486 | 485, 23 487 | 486, 16 488 | 487, 30 489 | 488, 23 490 | 489, 27 491 | 490, 13 492 | 491, 37 493 | 492, 26 494 | 493, 17 495 | 494, 56 496 | 495, 73 497 | 496, 144 498 | 497, 40 499 | 498, 21 500 | 499, 47 501 | 500, 39 502 | 501, 16 503 | 502, 37 504 | 503, 12 505 | 504, 17 506 | 505, 13 507 | 506, 12 508 | 507, 48 509 | 508, 73 510 | 509, 41 511 | 510, 50 512 | 511, 10 513 | 512, 65 514 | 513, 58 515 | 514, 13 516 | 515, 18 517 | 516, 22 518 | 517, 10 519 | 518, 11 520 | 519, 31 521 | 520, 27 522 | 521, 77 523 | 522, 21 524 | 523, 30 525 | 524, 16 526 | 525, 15 527 | 526, 18 528 | 527, 47 529 | 528, 56 530 | 529, 95 531 | 530, 33 532 | 531, 42 533 | 532, 51 534 | 533, 13 535 | 534, 29 536 | 535, 53 537 | 536, 41 538 | 537, 30 539 | 538, 16 540 | 539, 24 541 | 540, 16 542 | 541, 70 543 | 542, 28 544 | 543, 24 545 | 544, 45 546 | 545, 47 547 | 546, 64 548 | 547, 8 549 | 548, 23 550 | 549, 16 551 | 550, 54 552 | 551, 11 553 | 552, 92 554 | 553, 11 555 | 554, 64 556 | 555, 11 557 | 556, 58 558 | 557, 35 559 | 558, 19 560 | 559, 30 561 | 560, 23 562 | 561, 157 563 | 562, 40 564 | 563, 19 565 | 564, 15 566 | 565, 39 567 | 566, 77 568 | 567, 30 569 | 568, 13 570 | 569, 11 571 | 570, 18 572 | 571, 42 573 | 572, 27 574 | 573, 16 575 | 574, 35 576 | 575, 37 577 | 576, 72 578 | 577, 31 579 | 578, 20 580 | 579, 36 581 | 580, 40 582 | 581, 23 583 | 582, 7 584 | 583, 20 585 | 584, 46 586 | 585, 103 587 | 586, 90 588 | 587, 15 589 | 588, 63 590 | 589, 86 591 | 590, 18 592 | 591, 13 593 | 592, 20 594 | 593, 15 595 | 594, 8 596 | 595, 39 597 | 596, 54 598 | 597, 52 599 | 598, 36 600 | 599, 9 601 | 600, 41 602 | 601, 14 603 | 602, 66 604 | 603, 34 605 | 604, 13 606 | 605, 19 607 | 606, 12 608 | 607, 35 609 | 608, 37 610 | 609, 46 611 | 610, 25 612 | 611, 53 613 | 612, 30 614 | 613, 27 615 | 614, 30 616 | 615, 28 617 | 616, 91 618 | 617, 18 619 | 618, 19 620 | 619, 32 621 | 620, 24 622 | 621, 52 623 | 622, 18 624 | 623, 88 625 | 624, 38 626 | 625, 25 627 | 626, 20 628 | 627, 51 629 | 628, 25 630 | 629, 44 631 | 630, 14 632 | 631, 17 633 | 632, 54 634 | 633, 35 635 | 634, 40 636 | 635, 59 637 | 636, 34 638 | 637, 30 639 | 638, 30 640 | 639, 33 641 | 640, 60 642 | 641, 46 643 | 642, 26 644 | 643, 61 645 | 644, 45 646 | 645, 35 647 | 646, 33 648 | 647, 18 649 | 648, 31 650 | 649, 44 651 | 650, 24 652 | 651, 12 653 | 652, 15 654 | 653, 60 655 | 654, 24 656 | 655, 13 657 | 656, 40 658 | 657, 44 659 | 658, 17 660 | 659, 14 661 | 660, 19 662 | 661, 16 663 | 662, 40 664 | 663, 96 665 | 664, 23 666 | 665, 35 667 | 666, 33 668 | 667, 45 669 | 668, 18 670 | 669, 33 671 | 670, 15 672 | 671, 43 673 | 672, 19 674 | 673, 36 675 | 674, 28 676 | 675, 32 677 | 676, 9 678 | 677, 34 679 | 678, 8 680 | 679, 21 681 | 680, 26 682 | 681, 13 683 | 682, 34 684 | 683, 15 685 | 684, 32 686 | 685, 30 687 | 686, 21 688 | 687, 28 689 | 688, 28 690 | 689, 37 691 | 690, 10 692 | 691, 28 693 | 692, 38 694 | 693, 18 695 | 694, 23 696 | 695, 46 697 | 696, 30 698 | 697, 31 699 | 698, 34 700 | 699, 26 701 | 700, 13 702 | 701, 36 703 | 702, 11 704 | 703, 48 705 | 704, 24 706 | 705, 48 707 | 706, 18 708 | 707, 152 709 | 708, 13 710 | 709, 106 711 | 710, 19 712 | 711, 12 713 | 712, 20 714 | 713, 12 715 | 714, 39 716 | 715, 20 717 | 716, 20 718 | 717, 52 719 | 718, 77 720 | 719, 37 721 | 720, 79 722 | 721, 14 723 | 722, 23 724 | 723, 32 725 | 724, 56 726 | 725, 83 727 | 726, 47 728 | 727, 17 729 | 728, 12 730 | 729, 22 731 | 730, 27 732 | 731, 47 733 | 732, 25 734 | 733, 33 735 | 734, 30 736 | 735, 19 737 | 736, 36 738 | 737, 75 739 | 738, 20 740 | 739, 57 741 | 740, 12 742 | 741, 76 743 | 742, 30 744 | 743, 35 745 | 744, 77 746 | 745, 10 747 | 746, 73 748 | 747, 13 749 | 748, 39 750 | 749, 34 751 | 750, 31 752 | 751, 13 753 | 752, 14 754 | 753, 10 755 | 754, 45 756 | 755, 55 757 | 756, 29 758 | 757, 25 759 | 758, 47 760 | 759, 95 761 | 760, 13 762 | 761, 54 763 | 762, 17 764 | 763, 35 765 | 764, 74 766 | 765, 60 767 | 766, 14 768 | 767, 50 769 | 768, 30 770 | 769, 55 771 | 770, 22 772 | 771, 43 773 | 772, 92 774 | 773, 35 775 | 774, 47 776 | 775, 12 777 | 776, 51 778 | 777, 12 779 | 778, 93 780 | 779, 41 781 | 780, 47 782 | 781, 69 783 | 782, 36 784 | 783, 38 785 | 784, 32 786 | 785, 52 787 | 786, 13 788 | 787, 20 789 | 788, 48 790 | 789, 52 791 | 790, 33 792 | 791, 39 793 | 792, 56 794 | 793, 20 795 | 794, 41 796 | 795, 16 797 | 796, 70 798 | 797, 57 799 | 798, 85 800 | 799, 23 801 | 800, 17 802 | 801, 30 803 | 802, 33 804 | 803, 11 805 | 804, 26 806 | 805, 50 807 | 806, 40 808 | 807, 20 809 | 808, 68 810 | 809, 12 811 | 810, 75 812 | 811, 14 813 | 812, 36 814 | 813, 35 815 | 814, 39 816 | 815, 30 817 | 816, 13 818 | 817, 62 819 | 818, 23 820 | 819, 26 821 | 820, 56 822 | 821, 30 823 | 822, 40 824 | 823, 12 825 | 824, 23 826 | 825, 30 827 | 826, 17 828 | 827, 19 829 | 828, 17 830 | 829, 19 831 | 830, 45 832 | 831, 14 833 | 832, 60 834 | 833, 49 835 | 834, 32 836 | 835, 12 837 | 836, 44 838 | 837, 43 839 | 838, 21 840 | 839, 9 841 | 840, 12 842 | 841, 16 843 | 842, 14 844 | 843, 17 845 | 844, 18 846 | 845, 29 847 | 846, 56 848 | 847, 34 849 | 848, 24 850 | 849, 58 851 | 850, 27 852 | 851, 12 853 | 852, 23 854 | 853, 75 855 | 854, 15 856 | 855, 20 857 | 856, 31 858 | 857, 51 859 | 858, 10 860 | 859, 70 861 | 860, 70 862 | 861, 71 863 | 862, 53 864 | 863, 35 865 | 864, 12 866 | 865, 23 867 | 866, 26 868 | 867, 25 869 | 868, 48 870 | 869, 45 871 | 870, 36 872 | 871, 38 873 | 872, 27 874 | 873, 29 875 | 874, 55 876 | 875, 34 877 | 876, 38 878 | 877, 17 879 | 878, 43 880 | 879, 32 881 | 880, 40 882 | 881, 27 883 | 882, 8 884 | 883, 24 885 | 884, 18 886 | 885, 29 887 | 886, 11 888 | 887, 23 889 | 888, 30 890 | 889, 64 891 | 890, 65 892 | 891, 19 893 | 892, 52 894 | 893, 8 895 | 894, 29 896 | 895, 48 897 | 896, 67 898 | 897, 18 899 | 898, 18 900 | 899, 11 901 | 900, 53 902 | 901, 87 903 | 902, 24 904 | 903, 25 905 | 904, 27 906 | 905, 14 907 | 906, 80 908 | 907, 17 909 | 908, 32 910 | 909, 16 911 | 910, 32 912 | 911, 11 913 | 912, 27 914 | 913, 15 915 | 914, 9 916 | 915, 25 917 | 916, 48 918 | 917, 18 919 | 918, 38 920 | 919, 20 921 | 920, 27 922 | 921, 23 923 | 922, 19 924 | 923, 21 925 | 924, 21 926 | 925, 18 927 | 926, 49 928 | 927, 9 929 | 928, 58 930 | 929, 24 931 | 930, 18 932 | 931, 17 933 | 932, 25 934 | 933, 87 935 | 934, 31 936 | 935, 14 937 | 936, 39 938 | 937, 16 939 | 938, 29 940 | 939, 10 941 | 940, 14 942 | 941, 14 943 | 942, 12 944 | 943, 34 945 | 944, 26 946 | 945, 53 947 | 946, 55 948 | 947, 41 949 | 948, 55 950 | 949, 29 951 | 950, 26 952 | 951, 12 953 | 952, 46 954 | 953, 32 955 | 954, 62 956 | 955, 52 957 | 956, 78 958 | 957, 37 959 | 958, 91 960 | 959, 119 961 | 960, 28 962 | 961, 30 963 | 962, 31 964 | 963, 66 965 | 964, 32 966 | 965, 26 967 | 966, 22 968 | 967, 20 969 | 968, 22 970 | 969, 37 971 | 970, 22 972 | 971, 73 973 | 972, 33 974 | 973, 52 975 | 974, 44 976 | 975, 9 977 | 976, 31 978 | 977, 17 979 | 978, 22 980 | 979, 20 981 | 980, 20 982 | 981, 22 983 | 982, 49 984 | 983, 8 985 | 984, 65 986 | 985, 22 987 | 986, 38 988 | 987, 29 989 | 988, 8 990 | 989, 44 991 | 990, 25 992 | 991, 24 993 | 992, 27 994 | 993, 28 995 | 994, 32 996 | 995, 93 997 | 996, 24 998 | 997, 21 999 | 998, 47 1000 | 999, 30 1001 | 1000, 12 1002 | --------------------------------------------------------------------------------