TIFF属于一种高清图片格式,分辨率非常高,在CKFinder上传中会出现问题,查阅CF源码发现使用ImageIO上传图片数据,一般的JPG等格式是完全没问题的,但是在上传TIFF格式且提交较大时(达到1M以上就会报错,但是其他格式的完全不会)会报错内存溢出,但不是显示具体错误信息。
我们先采用两种方式解决问题:
第一种方式,就是修改CF的源代码,在上传TIFF格式图片的时候,保留TIFF格式的图片,同时将其转换为JPG格式的图片,这个是没有任何问题的。
第二种方式,尚未实现,需要解决CF缩略图模式下TIFF不支持预览问题。
CKFinder版本:2.3
解决方法一:TIFF数据格式图片转换JPG格式,同时保留原格式TIFF
WEB-INF/ckfinder.xml,添加tif格式,允许上传tif格式图片数据。
%BASE_URL%images/
%BASE_DIR%images
100M
bmp,gif,jpeg,jpg,png,tif
下载CKFinder 2.3版本的java源代码(注意对应Jeesite里面的版本),地址如下:
https://ckeditor.com/ckeditor-4/ckfinder/changelog/
直接将整个类文件复制到工程中,包含完整的包路径。
这里只要关注ImageIO这个方法,因为只要涉及到此方法都会报错,所以在ImageIO运行前就做格式判断,并强制取消对TIFF格式的数据验证,在createTmpThumb方法中,这里对图片进行上传操作,所以单独对TIFF格式数据进行格式转换成JPG进行存储即可。
PS:目前只做简单的处理,只能说勉强能用,后续再对第二种方法进行研究。
/*
* CKFinder
* ========
* http://ckfinder.com
* Copyright (C) 2007-2012, CKSource - Frederico Knabben. All rights reserved.
*
* The software, this file and its contents are subject to the CKFinder
* License. Please read the license.txt file before using, installing, copying,
* modifying or distribute this file or part of its contents. The contents of
* this file is part of the Source Code of CKFinder.
*/
package com.ckfinder.connector.utils;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
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.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.fileupload.FileItem;
import com.ckfinder.connector.configuration.IConfiguration;
import com.sun.media.jai.codec.FileCacheSeekableStream;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageEncoder;
import com.sun.media.jai.codec.JPEGEncodeParam;
import com.sun.media.jai.codec.TIFFEncodeParam;
/**
* Utils to operate on images.
*/
public class ImageUtils {
/**
* allowed image extensions.
*/
private static final String[] ALLOWED_EXT = { "gif", "jpeg", "jpg", "png",
"psd", "bmp", "tiff", "tif", "swc", "jpc", "jp2", "jpx", "jb2",
"xbm", "wbmp" };
private static final int MAX_BUFF_SIZE = 1024;
private static boolean prefix_tiff = false;
/**
* Resizes the image and writes it to the disk.
*
* @param sourceImage
* orginal image file.
* @param width
* requested width
* @param height
* requested height
* @param quality
* requested destenation file quality
* @param destFile
* file to write to
* @throws IOException
* when error occurs.
*/
private static void resizeImage(final BufferedImage sourceImage, final int width,
final int height, final float quality,
final File destFile) throws IOException {
try {
Thumbnails.of(sourceImage).size(width, height).keepAspectRatio(false)
.outputQuality(quality).toFile(destFile);
// for some special files outputQuality couses error:
//IllegalStateException inner Thumbnailator jar. When exception is thrown
// image is resized without quality
// When http://code.google.com/p/thumbnailator/issues/detail?id=9
// will be fixed this try catch can be deleted. Only:
//Thumbnails.of(sourceImage).size(width, height).keepAspectRatio(false)
//.outputQuality(quality).toFile(destFile);
// should remain.
} catch (IllegalStateException e) {
Thumbnails.of(sourceImage).size(width, height).keepAspectRatio(false)
.toFile(destFile);
}
}
/**
* create thumb file.
*
* @param orginFile
* orgin image file.
* @param file
* file to save thumb
* @param conf
* connector configuration
* @throws IOException
* when error occurs.
*/
public static void createThumb(final File orginFile, final File file,
final IConfiguration conf) throws IOException {
BufferedImage image = ImageIO.read(orginFile);
if (image != null) {
Dimension dimension = createThumbDimension(image,
conf.getMaxThumbWidth(), conf.getMaxThumbHeight());
FileUtils.createPath(file, conf, true);
if (image.getHeight() == dimension.height
&& image.getWidth() == dimension.width) {
writeUntouchedImage(orginFile, file);
} else {
resizeImage(image, dimension.width, dimension.height,
conf.getThumbsQuality(), file);
}
} else {
if (conf.isDebugMode()) {
throw new IOException("Wrong image file");
}
}
}
/**
* Uploads image and if the image size is larger than maximum allowed it
* resizes the image.
*
* @param stream
* input stream.
* @param file
* file name
* @param fileName
* name of file
* @param conf
* connector configuration
* @throws IOException
* when error occurs.
* 20180105 update method - upload 2 files, one of JPEG, one of TIFF
*/
public static void createTmpThumb(final InputStream stream,
final File file, final String fileName, final IConfiguration conf)
throws IOException {
if(prefix_tiff){
//System.out.println(file.getAbsolutePath());
//System.out.println(file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")));
FileCacheSeekableStream stream1 = new FileCacheSeekableStream(stream);
PlanarImage in = JAI.create("stream", stream1);
String newFilePath = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")) + ".jpg";
OutputStream osJPEG = new FileOutputStream(newFilePath);
JPEGEncodeParam JPEGparam = new JPEGEncodeParam();
ImageEncoder encJPEG = ImageCodec.createImageEncoder("JPEG", osJPEG, JPEGparam);
OutputStream osTIFF = new FileOutputStream(file);
TIFFEncodeParam TIFFparam = new TIFFEncodeParam();
TIFFparam.setCompression(TIFFEncodeParam.COMPRESSION_NONE);
ImageEncoder encTIFF = ImageCodec.createImageEncoder("TIFF", osTIFF, TIFFparam);
try {
encJPEG.encode(in);
osJPEG.flush();
osJPEG.close();
encTIFF.encode(in);
osTIFF.flush();
osTIFF.close();
stream.close();
} catch (IOException e) {
throw new IOException("Wrong file");
}
} else {
BufferedInputStream bufferedIS = new BufferedInputStream(stream);
bufferedIS.mark(Integer.MAX_VALUE);
BufferedImage image = ImageIO.read(bufferedIS);
if (image == null) {
throw new IOException("Wrong file");
}
Dimension dimension = createThumbDimension(image, conf.getImgWidth(),
conf.getImgHeight());
if (image.getHeight() == dimension.height
&& image.getWidth() == dimension.width) {
bufferedIS.reset();
writeUntouchedImage(bufferedIS, file);
} else {
resizeImage(image, dimension.width, dimension.height,
conf.getImgQuality(), file);
}
stream.close();
}
}
/**
* Creates image file with fixed width and height.
*
* @param sourceFile
* input file
* @param destFile
* file to save
* @param width
* image width
* @param height
* image height
* @param quality
* image quality
* @throws IOException
* when error occurs.
*/
public static void createResizedImage(final File sourceFile,
final File destFile, final int width, final int height,
final float quality) throws IOException {
BufferedImage image = ImageIO.read(sourceFile);
Dimension dimension = new Dimension(width, height);
if (image.getHeight() == dimension.height
&& image.getWidth() == dimension.width) {
writeUntouchedImage(sourceFile, destFile);
} else {
resizeImage(image, dimension.width, dimension.height, quality,
destFile);
}
}
/**
* creates dimension of thumb.
*
* @param image
* orginal image.
* @param maxWidth
* max thumb width
* @param maxHeight
* max thumb height
* @return dimension of thumb image.
*/
private static Dimension createThumbDimension(final BufferedImage image,
final int maxWidth, final int maxHeight) {
Dimension dimension = new Dimension();
if (image.getWidth() >= image.getHeight()) {
if (image.getWidth() >= maxWidth) {
dimension.width = maxWidth;
dimension.height = Math.round(((float) maxWidth / image
.getWidth()) * image.getHeight());
} else {
dimension.height = image.getHeight();
dimension.width = image.getWidth();
}
} else {
if (image.getHeight() >= maxHeight) {
dimension.height = maxHeight;
dimension.width = Math.round((((float) maxHeight / image
.getHeight()) * image.getWidth()));
} else {
dimension.height = image.getHeight();
dimension.width = image.getWidth();
}
}
return dimension;
}
/**
* checks if file is image.
*
* @param file
* file to check
* @return true if file is image.
*/
public static boolean isImage(final File file) {
List list = Arrays.asList(ALLOWED_EXT);
String fileExt = null;
if (file != null) {
fileExt = FileUtils.getFileExtension(file.getName().toLowerCase());
return (fileExt != null) ? list.contains(fileExt) : false;
} else {
return false;
}
}
/**
* check if image size isn't bigger then bigest allowed.
*
* @param stream
* temp file input stream.
* @param conf
* connector configuration.
* @return true if image size isn't bigger then bigest allowe.
* @throws IOException
* when error occurs during reading image.
*/
public static boolean checkImageSize(final InputStream stream,
final IConfiguration conf) throws IOException {
if(!prefix_tiff){
BufferedImage bi = ImageIO.read(stream);
stream.close();
if (bi == null) {
return false;
}
if (bi.getHeight() > conf.getImgHeight()
|| bi.getWidth() > conf.getImgWidth()) {
return false;
}
}
return true;
}
/**
* checks if image file is image.
*
* @param item
* file upload item
* @return true if file is image.
*/
public static boolean checkImageFile(final FileItem item) {
BufferedImage bi;
InputStream is = null;
if(item.getContentType().equals("image/tiff")){
prefix_tiff = true;
return true;
} else {
prefix_tiff = false;
try {
is = item.getInputStream();
bi = ImageIO.read(is);
} catch (IOException e) {
return false;
} finally {
if (is != null){
try { is.close(); } catch (Exception e) {}
}
}
return (bi != null);
}
}
/**
* writes unchanged file to disk.
*
* @param sourceFile
* - file to read from
*
* @param destFile
* - file to write to
*
* @throws IOException
* when error occurs.
*/
private static void writeUntouchedImage(final File sourceFile, final File destFile)
throws IOException {
FileInputStream fileIS = new FileInputStream(sourceFile);
writeUntouchedImage(fileIS, destFile);
}
/**
* writes unchanged file to disk.
*
* @param stream
* - stream to read the file from
*
* @param destFile
* - file to write to
*
* @throws IOException
* when error occurs.
*/
private static void writeUntouchedImage(final InputStream stream, final File destFile)
throws IOException {
ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
byte[] buffer = new byte[MAX_BUFF_SIZE];
int readNum = -1;
while ((readNum = stream.read(buffer)) != -1) {
byteArrayOS.write(buffer, 0, readNum);
}
byte[] bytes = byteArrayOS.toByteArray();
byteArrayOS.close();
FileOutputStream fileOS = new FileOutputStream(destFile);
fileOS.write(bytes);
fileOS.flush();
fileOS.close();
}
}