目录
4.坑,windows下,ImageIO 不支持真正的tif文件
com.sun.media.jai.codec.ImageCodec;
com.sun.media.jai.codecimpl.TIFFCodec;
====
■合并后的效果
===
3.png,4.png ⇒ 12.tif
■Java代码实现
1.Maven
<!-- tif 合并 -->
<dependencies>
<dependency>
<groupId>com.sun.media</groupId>
<artifactId>jai-codec</artifactId>
<version>1.1.3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>mvnrepository</id>
<name>mvnrepository</name>
<url>https://repository.jboss.org/maven2/</url>
</repository>
</repositories>
Index of /com/sun/media/jai-codec/1.1.3
---
可以正常下载到本地
2.代码
package com.sxz.test;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageEncoder;
import com.sun.media.jai.codec.TIFFEncodeParam;
public class TifUtils {
/**
* tif合并
**/
public static byte[] margerTif(List<byte[]> bytes){
ByteArrayInputStream bin = null;
List<BufferedImage> images = new ArrayList<BufferedImage> ();
for(byte[] b : bytes) {
try {
bin = new ByteArrayInputStream(b);
BufferedImage image = ImageIO.read(bin);
images.add(image);
bin.close();
}catch (Exception e) {
e.printStackTrace();
}
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
try{
TIFFEncodeParam params = new TIFFEncodeParam();
params.setCompression(TIFFEncodeParam.COMPRESSION_JPEG_TTN2);
ImageEncoder encoder = ImageCodec.createImageEncoder("tiff", out, params);
List<BufferedImage> imageList = new ArrayList<BufferedImage>();
for (int i = 1; i < images.size(); i++){
imageList.add(images.get(i));
}
params.setExtraImages(imageList.iterator());
encoder.encode(images.get(0));
}catch (Exception e){
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return out.toByteArray();
}
}
3.测试类
package com.sxz.test;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
File file1 = new File("C:\\TIF\\1.tif");
File file2 = new File("C:\\TIF\\2.tif");
FileOutputStream os;
try {
List<byte[]> list = new ArrayList();
list.add(Files.readAllBytes(file1.toPath()));
list.add(Files.readAllBytes(file2.toPath()));
byte[] b = TifUtils.margerTif(list);
os = new FileOutputStream(new File("C:\\TIF\\12.tif"));
os.write(b);
os.flush();
os.close();
}catch (Exception e){
e.printStackTrace();
} finally{
}
}
}
====
4.坑,windows下,ImageIO 不支持真正的tif文件
BufferedImage image = ImageIO.read(bin);
判断图片文件真实类型---通过文件表头判断。_sun0322-CSDN博客
返回值为null,出错原因
ImageIO.read() 返回 null_复利人生的博客-CSDN博客_imageio.read
for (int i = 0; i < ImageIO.getReaderFormatNames().length; i++) {
System.out.println(ImageIO.getReaderFormatNames()[i]);
}
---运行输出如下结果
JPG
jpg
bmp
BMP
gif
GIF
WBMP
png
PNG
jpeg
wbmp
JPEG
---linux中也不支持
sxz001@sxzap01:~$ cat /etc/redhat-release
cat: /etc/redhat-release: No such file or directory
sxz001@sxzap01:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.2 LTS
Release: 20.04
Codename: focal
sxz001@sxzap01:~$
sxz001@sxzap01:~$
sxz001@sxzap01:~$ clear
sxz001@sxzap01:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.2 LTS
Release: 20.04
Codename: focal
sxz001@sxzap01:~$
sxz001@sxzap01:~$
sxz001@sxzap01:~$ java com.sxz.test.Test
JPG
jpg
bmp
BMP
gif
GIF
WBMP
png
PNG
wbmp
jpeg
JPEG
sxz001@sxzap01:~$
sxz001@sxzap01:~$
sxz001@sxzap01:~$ uname -a
Linux sxzap01 5.4.0-72-generic #80-Ubuntu SMP Mon Apr 12 17:35:00 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
sxz001@sxzap01:~$
■VBA代码实现(最终解决方式)
=======
=======
■如何判断图片文件真实的类型
判断图片文件真实类型---通过文件表头判断。_sun0322-CSDN博客
■解决
解决ImageIO.read返回为null的问题_wxmgcs的专栏-CSDN博客_imageio.read返回null
■Jar中的一部分代码
com.sun.media.jai.codec.ImageCodec;
package com.sun.media.jai.codec;
import com.sun.media.jai.codecimpl.BMPCodec;
import com.sun.media.jai.codecimpl.FPXCodec;
import com.sun.media.jai.codecimpl.GIFCodec;
import com.sun.media.jai.codecimpl.ImagingListenerProxy;
import com.sun.media.jai.codecimpl.JPEGCodec;
import com.sun.media.jai.codecimpl.PNGCodec;
import com.sun.media.jai.codecimpl.PNMCodec;
import com.sun.media.jai.codecimpl.TIFFCodec;
import com.sun.media.jai.codecimpl.WBMPCodec;
import com.sun.media.jai.codecimpl.util.FloatDoubleColorModel;
import com.sun.media.jai.util.SimpleCMYKColorSpace;
import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
public abstract class ImageCodec {
private static Hashtable codecs = new Hashtable();
private static final byte[][] grayIndexCmaps;
private static final int[] GrayBits8;
private static final ComponentColorModel colorModelGray8;
private static final int[] GrayAlphaBits8;
private static final ComponentColorModel colorModelGrayAlpha8;
private static final int[] GrayBits16;
private static final ComponentColorModel colorModelGray16;
private static final int[] GrayAlphaBits16;
private static final ComponentColorModel colorModelGrayAlpha16;
private static final int[] GrayBits32;
private static final ComponentColorModel colorModelGray32;
private static final int[] GrayAlphaBits32;
private static final ComponentColorModel colorModelGrayAlpha32;
private static final int[] RGBBits8;
private static final ComponentColorModel colorModelRGB8;
private static final int[] RGBABits8;
private static final ComponentColorModel colorModelRGBA8;
private static final int[] RGBBits16;
private static final ComponentColorModel colorModelRGB16;
private static final int[] RGBABits16;
private static final ComponentColorModel colorModelRGBA16;
private static final int[] RGBBits32;
private static final ComponentColorModel colorModelRGB32;
private static final int[] RGBABits32;
private static final ComponentColorModel colorModelRGBA32;
public static ImageCodec getCodec(String name) {
return (ImageCodec) codecs.get(name.toLowerCase());
}
public static void registerCodec(ImageCodec codec) {
codecs.put(codec.getFormatName().toLowerCase(), codec);
}
public static void unregisterCodec(String name) {
codecs.remove(name.toLowerCase());
}
public static Enumeration getCodecs() {
return codecs.elements();
}
public static ImageEncoder createImageEncoder(String name, OutputStream dst, ImageEncodeParam param) {
ImageCodec codec = getCodec(name);
return codec == null ? null : codec.createImageEncoder(dst, param);
}
public static ImageDecoder createImageDecoder(String name, InputStream src, ImageDecodeParam param) {
ImageCodec codec = getCodec(name);
return codec == null ? null : codec.createImageDecoder(src, param);
}
public static ImageDecoder createImageDecoder(String name, File src, ImageDecodeParam param) throws IOException {
ImageCodec codec = getCodec(name);
return codec == null ? null : codec.createImageDecoder(src, param);
}
public static ImageDecoder createImageDecoder(String name, SeekableStream src, ImageDecodeParam param) {
ImageCodec codec = getCodec(name);
return codec == null ? null : codec.createImageDecoder(src, param);
}
private static String[] vectorToStrings(Vector nameVec) {
int count = nameVec.size();
String[] names = new String[count];
for (int i = 0; i < count; ++i) {
names[i] = (String) nameVec.elementAt(i);
}
return names;
}
public static String[] getDecoderNames(SeekableStream src) {
if (!src.canSeekBackwards() && !src.markSupported()) {
throw new IllegalArgumentException(JaiI18N.getString("ImageCodec2"));
} else {
Enumeration enumeration = codecs.elements();
Vector nameVec = new Vector();
Object var3 = null;
while (true) {
ImageCodec codec;
int bytesNeeded;
do {
if (!enumeration.hasMoreElements()) {
return vectorToStrings(nameVec);
}
codec = (ImageCodec) enumeration.nextElement();
bytesNeeded = codec.getNumHeaderBytes();
} while (bytesNeeded == 0 && !src.canSeekBackwards());
try {
if (bytesNeeded > 0) {
src.mark(bytesNeeded);
byte[] header = new byte[bytesNeeded];
src.readFully(header);
src.reset();
if (codec.isFormatRecognized(header)) {
nameVec.add(codec.getFormatName());
}
} else {
long pointer = src.getFilePointer();
src.seek(0L);
if (codec.isFormatRecognized(src)) {
nameVec.add(codec.getFormatName());
}
src.seek(pointer);
}
} catch (IOException var8) {
ImagingListenerProxy.errorOccurred(JaiI18N.getString("ImageCodec3"), var8,
class$com$sun$media$jai$codec$ImageCodec == null
? (class$com$sun$media$jai$codec$ImageCodec = class$(
"com.sun.media.jai.codec.ImageCodec"))
: class$com$sun$media$jai$codec$ImageCodec,
false);
}
}
}
}
public static String[] getEncoderNames(RenderedImage im, ImageEncodeParam param) {
Enumeration enumeration = codecs.elements();
Vector nameVec = new Vector();
Object var4 = null;
while (enumeration.hasMoreElements()) {
ImageCodec codec = (ImageCodec) enumeration.nextElement();
if (codec.canEncodeImage(im, param)) {
nameVec.add(codec.getFormatName());
}
}
return vectorToStrings(nameVec);
}
public abstract String getFormatName();
public int getNumHeaderBytes() {
return 0;
}
public boolean isFormatRecognized(byte[] header) {
throw new RuntimeException(JaiI18N.getString("ImageCodec0"));
}
public boolean isFormatRecognized(SeekableStream src) throws IOException {
throw new RuntimeException(JaiI18N.getString("ImageCodec1"));
}
protected abstract Class getEncodeParamClass();
protected abstract Class getDecodeParamClass();
protected abstract ImageEncoder createImageEncoder(OutputStream var1, ImageEncodeParam var2);
public abstract boolean canEncodeImage(RenderedImage var1, ImageEncodeParam var2);
protected ImageDecoder createImageDecoder(InputStream src, ImageDecodeParam param) {
SeekableStream stream = SeekableStream.wrapInputStream(src, true);
return this.createImageDecoder(stream, param);
}
protected ImageDecoder createImageDecoder(File src, ImageDecodeParam param) throws IOException {
return this.createImageDecoder((SeekableStream) (new FileSeekableStream(src)), param);
}
protected abstract ImageDecoder createImageDecoder(SeekableStream var1, ImageDecodeParam var2);
public static ColorModel createGrayIndexColorModel(SampleModel sm, boolean blackIsZero) {
if (sm.getNumBands() != 1) {
throw new IllegalArgumentException();
} else {
int sampleSize = sm.getSampleSize(0);
byte[] cmap = null;
int length;
byte[] cmap;
if (sampleSize < 8) {
cmap = grayIndexCmaps[sampleSize];
if (!blackIsZero) {
length = cmap.length;
byte[] newCmap = new byte[length];
for (int i = 0; i < length; ++i) {
newCmap[i] = cmap[length - i - 1];
}
cmap = newCmap;
}
} else {
cmap = new byte[256];
if (blackIsZero) {
for (length = 0; length < 256; ++length) {
cmap[length] = (byte) length;
}
} else {
for (length = 0; length < 256; ++length) {
cmap[length] = (byte) (255 - length);
}
}
}
return new IndexColorModel(sampleSize, cmap.length, cmap, cmap, cmap);
}
}
public static ColorModel createComponentColorModel(SampleModel sm) {
int type = sm.getDataType();
int bands = sm.getNumBands();
ComponentColorModel cm = null;
if (type == 0) {
switch (bands) {
case 1 :
cm = colorModelGray8;
break;
case 2 :
cm = colorModelGrayAlpha8;
break;
case 3 :
cm = colorModelRGB8;
break;
case 4 :
cm = colorModelRGBA8;
}
} else if (type == 1) {
switch (bands) {
case 1 :
cm = colorModelGray16;
break;
case 2 :
cm = colorModelGrayAlpha16;
break;
case 3 :
cm = colorModelRGB16;
break;
case 4 :
cm = colorModelRGBA16;
}
} else if (type == 3) {
switch (bands) {
case 1 :
cm = colorModelGray32;
break;
case 2 :
cm = colorModelGrayAlpha32;
break;
case 3 :
cm = colorModelRGB32;
break;
case 4 :
cm = colorModelRGBA32;
}
} else if (type == 4 && bands >= 1 && bands <= 4) {
ColorSpace cs = bands <= 2 ? ColorSpace.getInstance(1003) : ColorSpace.getInstance(1000);
boolean hasAlpha = bands % 2 == 0;
cm = new FloatDoubleColorModel(cs, hasAlpha, false, hasAlpha ? 3 : 1, 4);
}
return (ColorModel) cm;
}
public static ColorModel createComponentColorModel(SampleModel sm, ColorSpace cp) {
if (cp == null) {
return createComponentColorModel(sm);
} else {
int type = sm.getDataType();
int bands = sm.getNumBands();
ComponentColorModel cm = null;
int[] bits = null;
int transferType = -1;
boolean hasAlpha = bands % 2 == 0;
if (cp instanceof SimpleCMYKColorSpace) {
hasAlpha = false;
}
int transparency = hasAlpha ? 3 : 1;
if (type == 0) {
transferType = 0;
switch (bands) {
case 1 :
bits = GrayBits8;
break;
case 2 :
bits = GrayAlphaBits8;
break;
case 3 :
bits = RGBBits8;
break;
case 4 :
bits = RGBABits8;
}
} else if (type == 1) {
transferType = 1;
switch (bands) {
case 1 :
bits = GrayBits16;
break;
case 2 :
bits = GrayAlphaBits16;
break;
case 3 :
bits = RGBBits16;
break;
case 4 :
bits = RGBABits16;
}
} else if (type == 3) {
transferType = 3;
switch (bands) {
case 1 :
bits = GrayBits32;
break;
case 2 :
bits = GrayAlphaBits32;
break;
case 3 :
bits = RGBBits32;
break;
case 4 :
bits = RGBABits32;
}
}
if (type == 4 && bands >= 1 && bands <= 4) {
cm = new FloatDoubleColorModel(cp, hasAlpha, false, transparency, 4);
} else {
cm = new ComponentColorModel(cp, bits, hasAlpha, false, transparency, transferType);
}
return (ColorModel) cm;
}
}
public static boolean isIndicesForGrayscale(byte[] r, byte[] g, byte[] b) {
if (r.length == g.length && r.length == b.length) {
int size = r.length;
if (size != 256) {
return false;
} else {
for (int i = 0; i < size; ++i) {
byte temp = (byte) i;
if (r[i] != temp || g[i] != temp || b[i] != temp) {
return false;
}
}
return true;
}
} else {
return false;
}
}
static {
registerCodec(new BMPCodec());
registerCodec(new GIFCodec());
registerCodec(new FPXCodec());
registerCodec(new JPEGCodec());
registerCodec(new PNGCodec());
registerCodec(new PNMCodec());
registerCodec(new TIFFCodec());
registerCodec(new WBMPCodec());
grayIndexCmaps = new byte[][]{null, {0, -1}, {0, 85, -86, -1}, null,
{0, 17, 34, 51, 68, 85, 102, 119, -120, -103, -86, -69, -52, -35, -18, -1}};
GrayBits8 = new int[]{8};
colorModelGray8 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayBits8, false, false, 1, 0);
GrayAlphaBits8 = new int[]{8, 8};
colorModelGrayAlpha8 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayAlphaBits8, true, false, 3, 0);
GrayBits16 = new int[]{16};
colorModelGray16 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayBits16, false, false, 1, 1);
GrayAlphaBits16 = new int[]{16, 16};
colorModelGrayAlpha16 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayAlphaBits16, true, false, 3,
1);
GrayBits32 = new int[]{32};
colorModelGray32 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayBits32, false, false, 1, 3);
GrayAlphaBits32 = new int[]{32, 32};
colorModelGrayAlpha32 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayAlphaBits32, true, false, 3,
3);
RGBBits8 = new int[]{8, 8, 8};
colorModelRGB8 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBBits8, false, false, 1, 0);
RGBABits8 = new int[]{8, 8, 8, 8};
colorModelRGBA8 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBABits8, true, false, 3, 0);
RGBBits16 = new int[]{16, 16, 16};
colorModelRGB16 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBBits16, false, false, 1, 1);
RGBABits16 = new int[]{16, 16, 16, 16};
colorModelRGBA16 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBABits16, true, false, 3, 1);
RGBBits32 = new int[]{32, 32, 32};
colorModelRGB32 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBBits32, false, false, 1, 3);
RGBABits32 = new int[]{32, 32, 32, 32};
colorModelRGBA32 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBABits32, true, false, 3, 3);
}
}
---
com.sun.media.jai.codec;
package com.sun.media.jai.codec;
import com.sun.media.jai.codecimpl.BMPCodec;
import com.sun.media.jai.codecimpl.FPXCodec;
import com.sun.media.jai.codecimpl.GIFCodec;
import com.sun.media.jai.codecimpl.ImagingListenerProxy;
import com.sun.media.jai.codecimpl.JPEGCodec;
import com.sun.media.jai.codecimpl.PNGCodec;
import com.sun.media.jai.codecimpl.PNMCodec;
import com.sun.media.jai.codecimpl.TIFFCodec;
import com.sun.media.jai.codecimpl.WBMPCodec;
import com.sun.media.jai.codecimpl.util.FloatDoubleColorModel;
import com.sun.media.jai.util.SimpleCMYKColorSpace;
import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
public abstract class ImageCodec {
private static Hashtable codecs = new Hashtable();
private static final byte[][] grayIndexCmaps;
private static final int[] GrayBits8;
private static final ComponentColorModel colorModelGray8;
private static final int[] GrayAlphaBits8;
private static final ComponentColorModel colorModelGrayAlpha8;
private static final int[] GrayBits16;
private static final ComponentColorModel colorModelGray16;
private static final int[] GrayAlphaBits16;
private static final ComponentColorModel colorModelGrayAlpha16;
private static final int[] GrayBits32;
private static final ComponentColorModel colorModelGray32;
private static final int[] GrayAlphaBits32;
private static final ComponentColorModel colorModelGrayAlpha32;
private static final int[] RGBBits8;
private static final ComponentColorModel colorModelRGB8;
private static final int[] RGBABits8;
private static final ComponentColorModel colorModelRGBA8;
private static final int[] RGBBits16;
private static final ComponentColorModel colorModelRGB16;
private static final int[] RGBABits16;
private static final ComponentColorModel colorModelRGBA16;
private static final int[] RGBBits32;
private static final ComponentColorModel colorModelRGB32;
private static final int[] RGBABits32;
private static final ComponentColorModel colorModelRGBA32;
public static ImageCodec getCodec(String name) {
return (ImageCodec) codecs.get(name.toLowerCase());
}
public static void registerCodec(ImageCodec codec) {
codecs.put(codec.getFormatName().toLowerCase(), codec);
}
public static void unregisterCodec(String name) {
codecs.remove(name.toLowerCase());
}
public static Enumeration getCodecs() {
return codecs.elements();
}
public static ImageEncoder createImageEncoder(String name, OutputStream dst, ImageEncodeParam param) {
ImageCodec codec = getCodec(name);
return codec == null ? null : codec.createImageEncoder(dst, param);
}
public static ImageDecoder createImageDecoder(String name, InputStream src, ImageDecodeParam param) {
ImageCodec codec = getCodec(name);
return codec == null ? null : codec.createImageDecoder(src, param);
}
public static ImageDecoder createImageDecoder(String name, File src, ImageDecodeParam param) throws IOException {
ImageCodec codec = getCodec(name);
return codec == null ? null : codec.createImageDecoder(src, param);
}
public static ImageDecoder createImageDecoder(String name, SeekableStream src, ImageDecodeParam param) {
ImageCodec codec = getCodec(name);
return codec == null ? null : codec.createImageDecoder(src, param);
}
private static String[] vectorToStrings(Vector nameVec) {
int count = nameVec.size();
String[] names = new String[count];
for (int i = 0; i < count; ++i) {
names[i] = (String) nameVec.elementAt(i);
}
return names;
}
public static String[] getDecoderNames(SeekableStream src) {
if (!src.canSeekBackwards() && !src.markSupported()) {
throw new IllegalArgumentException(JaiI18N.getString("ImageCodec2"));
} else {
Enumeration enumeration = codecs.elements();
Vector nameVec = new Vector();
Object var3 = null;
while (true) {
ImageCodec codec;
int bytesNeeded;
do {
if (!enumeration.hasMoreElements()) {
return vectorToStrings(nameVec);
}
codec = (ImageCodec) enumeration.nextElement();
bytesNeeded = codec.getNumHeaderBytes();
} while (bytesNeeded == 0 && !src.canSeekBackwards());
try {
if (bytesNeeded > 0) {
src.mark(bytesNeeded);
byte[] header = new byte[bytesNeeded];
src.readFully(header);
src.reset();
if (codec.isFormatRecognized(header)) {
nameVec.add(codec.getFormatName());
}
} else {
long pointer = src.getFilePointer();
src.seek(0L);
if (codec.isFormatRecognized(src)) {
nameVec.add(codec.getFormatName());
}
src.seek(pointer);
}
} catch (IOException var8) {
ImagingListenerProxy.errorOccurred(JaiI18N.getString("ImageCodec3"), var8,
class$com$sun$media$jai$codec$ImageCodec == null
? (class$com$sun$media$jai$codec$ImageCodec = class$(
"com.sun.media.jai.codec.ImageCodec"))
: class$com$sun$media$jai$codec$ImageCodec,
false);
}
}
}
}
public static String[] getEncoderNames(RenderedImage im, ImageEncodeParam param) {
Enumeration enumeration = codecs.elements();
Vector nameVec = new Vector();
Object var4 = null;
while (enumeration.hasMoreElements()) {
ImageCodec codec = (ImageCodec) enumeration.nextElement();
if (codec.canEncodeImage(im, param)) {
nameVec.add(codec.getFormatName());
}
}
return vectorToStrings(nameVec);
}
public abstract String getFormatName();
public int getNumHeaderBytes() {
return 0;
}
public boolean isFormatRecognized(byte[] header) {
throw new RuntimeException(JaiI18N.getString("ImageCodec0"));
}
public boolean isFormatRecognized(SeekableStream src) throws IOException {
throw new RuntimeException(JaiI18N.getString("ImageCodec1"));
}
protected abstract Class getEncodeParamClass();
protected abstract Class getDecodeParamClass();
protected abstract ImageEncoder createImageEncoder(OutputStream var1, ImageEncodeParam var2);
public abstract boolean canEncodeImage(RenderedImage var1, ImageEncodeParam var2);
protected ImageDecoder createImageDecoder(InputStream src, ImageDecodeParam param) {
SeekableStream stream = SeekableStream.wrapInputStream(src, true);
return this.createImageDecoder(stream, param);
}
protected ImageDecoder createImageDecoder(File src, ImageDecodeParam param) throws IOException {
return this.createImageDecoder((SeekableStream) (new FileSeekableStream(src)), param);
}
protected abstract ImageDecoder createImageDecoder(SeekableStream var1, ImageDecodeParam var2);
public static ColorModel createGrayIndexColorModel(SampleModel sm, boolean blackIsZero) {
if (sm.getNumBands() != 1) {
throw new IllegalArgumentException();
} else {
int sampleSize = sm.getSampleSize(0);
byte[] cmap = null;
int length;
byte[] cmap;
if (sampleSize < 8) {
cmap = grayIndexCmaps[sampleSize];
if (!blackIsZero) {
length = cmap.length;
byte[] newCmap = new byte[length];
for (int i = 0; i < length; ++i) {
newCmap[i] = cmap[length - i - 1];
}
cmap = newCmap;
}
} else {
cmap = new byte[256];
if (blackIsZero) {
for (length = 0; length < 256; ++length) {
cmap[length] = (byte) length;
}
} else {
for (length = 0; length < 256; ++length) {
cmap[length] = (byte) (255 - length);
}
}
}
return new IndexColorModel(sampleSize, cmap.length, cmap, cmap, cmap);
}
}
public static ColorModel createComponentColorModel(SampleModel sm) {
int type = sm.getDataType();
int bands = sm.getNumBands();
ComponentColorModel cm = null;
if (type == 0) {
switch (bands) {
case 1 :
cm = colorModelGray8;
break;
case 2 :
cm = colorModelGrayAlpha8;
break;
case 3 :
cm = colorModelRGB8;
break;
case 4 :
cm = colorModelRGBA8;
}
} else if (type == 1) {
switch (bands) {
case 1 :
cm = colorModelGray16;
break;
case 2 :
cm = colorModelGrayAlpha16;
break;
case 3 :
cm = colorModelRGB16;
break;
case 4 :
cm = colorModelRGBA16;
}
} else if (type == 3) {
switch (bands) {
case 1 :
cm = colorModelGray32;
break;
case 2 :
cm = colorModelGrayAlpha32;
break;
case 3 :
cm = colorModelRGB32;
break;
case 4 :
cm = colorModelRGBA32;
}
} else if (type == 4 && bands >= 1 && bands <= 4) {
ColorSpace cs = bands <= 2 ? ColorSpace.getInstance(1003) : ColorSpace.getInstance(1000);
boolean hasAlpha = bands % 2 == 0;
cm = new FloatDoubleColorModel(cs, hasAlpha, false, hasAlpha ? 3 : 1, 4);
}
return (ColorModel) cm;
}
public static ColorModel createComponentColorModel(SampleModel sm, ColorSpace cp) {
if (cp == null) {
return createComponentColorModel(sm);
} else {
int type = sm.getDataType();
int bands = sm.getNumBands();
ComponentColorModel cm = null;
int[] bits = null;
int transferType = -1;
boolean hasAlpha = bands % 2 == 0;
if (cp instanceof SimpleCMYKColorSpace) {
hasAlpha = false;
}
int transparency = hasAlpha ? 3 : 1;
if (type == 0) {
transferType = 0;
switch (bands) {
case 1 :
bits = GrayBits8;
break;
case 2 :
bits = GrayAlphaBits8;
break;
case 3 :
bits = RGBBits8;
break;
case 4 :
bits = RGBABits8;
}
} else if (type == 1) {
transferType = 1;
switch (bands) {
case 1 :
bits = GrayBits16;
break;
case 2 :
bits = GrayAlphaBits16;
break;
case 3 :
bits = RGBBits16;
break;
case 4 :
bits = RGBABits16;
}
} else if (type == 3) {
transferType = 3;
switch (bands) {
case 1 :
bits = GrayBits32;
break;
case 2 :
bits = GrayAlphaBits32;
break;
case 3 :
bits = RGBBits32;
break;
case 4 :
bits = RGBABits32;
}
}
if (type == 4 && bands >= 1 && bands <= 4) {
cm = new FloatDoubleColorModel(cp, hasAlpha, false, transparency, 4);
} else {
cm = new ComponentColorModel(cp, bits, hasAlpha, false, transparency, transferType);
}
return (ColorModel) cm;
}
}
public static boolean isIndicesForGrayscale(byte[] r, byte[] g, byte[] b) {
if (r.length == g.length && r.length == b.length) {
int size = r.length;
if (size != 256) {
return false;
} else {
for (int i = 0; i < size; ++i) {
byte temp = (byte) i;
if (r[i] != temp || g[i] != temp || b[i] != temp) {
return false;
}
}
return true;
}
} else {
return false;
}
}
static {
registerCodec(new BMPCodec());
registerCodec(new GIFCodec());
registerCodec(new FPXCodec());
registerCodec(new JPEGCodec());
registerCodec(new PNGCodec());
registerCodec(new PNMCodec());
registerCodec(new TIFFCodec());
registerCodec(new WBMPCodec());
grayIndexCmaps = new byte[][]{null, {0, -1}, {0, 85, -86, -1}, null,
{0, 17, 34, 51, 68, 85, 102, 119, -120, -103, -86, -69, -52, -35, -18, -1}};
GrayBits8 = new int[]{8};
colorModelGray8 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayBits8, false, false, 1, 0);
GrayAlphaBits8 = new int[]{8, 8};
colorModelGrayAlpha8 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayAlphaBits8, true, false, 3, 0);
GrayBits16 = new int[]{16};
colorModelGray16 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayBits16, false, false, 1, 1);
GrayAlphaBits16 = new int[]{16, 16};
colorModelGrayAlpha16 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayAlphaBits16, true, false, 3,
1);
GrayBits32 = new int[]{32};
colorModelGray32 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayBits32, false, false, 1, 3);
GrayAlphaBits32 = new int[]{32, 32};
colorModelGrayAlpha32 = new ComponentColorModel(ColorSpace.getInstance(1003), GrayAlphaBits32, true, false, 3,
3);
RGBBits8 = new int[]{8, 8, 8};
colorModelRGB8 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBBits8, false, false, 1, 0);
RGBABits8 = new int[]{8, 8, 8, 8};
colorModelRGBA8 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBABits8, true, false, 3, 0);
RGBBits16 = new int[]{16, 16, 16};
colorModelRGB16 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBBits16, false, false, 1, 1);
RGBABits16 = new int[]{16, 16, 16, 16};
colorModelRGBA16 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBABits16, true, false, 3, 1);
RGBBits32 = new int[]{32, 32, 32};
colorModelRGB32 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBBits32, false, false, 1, 3);
RGBABits32 = new int[]{32, 32, 32, 32};
colorModelRGBA32 = new ComponentColorModel(ColorSpace.getInstance(1000), RGBABits32, true, false, 3, 3);
}
}
---
com.sun.media.jai.codecimpl.TIFFCodec;
package com.sun.media.jai.codecimpl;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageDecodeParam;
import com.sun.media.jai.codec.ImageDecoder;
import com.sun.media.jai.codec.ImageEncodeParam;
import com.sun.media.jai.codec.ImageEncoder;
import com.sun.media.jai.codec.SeekableStream;
import java.awt.image.RenderedImage;
import java.io.OutputStream;
public final class TIFFCodec extends ImageCodec {
public String getFormatName() {
return "tiff";
}
public Class getEncodeParamClass() {
return class$com$sun$media$jai$codec$TIFFEncodeParam == null
? (class$com$sun$media$jai$codec$TIFFEncodeParam = class$("com.sun.media.jai.codec.TIFFEncodeParam"))
: class$com$sun$media$jai$codec$TIFFEncodeParam;
}
public Class getDecodeParamClass() {
return class$com$sun$media$jai$codec$TIFFDecodeParam == null
? (class$com$sun$media$jai$codec$TIFFDecodeParam = class$("com.sun.media.jai.codec.TIFFDecodeParam"))
: class$com$sun$media$jai$codec$TIFFDecodeParam;
}
public boolean canEncodeImage(RenderedImage im, ImageEncodeParam param) {
return true;
}
protected ImageEncoder createImageEncoder(OutputStream dst, ImageEncodeParam param) {
return new TIFFImageEncoder(dst, param);
}
protected ImageDecoder createImageDecoder(SeekableStream src, ImageDecodeParam param) {
return new TIFFImageDecoder(src, param);
}
public int getNumHeaderBytes() {
return 4;
}
public boolean isFormatRecognized(byte[] header) {
if (header[0] == 73 && header[1] == 73 && header[2] == 42 && header[3] == 0) {
return true;
} else {
return header[0] == 77 && header[1] == 77 && header[2] == 0 && header[3] == 42;
}
}
}
---
■TIF图像的读取
====
・TIF的存储结构
TIFF⽂件以.tif为扩展名。其数据格式是⼀种3级体系结构,从⾼到低依次为:⽂件头、⼀个或多个称为IFD的包含标记指针的⽬录和数据。
====
【1.⽂件头(IFH)】
在每⼀个TIFF⽂件中第⼀个数据结构称为图像⽂件头或IFH,它是图像⽂件体系结构的最⾼层。这个结构在⼀个TIFF⽂件中是惟⼀的,
有固定的位置。它位于⽂件的开始部分,包含了正确解释TIFF⽂件的其他部分所需的必要信息。
IFH数据结构包含3个成员共计8个字节,Byte order成员可能是“MM”(0x4d4d)或“II”(0x4949),0x4d4d表⽰该TIFF图是摩托罗拉整数格式
0x4949表⽰该图是Intel整数格式;Version成员总是包含⼗进制42(0x2a),它⽤于进⼀步校验该⽂件是否为TIF格式,42这个数并不是⼀般
⼈想象中的那样认为是tif软件的版本,实际上,42这个数⼤概永远不会变化;第三个成员是IFD(接下来要说的第⼆个数据结构)相对⽂件
开始处的偏移量。
【2.图像⽂件⽬录(IFD)】
IFD是TIFF⽂件中第2个数据结构,它是⼀个名为标记(tag)的⽤于区分⼀个或多个可变长度数据块的表,标记中包含了有关于图像的所
有信息。IFD提供了⼀系列的指针(索引),这些指针告诉我们各种有关的数据字段在⽂件中的开始位置,并给出每个字段的数据类型及长度。
这种⽅法允许数据字段定位在⽂件的任何地⽅,且可以是任意长度,因此⽂件格式⼗分灵活。
IFD是TIF图中最重要的数据结构,它包含了⼀个TIF⽂件中最重要的信息,★★★⼀个TIF图可能有多个IFD,这说明⽂件中有多个图像★★★,
每个IFD标识1个图像的基本属性。 IFD结构中包含了三类成员,Directory Entry Count指出该结构⾥⾯有多少个⽬录⼊⼝;接下来就是N个线性
排列的DE序列,数量不定(这就是为什么称TIF格式⽂件为可扩充标记的⽂件,甚⾄⽤户可以添加⾃定义的标记属性),每个DE标识了图
像的某⼀个属性;最后就是⼀个偏移量,标识下⼀个⽂件⽬录相对于⽂件开始处的位置,当然,如果该TIF⽂件只包含了⼀幅图像,那么就
只有⼀个IFD,显然,这个偏移量就等于0;
共12个字节,。简单说,⼀个DE就是⼀幅图像的某⼀个属性。例如图像的⼤⼩、分辨率、是否压缩、像素的⾏列数、⼀个像素由⼏
位表⽰(1位代表⿊⽩两⾊,8位代表256⾊等等)等。其中:tag成员是该属性的编号,在图像⽂件⽬录中,它是按照升序排列的。我们可
以通过读这些编号,然后到TIF格式官⽅⽩⽪书中查找相应的含义。属性是⽤数据来表⽰的,那么type就是代表着该数据的类型,TIF官⽅指
定的有5种数据类型。type=1就是BYTE类型(8位⽆标记整数)、type=2是ASCII类型(7位ASCII码加1位⼆进制0)、type=3是SHORT类
型(16位⽆标记整数)、type=4是LONG 类型(32位⽆标记整数)、type=5是RATIONAL类型(2个LONG,第⼀个是分⼦,第⼆个是分
母)。length成员是数据的数量⽽不是数据类型的长度。第4个成员valueOffset很重要,它是tag标识的属性代表的变量值相对⽂件开始处的
偏移量。如果变量值占⽤的空间⼩于4个字节,那么该值就存放在 valueOffset中即可,没必要再另外指向⼀个地⽅了。
【 3.图像数据】
根据IFD所指向的地址.存储相关的图像信