java-使用Jacob實現office轉換成pdf


注意:com的線程回收不由java垃圾回收器進行處理,因此,每new一次jacob提供的類就要分配一定大小的內存給該操作,new出來的這個com對象在使用結束之后產生的垃圾java是無法回收的,new出來的對象越來越多,內存溢出就不可避免了

https://blog.csdn.net/u011783999/article/details/50897672?tdsourcetag=s_pcqq_aiomsg

https://men4661273.iteye.com/blog/2097871

參考路徑:

https://blog.csdn.net/csdnFlyFun/article/details/79523262#commentBox

Jacob組件下載地址:https://sourceforge.net/projects/jacob-project/

Jacob 介紹

Jacob 是 JAVA-COM Bridge的縮寫,是一個中間件,能夠提供自動化訪問MS系統下COM組件和Win32 libraries的功能。

MS系統提供的COM組件

COM組件 對象ID
Microsoft Word Word.Application
Microsoft Excel Excel.Application
Microsoft Powerpoint Powerpoint.Application
Microsoft IE InternetExplore.Application
WPS文字 KWPS.Aplication
WPS的Excel KET.Application
WPS的演示文檔 KWPP.Application

核心類:

JacobObject:用於Java程序MS下的COM進行通信,創建標准的API框架

ComThread:初始化COM組件線程,釋放線程,對線程進行管理

Dispatch:調度處理類,封裝了操作來從而操作Office,並表示不同MS級別調度對象

ActiveXComponent : 創建COM組件

Variant : 與COM通訊的參數或者返回值

ROT :Running Object Table (ROT),運行對象表將每個線程映射到所有jacobobjects,在線程創建

核心方法:

Dispatch : 可調用該自動化對象的屬性或方法,具體的屬性和方法要看參考文檔VBA API

Dispatch.get(dispatch, String name);獲取對象屬性

Dispatch.put(dispatch, String name, Object value);設置對象屬性

Dispatch.call(dispatch, String name, Object… args);調用對象方法

Dispatch.call部分參數解釋:

Dispatch content = Dispatch.call(document, "XXX").getDispatch();

XXX所表示:

Documents:所有文檔

Open:打開文檔

ActiveXComponent.Visible:設置編輯器是否可見

Tables:獲得所有的表格

Bookmarks:所有標簽

Selection:光標所在處或選中的區域

select:選中

typeParagraph:設置為一個段落

ParagraphFormat:段落格式,用alignment設置

alignment:1、居中,2、靠右,3、靠左

Add:新建一個word文檔

Close:關閉文檔,0不保存,-1保存,-2彈出框確認,注意ComThread.Release();關閉整個word進程

SaveAS:另存為

save:保存

printOut:打印

Application:得到ActiveXComponent的實例

WindowState:Application的屬性,表示窗口的大小,0、default,1、maximize,2、minimize

top、left、height、width:application的屬性,表示窗口的位置

ActiveXComponent.Quit:關閉所有word文檔,但是不退出整個word程序

Range:表示文檔中的一個連續范圍,由一個起始字符位置和一個終止字符位置定義,進而可以得到格式的信息

Item:得到指定的表格

Rows:得到表格的所有行

Cell:表格的一個單元格

Text:word的文本內容

InsertFile:插入文件

InsertRowsBelow:在指定的行下面插入一行

InsertAfter:在指定對象后插入

Delete:刪除,可以是表格的行

Count:返回數目,比如Rows、Tables的數目

Height:返回高度,比如行高、表格行的高

Split:拆分單元格,要指定行數和列數

Merge:合並單元格

Exists:指定的對象是否存在,返回bool值

Copy:復制

Paste:粘貼

Font:字體

Name:字體的名字

Bold:字體是否為粗體

Italic:字體是否為斜體

Underline:字體是否有下划線

Color:顏色

Size:大小

Borders:指定邊框,-1為上邊框,-2左邊框,-3為下邊框,-4有右邊框,-5為橫向邊框,-6為縱向邊框,-7從左上角開始的斜線,-8從左下角開始的斜線

AutoFitBehavior:自動調整大小,1為內容自動調整大小,2為窗口自動調整大小

Content:取的內容

InLineShapes:

AddPicture:增加一張圖片,需要制定路徑

homeKey:光標移到開頭

moveDown:光標往下一行

moveUp:光標往上一行

moveRight:光標往左一列

moveLeft:光標往右一列

find:要查找的文本

Forward:向前查找

Format:查找的文本格式

MatchCase:大小寫匹配

MatchWholeWord:全字匹配

Execute:開始執行查找

 

參考:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComFailException;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;

public class JacobPDFConverter implements PDFConverter {
    private static final int wdFormatPDF = 17;
    private static final int xlTypePDF = 0;
    private static final int ppSaveAsPDF = 32;
    
    public void convert2PDF(String inputFile, String pdfFile) {
        String suffix = FileUtils.getFileSufix(inputFile);
        File file = new File(inputFile);
        if(!file.exists()){
            System.out.println("文件不存在!");
            return;
        }
        if(suffix.equals("pdf")){
            System.out.println("PDF not need to convert!");
            return ;
        }
        boolean isImg = false;//FileUtils.isImage(inputFile);
        try{
            isImg = FileUtils.isImage(inputFile);
        }catch(Exception ce){

        }
        if(isImg){
            img2PDF(inputFile,pdfFile);
        }else if(suffix.equals("doc")||suffix.equals("docx")||suffix.equals("txt")){
            word2PDF(inputFile,pdfFile);
        }else if(suffix.equals("ppt")||suffix.equals("pptx")){
            ppt2PDF(inputFile,pdfFile);
        }else if(suffix.equals("xls")||suffix.equals("xlsx")){
            excel2PDF(inputFile,pdfFile);
        }else if(suffix.equals("wps")){
            //wps2PDF(inputFile,pdfFile);
            word2PDF(inputFile,pdfFile);
        }else{
            //System.out.println("文件格式不支持轉換!");
            word2PDF(inputFile,pdfFile);
        }
    }

    public void convert2PDF(String inputFile) {
        String pdfFile = FileUtils.getFilePrefix(inputFile)+".pdf";
        convert2PDF(inputFile,pdfFile);
        
    }
    
    public  void convert2PDF(String[] inputFiles, String[] pdfFiles) {
        try {
            for(int i = 0;i<inputFiles.length;i++){
                String inputFile = inputFiles[i];
                String pdfFile = pdfFiles[i];
                if(inputFile==null || inputFile.equals("")) continue;
                convert2PDF(inputFile,pdfFile);
            }
        }catch (Exception ce) {
            
        }
    }
    
    public void convert2PDF(String[] inputFiles) {
        String pdfFiles[] = new String[inputFiles.length];
        for(int i = 0;i<inputFiles.length;i++){
            String inputFile = inputFiles[i];
            String pdfFile = FileUtils.getFilePrefix(inputFile)+".pdf";
            pdfFiles[i] = pdfFile;
        }
        convert2PDF(inputFiles,pdfFiles);
    }    
    
    public static void word2PDF(String inputFile,String pdfFile){
        ActiveXComponent app = null;
        Dispatch doc = null;
        try {
            ComThread.InitSTA();
            app = new ActiveXComponent("Word.Application"); //打開word應用程序
            app.setProperty("Visible", false); //設置word不可見
            Dispatch docs = app.getProperty("Documents").toDispatch(); //獲得word中所有打開的文檔,返回Documents對象
            //調用Documents對象中Open方法打開文檔,並返回打開的文檔對象Document
            doc = Dispatch.call(docs,
                                    "Open",
                                    inputFile,
                                    false,
                                    true
                                    ).toDispatch();
            Dispatch.call(doc,
                "ExportAsFixedFormat",
                pdfFile,
                wdFormatPDF        //word保存為pdf格式宏,值為17
                );
        } catch (ComFailException e) {  
              
        } catch (Exception e) {  
          
        } finally {  
            if (doc != null) {  
                Dispatch.call(doc, "Close", false); //關閉文檔
            }  
            if (app != null) {  
                app.invoke("Quit", 0); //關閉word應用程序
            }  
            ComThread.Release();  
        }  
    }
    public static void excel2PDF(String inputFile,String pdfFile){
        ActiveXComponent app = null;
        Dispatch excel = null;
        try {
            ComThread.InitSTA();
            app = new ActiveXComponent("Excel.Application");
            app.setProperty("Visible", false);
            Dispatch excels = app.getProperty("Workbooks").toDispatch();
            excel = Dispatch.call(excels,
                                    "Open",
                                    inputFile,
                                    false,
                                    true
                                    ).toDispatch();
            Dispatch.call(excel,
                    "ExportAsFixedFormat",
                    xlTypePDF,        
                    pdfFile
                    );
        } catch (ComFailException e) {  
             
        } catch (Exception e) {  
  
        } finally {  
            if (excel != null) {  
                Dispatch.call(excel, "Close",false);  
            }  
            if (app != null) {  
                app.invoke("Quit");  
            }  
            ComThread.Release();  
        }
    }
    public static void ppt2PDF(String inputFile,String pdfFile){
        ActiveXComponent app = null;  
        Dispatch ppt = null; 
        try {
            ComThread.InitSTA();
            app = new ActiveXComponent("PowerPoint.Application");
            //app.setProperty("Visible", false);
            Dispatch ppts = app.getProperty("Presentations").toDispatch();
            ppt = Dispatch.call(ppts,
                                    "Open",
                                    inputFile,
                                    true,//ReadOnly
                                    true,//Untitled指定文件是否有標題
                                    false//WithWindow指定文件是否可見
                                    ).toDispatch();
            Dispatch.call(ppt,
                    "SaveAs",
                    pdfFile,
                    ppSaveAsPDF    
                    );
        } catch (ComFailException e) {  
            System.out.println(e.getMessage());
        } catch (Exception e) {  
  
        } finally {  
            if (ppt != null) {  
                Dispatch.call(ppt, "Close");  
            }  
            if (app != null) {  
                app.invoke("Quit");  
            }  
            ComThread.Release();
        }
    }
    
    public void wps2PDF(String inputFile,String pdfFile) {  
        File sFile = new File(inputFile);
        File tFile = new File(pdfFile);
        ActiveXComponent wps = null;
        try {
            ComThread.InitSTA();
            wps = new ActiveXComponent("wps.application");
            ActiveXComponent doc = wps.invokeGetComponent("Documents").invokeGetComponent("Open", new Variant(sFile.getAbsolutePath()));  
            doc.invoke("ExportPdf", new Variant(tFile.getAbsolutePath()));  
            doc.invoke("Close");  
            doc.safeRelease();  
        } catch (Exception e) {  
            System.out.println(e.getMessage());  
        } finally {  
            if (wps != null) {  
                wps.invoke("Terminate");  
                wps.safeRelease();  
            }
            ComThread.Release();
        }  
    }  

    public void img2PDF(String inputFile,String pdfFile) {
        Document doc = new Document(PageSize.A4, 20, 20, 20, 20);
        try {
            PdfWriter.getInstance(doc, new FileOutputStream(pdfFile));
            doc.open();
            doc.newPage();
            Image img = Image.getInstance(inputFile);
            float heigth = img.getHeight();
            float width = img.getWidth();
            int percent = getPercent(heigth, width);
            img.setAlignment(Image.MIDDLE);
            img.scalePercent(percent+3);// 表示是原來圖像的比例;
            doc.add(img);
            doc.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        File mOutputPdfFile = new File(pdfFile);
        if (!mOutputPdfFile.exists()) {
            mOutputPdfFile.deleteOnExit();
            return;
        }
    }
    public static int getPercent(float h, float w) {
        int p = 0;
        float p2 = 0.0f;
        p2 = 530 / w * 100;
        p = Math.round(p2);
        return p;
       }
}
View Code

 

例:

package net.nblh.utils;

import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.icepdf.core.pobjects.Document;
import org.icepdf.core.util.GraphicsRenderingHints;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComFailException;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;

public class Word2PdfUtil {

    private static final int ppSaveAsPDF = 32;

    static final int wdDoNotSaveChanges = 0;// 不保存待定的更改
    static final int wdFormatPDF = 17;// word轉PDF 格式

    /**
     * 文檔轉pdf轉png
     * @param source 源文件
     */
    public static int execuConvert(String source) {
        
        String ext = source.substring(source.lastIndexOf("."));
        String tar = source.replace(ext, ".pdf");
        File file = new File(tar);
        
        if (file.exists()) {
            //pdf文件已轉換,直接轉png
            return pdf2pngByFile(tar);
        }

        // 示例
//        String source = "D:\\2017\\庭審案件材料一.doc";
//        String target = "D:\\2018\\庭審案件材料一.pdf";

        if (!checkAvailable(source,tar)) {
            return 0;
        }

//        String t = setPdfType(source, target);
        
        String suffixStr = getSuffix(source);
        if (".doc".equals(suffixStr) || ".docx".equals(suffixStr)) {
            return word2pdf(source, tar);
        } else if(".pptx".equals(suffixStr) || ".ppt".equals(suffixStr)){
             return ppt2pdf(source, tar);
        } else if(".xls".equals(suffixStr) || ".xlsx".equals(suffixStr)){
            return xls2Pdf(source, tar);
        } else {
            System.out.println("無法轉換此文件格式");
        }
        return 0;

    }

    public static int word2pdf(String source, String target) {
        ActiveXComponent app = null;
        Dispatch doc = null;
        try {
            app = new ActiveXComponent("Word.Application");
            app.setProperty("Visible", false);

            Dispatch docs = app.getProperty("Documents").toDispatch();

            doc = Dispatch.call(docs, "Open", source, false, true).toDispatch();
            File tofile = new File(target);
            File dirPath = new File(getPath(target));
            if (tofile.exists()) {
                tofile.delete();
            } else if (!dirPath.exists()) {
                dirPath.mkdirs();
            }

            Dispatch.call(doc, "SaveAs", target, wdFormatPDF);
//            Dispatch.call(doc, "SAs", target, wdFormatPDF);

            Dispatch.call(doc, "Close", false);
            doc = null;

            app.invoke("Quit", wdDoNotSaveChanges);
            app = null;
            System.out.println("pdf_ok");
            
            return pdf2pngByFile(target);
        } catch (Exception e) {
            return 0;
        } finally {
            if (null != doc) {
                Dispatch.call(doc, "Close", false);
            }
            if (app != null) {
                app.invoke("Quit", wdDoNotSaveChanges);
            }
        }
    }

    /**
     * 檢查文件格式,只轉換doc ,docx,ppt格式 fileName 文件名
     * 
     * @return
     */
    private static boolean checkFormat(String fileName) {
        if (null == fileName || "".equals(fileName)) {
            return false;
        }

        if (!(fileName.substring(fileName.lastIndexOf(File.separator)).contains("."))) {
            System.out.println("沒有指明要轉換的文件");
            return false;
        }

        String format = fileName.substring(fileName.lastIndexOf("."));
        if (".doc".equals(format) || ".docx".equals(format) || ".ppt".equals(format) || ".pptx".equals(format)
                || ".xls".equals(format) || ".xlsx".equals(format) || ".dot".equals(format) || ".dotx".equals(format)
                || ".pot".equals(format) || ".potx".equals(format) || ".xlt".equals(format) || "xltx".equals(format)) {

            return true;
        }
        System.out.println("文件格式不合符,無法轉換");
        return false;
    }
    
    /**
     * 檢查路徑是否正確
     * @return
     */
    public static boolean checkAvailable(String source,String target){
        if (isEmpty(source.trim())) {
            System.out.println("源文件路徑不存在");
            return false;
        }
        
        if(!source.contains(File.separator) || !source.contains(".")){
            System.out.println("請輸入正確的源文件路徑,以及源文件名");
            return false;
        }
        
        if(".".equals(getSuffix(source).trim())){
            System.out.println("請輸入正確的源文件名");
            return false;
        }
        
        if(isEmpty(target)){
            System.out.println("目標文件路徑不存在");
            return false;
        }
        
        if(!target.contains(File.separator) || !target.contains(".")){
            System.out.println("請輸入正確的目標文件路徑,以及目標文件名");
            return false;
        }
        
        if(!".pdf".equals(getSuffix(target))){
            System.out.println("請正確輸入要生成的pdf文件名");
            return false;
        }
        
        return true;
    }

    /**
     * 截取文件全路徑,不包括文件名 F:/snd/down/ceshi/
     */
    private static String getPath(String fileName) {
        if (null != fileName || !"".equals(fileName)) {
            return fileName.substring(0, fileName.lastIndexOf(File.separator));
        }
        return "";
    }

    /**
     * 如果目標文件后綴名不是pdf,則強行改為pdf
     */
    private static String setPdfType(String source, String target) {
        // 目標路徑包含文件名稱
        if (target.substring(target.lastIndexOf(File.separator)).contains(".")) {
            String ext = target.substring(target.lastIndexOf("."));
            String fileName = target.replace(ext, ".pdf");
            return fileName;
        } else {
            // 沒有文件名稱,只有路徑
            return target + getFileName(source) + ".pdf";
        }
    }

    /**
     * 截取文件名 不包含后綴名
     * 
     * @return
     */
    private static String getFileName(String fileName) {
        if (!isEmpty(fileName)) {
            return fileName.substring(fileName.lastIndexOf(File.separator), fileName.lastIndexOf("."));
        }
        return "";
    }
    
    /**
     * 獲得后綴名
     * @param fileName
     * @return
     */
    private static String getSuffix(String fileName){
        return fileName.substring(fileName.lastIndexOf("."));
    }

    private static boolean isEmpty(String str) {
        if (null == str || "".equals(str)) {
            return true;
        }
        return false;
    }

    //ppt 轉 pdf
    public static int ppt2pdf(String srcFilePath, String pdfFilePath) {
        ActiveXComponent app = null;
        Dispatch ppt = null;
        try {
            
            ComThread.InitSTA();
            app = new ActiveXComponent("PowerPoint.Application");
            Dispatch ppts = app.getProperty("Presentations").toDispatch();

            // 因POWER.EXE的發布規則為同步,所以設置為同步發布
            ppt = Dispatch.call(ppts, "Open", srcFilePath, true, // ReadOnly
                    true, // Untitled指定文件是否有標題
                    false// WithWindow指定文件是否可見
            ).toDispatch();
            
            File dirPath = new File(getPath(pdfFilePath));
            if (!dirPath.exists()) {
                dirPath.mkdirs();
            }

            Dispatch.call(ppt, "SaveAs", pdfFilePath, ppSaveAsPDF); // ppSaveAsPDF為特定值32
            System.out.println("pdf轉換完成!");
            
            return pdf2pngByFile(pdfFilePath); // set flag true;
        } catch (ComFailException e) {
            System.out.println(e.toString());
            return 0;
        } catch (Exception e) {
            System.out.println(e.toString());
            return 0;
        } finally {
            if (ppt != null) {
                Dispatch.call(ppt, "Close");
            }
            if (app != null) {
                app.invoke("Quit");
            }
            ComThread.Release();
        }
    }

    // EXCEL轉PDF
    public static int xls2Pdf(String inFilePath, String outFilePath) {
        ActiveXComponent ax = null;
        Dispatch excels = null;
        Dispatch excel = null;
        try {
            
            ax = new ActiveXComponent("Excel.Application");
            ComThread.InitSTA();
            ax.setProperty("Visible", new Variant(false));
            ax.setProperty("AutomationSecurity", new Variant(3)); // 禁用宏
            excels = ax.getProperty("Workbooks").toDispatch();
            
            File dirPath = new File(getPath(outFilePath));
            if (!dirPath.exists()) {
                dirPath.mkdirs();
            }

            excel = Dispatch
                    .invoke(excels, "Open", Dispatch.Method,
                            new Object[] { inFilePath, new Variant(false), new Variant(false) }, new int[9])
                    .toDispatch();

            // 轉換格式
            Dispatch.invoke(excel, "ExportAsFixedFormat", Dispatch.Method, new Object[] { new Variant(0), // PDF格式=0
                    outFilePath, new Variant(0) }, new int[1]);// 0=標准
                                                                // (生成的PDF圖片不會變模糊)
                                                                // 1=最小文件
                                                                // (生成的PDF圖片糊的一塌糊塗)

            Dispatch.call(excel, "Close", new Variant(false));

            if (ax != null) {
                ax.invoke("Quit", new Variant[] {});
                ax = null;
            }
            System.out.println("pdf轉換完成!");
            
            return pdf2pngByFile(outFilePath);
        } catch (Exception es) {
            System.out.println(es.toString());
            return 0;
        } finally {
            ComThread.Release();
        }
    }
    
    /**
     * 本地pdf文件轉png 
     */
    public static int pdf2pngByFile(String target){
        String filePath = target;
        Document document = new Document();
//        System.out.println("開始轉png");
        try {
            document.setFile(filePath);
            float scale = 1.5f;// 縮放比例(大圖)
            // float scale = 0.2f;// 縮放比例(小圖)
            float rotation = 0f;// 旋轉角度
            int pageSize = document.getNumberOfPages();
            for (int i = 0; i < document.getNumberOfPages(); i++) {
                BufferedImage image = (BufferedImage) document.getPageImage(i, GraphicsRenderingHints.SCREEN,
                        org.icepdf.core.pobjects.Page.BOUNDARY_CROPBOX, rotation, scale);
                RenderedImage rendImage = image;
//                try {
//                    File file = new File("D:/fileUpload/ftpDownload/icepdf_a" + i + ".png");
//                    // 這里png作用是:格式是jpg但有png清晰度
//                    ImageIO.write(rendImage, "png", file);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
                try {
//                    WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
//                    ServletContext servletContext = webApplicationContext.getServletContext();
//                    File contextPath = new File(servletContext.getRealPath("/")); // 項目根目錄
//                    File uploadPath = new File(
//                            contextPath.getParentFile().getAbsoluteFile() + File.separator + "uploadFiles"); // 上傳圖片存放目錄
                    File uploadPath = new File(target);
                    String fileName = getPathWithName(target);
                    File file1 = new File(fileName);
                    if (!file1.exists()) {
                        file1.mkdirs();
                    }
//                    System.out.println("地址=" + uploadPath.getAbsolutePath() + "/icepdf_a" + i + ".png" + "\n");
                    File file = new File(fileName + "\\" + i + ".png");
                    // 這里png作用是:格式是jpg但有png清晰度
                    ImageIO.write(rendImage, "png", file);
                    
                } catch (IOException e) {
                    e.printStackTrace();
                }
                image.flush();
            }
            document.dispose();
            System.out.println("png_ok");
            System.out.println("pageSize="+pageSize);
            return pageSize;
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return 0;
    }
    
    /**
     * 截取文件全路徑,包括文件名,去掉后綴 F:/snd/down/ceshi/aaa
     */
    public static String getPathWithName(String fileName) {
        if (null != fileName || !"".equals(fileName)) {
            return fileName.substring(0, fileName.lastIndexOf("."));
        }
        return "";
    }

}
View Code

 

ppt = Dispatch.call(ppts, "Open", srcFilePath, true, // ReadOnly
                    false, // Untitled指定文件是否有標題(參數必須為false,設置成true,ppt轉換pdf異常)
                    false// WithWindow指定文件是否可見
            ).toDispatch();

Dispatch.call(ppt, "SaveAs", pdfFilePath, ppSaveAsPDF); // ppSaveAsPDF為特定值32

 

參考地址:

https://blog.csdn.net/u013761812/article/details/72742629

http://blog.sina.com.cn/s/blog_aa90e61e0101a14x.html

http://www.bubuko.com/infodetail-1320787.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM