poi docx 字符,图片替换

项目中遇到 word动态替换参数,及图片的问题、总结一下

maven pom.xml jar包导入
		<!-- poi -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.12</version>
		</dependency>
		  <dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.12</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-scratchpad</artifactId>
			<version>3.12</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>3.12</version>
		</dependency>
	
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>ooxml-schemas</artifactId>
			<version>1.1</version>
		</dependency>

		<dependency>  
	        <groupId>fr.opensagres.xdocreport</groupId>  
	        <artifactId>org.apache.poi.xwpf.converter.core</artifactId>  
	        <version>1.0.5</version>  
	    </dependency>
		 <dependency>
			 <groupId>fr.opensagres.xdocreport</groupId> 
				<artifactId>org.apache.poi.xwpf.converter.xhtml</artifactId>
				<version>1.0.5</version>
			</dependency> 



2 转换 Word07toHtml.java

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.poi.xwpf.converter.core.FileImageExtractor;
import org.apache.poi.xwpf.converter.core.FileURIResolver;
import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
  
/**
 * @author lzhang
 * word docx 转 html
 *
 */
public class Word07toHtml {
	private static Logger logger = LoggerFactory.getLogger(Word07toHtml.class);
	
    /**
     * word 2007 支持.docx 转html文件
     * @param sourceWordUrl word文件路径+文件名
     * @param targetImageFolderFileUrl html生成图片目录
     * @param targetHtmlUrl 生成html文件路径+名称
     * @return
     * @throws IOException
     */
    public static String canExtractImage(String sourceWordUrl,String targetImageFolderFileUrl,String targetHtmlUrl){
    	//sourceWordUrl="D:\\tmp\\upload_file\\sinfo-p-tmp\\78.docx";
    	// targetImageFolderFileUrl = "C:\\Users\\qk203\\Desktop\\view\\";
    	// targetHtmlUrl = "1.html";
        File f = new File(sourceWordUrl);
        if (f.getName().endsWith(".docx") || f.getName().endsWith(".DOCX")) {
            OutputStream out = null;
            InputStream in = null;
            try {
            	 // 1) Load DOCX into XWPFDocument  
                in = new FileInputStream(f);  
                XWPFDocument document = new XWPFDocument(in);  
                // 2) Prepare XHTML options (here we set the IURIResolver to  
                // load images from a "word/media" folder)  
                File file = new File(targetImageFolderFileUrl);
                if(!file.exists()){
                	file.mkdir();
                }
                //
                File imageFolderFile = new File(targetImageFolderFileUrl);
                FileURIResolver a=new FileURIResolver(imageFolderFile);
                XHTMLOptions options = XHTMLOptions.create().URIResolver(new FileURIResolver(imageFolderFile));
                options.setExtractor(new FileImageExtractor(imageFolderFile));  
                
                options.setOmitHeaderFooterPages(false);
                
                //options.setIgnoreStylesIfUnused(false);  
                //options.setFragment(true);  
                // 3) Convert XWPFDocument to XHTML  
            	out = new FileOutputStream(new File(targetImageFolderFileUrl+targetHtmlUrl));
                XHTMLConverter.getInstance().convert(document, out, options); 

                document = null;
                imageFolderFile = null;
                options = null;
                return targetImageFolderFileUrl+targetHtmlUrl;
			} catch (Exception e) {
				logger.error("canExtractImage XHTMLConverter.getInstance Exception,",e);
			}finally{
				 try {
					in.close();
				} catch (IOException e) {
					logger.error("canExtractImage in.close Exception,",e);
				}
		         try {
					out.close();
				} catch (IOException e) {
					logger.error("canExtractImage out.close Exception,",e);
				}
			}
        }   
	    logger.info("Word07toHtml canExtractImage Sorry File does not Exists!");
	    return null;
    } 
    
    public static void main(String[] args) {
    	try {
    		
    		Map<String, String> param = new HashMap<String, String>();
			param.put("${candName}", "huangqiqing");  
	        param.put("${postName}", "信息管理与信息系统");  
	        param.put("${candSex}", "男");  
	        param.put("${candRegisterAddress}", "山东财经大学");  
	        param.put("${candEmergencyPeple}", "王麻子");//紧急联系人
	        param.put("${pdetBedate}","2015年12月1日");
	        param.put("${pdetEndate}","2015年12月15日");
	        param.put("${pdetProbationaryEdate}","2015年10月1日");
	        param.put("${pdetAformalDate}","2015年10月15日");
			 
    		String doc ="";
    		 doc = WordCompileReport.wordReplace("D:\\tmp\\upload_file\\pact\\pact-151109160601.docx", 
    				"D:\\tmp\\upload_file\\sinfo-p-tmp\\",
    				"78.docx", "D:\\tmp\\upload_file\\sinfo-p-tmp\\", param);
    		
    		doc ="D:\\tmp\\upload_file\\sinfo-p-tmp\\78.docx";
			canExtractImage(doc,"D:\\tmp\\upload_file\\info-p-view\\","78.html");
			
			System.out.println("ok~");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}  


3 WordCompileReport.java

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @author lzhang
 * word 参数转换
 */
public class WordCompileReport {
		private static Logger logger = LoggerFactory.getLogger(Word07toHtml.class);
	
        public static void searchAndReplace(String srcPath, String destPath,
                Map<String,String> map,Map<String,String> mapImage) {
            try {
                XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(srcPath));
                //替换段落占位符
                checkParagraphs(document,map);
               //替换图片
                if(mapImage.get("${img}") != null ){
                    replaceTextToImage(document,mapImage,150,60);
                }
                FileOutputStream outStream = null;
                outStream = new FileOutputStream(destPath);
                document.write(outStream);
                outStream.close();
                document = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        
        /**
         * table 内容替换
         * @param document
         * @param map
         */
        public static void checkTables(XWPFDocument document,
                Map<Object,Object> map) {
            Iterator it = document.getTablesIterator();
            while (it.hasNext()) {
                XWPFTable table = (XWPFTable) it.next();
                int rcount = table.getNumberOfRows();
                for (int i = 0; i < rcount; i++) {
                    XWPFTableRow row = table.getRow(i);
                    List<XWPFTableCell> cells = row.getTableCells();
                    for (XWPFTableCell cell : cells) {
                        List<XWPFParagraph> listCell;
                        for (Object e : map.keySet()) {
                            listCell = cell.getParagraphs();
                            List<XWPFRun> cellRun;
                            Map mapAttr = new HashMap();
                            for (int j = 0; j < listCell.size(); j++) {
                                if (listCell.get(j).getText().indexOf(e+"") != -1) {
                                    cellRun = listCell.get(j).getRuns();
                                    for (int c = 0; c < cellRun.size(); c++) {
                                        if (cellRun.get(c).getText(0).equals(e)) {
                                            mapAttr = getWordXWPFRunStyle(cellRun.get(c));
                                            listCell.get(j).removeRun(c);
                                            XWPFRun newRun = listCell.get(j).insertNewRun(c);
                                            setWordXWPFRunStyle(newRun, mapAttr,map.get(e)+"", false);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        
        /**
         * 段落参数替换
         * @param document
         * @param map
         */
        public static void checkParagraphs(XWPFDocument document,Map<String,String> map){
        	List<XWPFRun> listRun;
            Map mapAttr = new HashMap();
            List<XWPFParagraph> listParagraphs = document.getParagraphs();
            for (int sa = 0; sa < listParagraphs.size(); sa++) {
            	String str = listParagraphs.get(sa).getText();
            	//logger.info("XWPFParagraph="+str);
                for (String key : map.keySet()) {
                    if (str.indexOf(key+"") != -1) {
                        listRun = listParagraphs.get(sa).getRuns();
                        for (int p = 0; p < listRun.size(); p++) {
                        	String pstr = listRun.get(p).toString();
                        	logger.debug(" listRun.get(p)="+pstr);
                        	  if (pstr.indexOf(key) > -1) {
                        		logger.info("pstr="+pstr+" value="+map.get(key));
                        	    pstr = pstr.replace(key, map.get(key));
                                //得到占位符的文本格式
                                XWPFRun runOld = listParagraphs.get(sa).getRuns().get(p);
                                mapAttr=getWordXWPFRunStyle(runOld); //封装该占位符文本样式到map
                                listParagraphs.get(sa).removeRun(p);//移除占位符
                                //创建设置对应占位符的文本
                                XWPFRun runNew = listParagraphs.get(sa).insertNewRun(p);
                                setWordXWPFRunStyle(runNew,mapAttr,pstr+"",true);
                            }
                        }
                    }
                }
            }
        }
        
        public static Map getWordXWPFRunStyle(XWPFRun runOld){
            Map mapAttr = new HashMap();
            mapAttr.put("Underline", runOld.getUnderline());
            //mapAttr.put("Color", runOld.getColor());
            //mapAttr.put("FontSize", runOld.getFontSize());
            //mapAttr.put("Subscript", runOld.getSubscript());
            //mapAttr.put("FontFamily",runOld.getFontFamily());
            return mapAttr;
        }
        
        public static XWPFRun setWordXWPFRunStyle(XWPFRun runNew,Map mapAttr,String text,boolean flag){
            runNew.setText(text);
/*            runNew.setColor((String) mapAttr.get("Color"));
            if("-1".equals(mapAttr.get("FontSize").toString())){//处理小四字号读取为-1的问题
                runNew.setFontSize(12);
            }else{
                runNew.setFontSize((Integer) mapAttr.get("FontSize"));
            }
            //runNew.setBold(flag);
            runNew.setSubscript((VerticalAlign) mapAttr.get("Subscript"));
            runNew.setFontFamily((String) mapAttr.get("FontFamily"));*/
            runNew.setUnderline((UnderlinePatterns) mapAttr.get("Underline"));
            return runNew;
        }
        
        /**
         * 替换图片
         * @param document
         * @param id
         * @param width
         * @param height
         */
        public static void updatePicture(XWPFDocument document,int id, int width, int height) {
            if(id==0){
                id = document.getAllPictures().size()-1;
            }
            final int EMU = 9525;
            width *= EMU;
            height *= EMU;
            String blipId = document.getAllPictures().get(id).getPackageRelationship()
                    .getId();
            CTInline inline = document.createParagraph().createRun().getCTR()
                    .addNewDrawing().addNewInline();
            
            String picXml = ""
                    + ""
                    + "   "
                    + "      "
                    + "         " + "         "  
                    + id
                    + "\" name=\"Generated\"/>"
                    + "            "
                    + "         "
                    + "         "
                    + "           "
                    + blipId
                    + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
                    + "            "
                    + "               "
                    + "            "
                    + "         "
                    + "         "
                    + "            "
                    + "               "
                    + "              "
                    + width
                    + "\" cy=\""
                    + height
                    + "\"/>"
                    + "            "
                    + "            "
                    + "               "
                    + "            "
                    + "         "
                    + "      "
                    + "   " + "";
            // CTGraphicalObjectData graphicData =
            inline.addNewGraphic().addNewGraphicData();
            XmlToken xmlToken = null;
            try {
                xmlToken = XmlToken.Factory.parse(picXml);
            } catch (XmlException xe) {
                xe.printStackTrace();
            }
            inline.set(xmlToken);
            // graphicData.set(xmlToken);
            inline.setDistT(0);
            inline.setDistB(0);
            inline.setDistL(0);
            inline.setDistR(0);
            CTPositiveSize2D extent = inline.addNewExtent();
            extent.setCx(width);
            extent.setCy(height);
            CTNonVisualDrawingProps docPr = inline.addNewDocPr();
            docPr.setId(id);
            docPr.setName("IMG_" + id);
            docPr.setDescr("IMG_" + id);
        }
        
        
        public static void addPictureToWord(XWPFDocument document,String imagePath,int imageType,int width,int height){
            if(0==imageType){
                imageType=XWPFDocument.PICTURE_TYPE_JPEG;
            }
            try {
                String ind = document.addPictureData(new FileInputStream(imagePath), imageType);
            } catch (InvalidFormatException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            updatePicture(document,document.getAllPictures().size()-1,400,400);
        }
        
        public static void addParagraphToWord(XWPFDocument document,String text,int fontSize,int alignment,String RGBColor,boolean isBold){
            XWPFParagraph paragraph = document.createParagraph();
            if(1==alignment){
                paragraph.setAlignment(ParagraphAlignment.CENTER);
            }else if(2==alignment){
                paragraph.setAlignment(ParagraphAlignment.CENTER);
            }else if(3==alignment){
                paragraph.setAlignment(ParagraphAlignment.RIGHT);
            }else{
                paragraph.setIndentationLeft(alignment);
            }
            XWPFRun runOne = paragraph.createRun();
            runOne.setText(text);
            runOne.setBold(isBold);
            runOne.setFontSize(fontSize);
            if(RGBColor.startsWith("#")){
                runOne.setColor(RGBColor.substring(1));
            }else{
                runOne.setColor(RGBColor);
            }
        }
        
        
        public static void addRunToParagraph(XWPFParagraph paragraph,String text,int fontSize,String RGBColor,boolean isBold,boolean isWrap){
            XWPFRun runText = paragraph.createRun();
//            runText.setStrike(true);  //删除线
            runText.setBold(isBold);
            runText.setColor(RGBColor);
            runText.setFontSize(fontSize);
            runText.setText(text);
            if(isWrap)runText.addBreak();
        }
        
        
        public static void replaceTextToImage(XWPFDocument document,Map<String,String> mapImage,int width,int height){
                List listRun;
                List<XWPFParagraph> listParagraphs = document.getParagraphs();
                for (int sa = 0; sa < listParagraphs.size(); sa++) {
                    for (String e : mapImage.keySet()) {
                    	String str = listParagraphs.get(sa).getText();
                    	//logger.info("imgstr XWPFParagraph ="+str);
                        if (str.indexOf(e) != -1) {
                            listRun = listParagraphs.get(sa).getRuns();
                            for (int p = 0; p < listRun.size(); p++) {
                            	String strp = listRun.get(p).toString();
                            	//logger.info("img========="+str);
                                if (strp.indexOf(e) > -1) {
                                    listParagraphs.get(sa).removeRun(p);//移除占位符
                                    //获得当前CTInline
                                    CTInline inline = listParagraphs.get(sa).createRun().getCTR().addNewDrawing().addNewInline();
                                    try {
                                        insertPicture(document,mapImage.get(e),inline,width,height);
                                    } catch (InvalidFormatException e1) {
                                        e1.printStackTrace();
                                    } catch (FileNotFoundException e1) {
                                        e1.printStackTrace();
                                    }
                                }
                            }
                        }
                    }
                }
        }
        
        public static void insertPicture(XWPFDocument document,String filePath,CTInline inline,int width, int height) throws InvalidFormatException, FileNotFoundException{
             // byte[]
        	String ind =document.addPictureData(openFile(filePath), 5);
        	
        	//String ind = document.addPictureData(new FileInputStream(filePath), 5);
                int id = document.getAllPictures().size()-1;
                final int EMU = 9525;
                width *= EMU;
                height *= EMU;
                String blipId = document.getAllPictures().get(id).getPackageRelationship()
                        .getId();
                String picXml = ""    
                        + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"    
                        + "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"    
                        + "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"    
                        + "         <pic:nvPicPr>" + "            <pic:cNvPr id=\""    
                        + id    
                        + "\" name=\"Generated\"/>"    
                        + "            <pic:cNvPicPr/>"    
                        + "         </pic:nvPicPr>"    
                        + "         <pic:blipFill>"    
                        + "            <a:blip r:embed=\""    
                        + blipId    
                        + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"    
                        + "            <a:stretch>"    
                        + "               <a:fillRect/>"    
                        + "            </a:stretch>"    
                        + "         </pic:blipFill>"    
                        + "         <pic:spPr>"    
                        + "            <a:xfrm>"    
                        + "               <a:off x=\"0\" y=\"0\"/>"    
                        + "               <a:ext cx=\""    
                        + width    
                        + "\" cy=\""    
                        + height    
                        + "\"/>"    
                        + "            </a:xfrm>"    
                        + "            <a:prstGeom prst=\"rect\">"    
                        + "               <a:avLst/>"    
                        + "            </a:prstGeom>"    
                        + "         </pic:spPr>"    
                        + "      </pic:pic>"    
                        + "   </a:graphicData>" + "</a:graphic>";  
                
                inline.addNewGraphic().addNewGraphicData();
                XmlToken xmlToken = null;
                try {
                    xmlToken = XmlToken.Factory.parse(picXml);
                } catch (XmlException xe) {
                    xe.printStackTrace();
                }
                inline.set(xmlToken);
                inline.setDistT(0);
                inline.setDistB(0);
                inline.setDistL(0);
                inline.setDistR(0);
                CTPositiveSize2D extent = inline.addNewExtent();
                extent.setCx(width);
                extent.setCy(height);
                CTNonVisualDrawingProps docPr = inline.addNewDocPr();
                docPr.setId(id);
                docPr.setName("IMG_" + id);
                docPr.setDescr("IMG_" + id);
        }
        
        public static void main(String[] args) {
            HashMap<String,String> param = new HashMap<String,String>();
            HashMap<String,String> mapImage = new HashMap<String,String>();
	        param.put("${candName}", "huangqiqing");  
	        param.put("${postName}", "信息管理与信息系统");  
	        param.put("${candSex}", "男");  
	        param.put("${candRegisterAddress}", "山东财经大学");  
	        param.put("${peple}", "王麻子"); 
	        param.put("${candIdentityCard}","421003199905023219");
	        param.put("${candEmergencyTelephone}","15600139682");
	        param.put("${pdetBedate}","2015年12月1日");
	        param.put("${pdetEndate}","2015年12月15日");
	        param.put("${pdetProbationaryEdate}","2015年10月1日");
	        param.put("${pdetAformalDate}","2015年10月15日");
            mapImage.put("${img}", "C:\\Users\\qk203\\Desktop\\1.jpg");
            String srcPath = "D:\\tmp\\upload_file\\pact\\pact-151109160601.docx";
            String destPath = "D:\\tmp\\upload_file\\sinfo-p-tmp\\test.docx";
            searchAndReplace(srcPath, destPath, param,mapImage);
        }

        
    	/**
    	 * word 参数动态替换 2007 .docx
    	 * 
    	 * @param pactUrl word模板路径
    	 * @param pactTargetul 替换后生成的word文件路径
    	 * @param pactTargetName word文件名称
    	 * @param signatureUrl 电子签名图片
    	 * @param param 替换参数
    	 * 	@return 替换后生成word的文件路径名称
    	 * @throws FileNotFoundException
    	 * @throws IOException
    	 */
		public static String wordReplace(String pactUrl, String pactTargetul,
				String pactTargetName, String signatureUrl,
				Map<String, String> param) {
			HashMap<String,String> mapImage = new HashMap<String,String>();
			if(!StringUtils.isEmpty(signatureUrl)){
				signatureUrl=signatureUrl.substring(signatureUrl.lastIndexOf("/"));
				String netUrl = PropertiesUtil.getProperty("NetFileUrl") + Constant.FILEPATH.CAND_SIGNATURE + signatureUrl;
				mapImage.put("${img}",netUrl);
				//mapImage.put("${img}", "d:\\1.jpg");
			}
			File file = new File(pactTargetul);
			if(!file.exists()){
				file.mkdir();
			}
			file =null;
			searchAndReplace(pactUrl, pactTargetul+pactTargetName, param,mapImage);
			return pactTargetul+pactTargetName;
		}
		
		private static InputStream openFile(String filePath) {
	        int HttpResult; // 服务器返回的状态
	        //String ee = new String();
	        //InputStreamReader isReader =null;
	        try 
	        {
	            URL url =new URL(filePath); // 创建URL
	            URLConnection urlconn = url.openConnection(); // 试图连接并取得返回状态码
	            urlconn.connect();
	            HttpURLConnection httpconn =(HttpURLConnection)urlconn;
	            HttpResult = httpconn.getResponseCode();
	            if(HttpResult != HttpURLConnection.HTTP_OK){
	            	logger.info("url.openConnection 数据签名图片无法连接到");// 不等于HTTP_OK说明连接不成功
	            } 
	            else
	            {
	            	return urlconn.getInputStream();
	           /* int filesize = urlconn.getContentLength(); // 取数据长度
	               isReader = new InputStreamReader();
	                BufferedReader reader = new BufferedReader(isReader);
	                StringBuffer buffer = new StringBuffer();
	                String line; // 用来保存每行读取的内容
	                line = reader.readLine(); // 读取第一行
	                while (line != null) { // 如果 line 为空说明读完了
	                    buffer.append(line); // 将读到的内容添加到 buffer 中
	                    buffer.append(" "); // 添加换行符
	                    line = reader.readLine(); // 读取下一行
	                }
	                ee = buffer.toString();*/
	            }
	        } 
	        catch (Exception e) {
	        	logger.error("openFile Exception e:",e);
	        } 
	        return  null;
	    }
	    
    public static String repalceImage(String source,String target){
    	//String str ="asdfsadafsadfasdf<img src=\"D:\\tmp\\upload_file\\info-p-view/word/media/image1.jpeg\" width=\"112.5pt\" height=\"45.0pt\"/>";
		String str = source;
    	int start=str.indexOf("<img src=\"");
		start+=10;
		int end =str.indexOf(".jpeg");
		end+=5;
		String temp = str.substring(start, end);
		temp=str.replace(temp, target);
    	return temp;
    }
}



注:支持office2007版本,poi版本为3.12

猜你喜欢

转载自zl-go.iteye.com/blog/2267814