public class PVRTDecompress
{
/*
author:FormatFa
mail :1758759399@qq.com
date :2017-6-14
*/
//modify from PVRTDecompress.cpp in PowerVR
//https://github.com/gildor2/UModel libs dir
public static int Version3 = 0x03525650;
static int ETC_FLIP = 0x01000000;
static int ETC_DIFF = 0x02000000;
static int[][] mod= new int[][]{
{2, 8, -2, -8},
{5, 17, -5, -17},
{9, 29, -9, -29},
{13, 42, -13, -42},
{18, 60, -18, -60},
{24, 80, -24, -80},
{33, 106, -33, -106},
{47, 183, -47, -183}
};
/*
PvrtHeader info from PVR File Format Specification.pdf
*/
public static int flag_NoFlag=0x0;
//When this flag is set, colour values within the texture have been pre- multiplied by the alpha values
public static int flag_premultiplied=0x02;
//Texture data is in the Linear RGB colour space
public static int colorSpace_LinearRGB=0;
//Texture data is in the Standard RGB colour space
public static int colorSpace_aRGB=1;
public static int channel_UnsignedByteNormalised=0;
public static long format_ETC2_RGB=0x00000016;
public static class PVRTHeader
{
public int version;
public int flags;
public long pixelFormat;
//int piexlFormat2;
public int colorSpace;
public int channelType;
public int width;
public int heigth;
public int depth;
public int numSurface;
public int numFace;
public int minMapCount;
public int metaDataSize;
public byte[] imgdata;
@Override
public String toString()
{
return "version:"+Integer.toHexString(version)
+"\nflag:"+Integer.toHexString(flags)
+"\npiex:"+Long.toHexString(pixelFormat)
+"\ncolor:"+Integer.toHexString(colorSpace)
+"\nchannal:"+Integer.toHexString(channelType)
+"\nwdth:"+Integer.toHexString(width)
+"\nheigth:"+Integer.toHexString(heigth)
+"\nsurface:"+Integer.toHexString(numSurface)
+"\nface:"+Integer.toHexString(numFace)
+"\nminp:"+Integer.toHexString(minMapCount)
+"\nmeta:"+Integer.toHexString(metaDataSize);
}
}
void pri(int l)
{
}
public static PVRTHeader loadPVRHeader(InputStream is) throws Exception
{
PVRTHeader head = new PVRTHeader();
//if(head.version!=Version3)
// throw new Exception("magic except:"+Integer.toHexString(head.version);
MyDataInputStream my = new MyDataInputStream(is);
head.version = my.readInt();
head.flags = my.readInt();
head.pixelFormat = my.readLong();
head.colorSpace = my.readInt();
head.channelType = my.readInt();
head.width = my.readInt();
head.heigth= my.readInt();
head.depth = my.readInt();
head.numSurface = my.readInt();
head.numFace = my.readInt();
head.minMapCount = my.readInt();
head.metaDataSize = my.readInt();
is.skip(head.metaDataSize);
byte[] data = new byte[my.available()];
my.readFully(data);
head.imgdata = data;
return head;
}
public static int[] PVRTDecompressETC_int(PVRTHeader head)
{
List<Integer> t=new ArrayList<Integer>();
int[] piex=new int[head.width*head.heigth];
long blockTop,blockBot;
long modtable1,modtable2;
boolean bFlip,bDiff;
char red1,green1,blue1;
char red2,green2,blue2;
int offset=0;
int mark = 0;
int w = head.width;
int h = head.heigth;
byte[] data = head.imgdata;
for(int i = 0 ; i < h;i+=4)
{
for(int j = 0; j<w;j+=4)
{
int p = offset;
mark = i*w+j;
blockTop = ByteUtils.byte2intLow(new byte[]{data[p],data[p+1],data[p+2],data[p+3]});
blockBot = ByteUtils.byte2intLow(new byte[]{data[p+4],data[p+5],data[p+6],data[p+7]});
// System.out.println(Integer.toHexString((int)blockTop)+" "+Integer.toHexString((int)blockBot));
offset+=8;
bFlip = ((blockTop&ETC_FLIP)!=0);
bDiff = (blockTop&ETC_DIFF)!=0;
if(bDiff)
{
blue1 =(char) ((blockTop & 0xf80000) >> 16);
green1 = (char)((blockTop & 0xf800) >> 8);
red1 = (char)(blockTop & 0xf8);
// System.out.println("greeqn:"+(int)green1+",:"+(int)blue1+","+(int)red1);
//in c is signed char,
// get differential colour for subblock 2
char blues = (char)((blue1 >> 3) +(char) (((blockTop & 0x70000) >> 11) >> 5));
char greens=( (char)( (green1 >> 3 )+ ( ((blockTop & 0x700) >> 3) >> 5)));
char reds =(char)( (red1 >> 3) + ( ((blockTop & 0x7) << 5) >> 5));
// System.out.println("b:"+blockTop+ "sgreeqn:"+(int)greens+",:"+(int)blues+","+(int)reds);
blue2 = blues;
green2 = greens;
red2 = reds;
if(offset<120&&bFlip)
//
System.out.println( (int)red1+"trs:"+(int)reds+"-- "+blockTop+ "_yes:"+ (int)red2+","+(int)green2+","+(int) blue2);
//
red1 =(char)( red1 + (red1 >> 5)); // copy bits to lower sig
green1 = (char)( green1 + (green1 >> 5)); // copy bits to lower sig
blue1 = (char)( blue1 + (blue1 >> 5)); // copy bits to lower sig
red2 = (char)( (red2 << 3) + (red2 >> 2)); // copy bits to lower sig
green2 = (char)( (green2 << 3) + (green2 >> 2)); // copy bits to lower sig
blue2 = (char)( (blue2 << 3) + (blue2 >> 2)); // copy bits to lower sig
}
else
{
//System.out.println("diff");
// individual mode 4 + 4 colour bits
// get base colour for subblock 1
blue1 =(char) ((blockTop & 0xf00000) >> 16);
blue1 =(char) ( blue1 + (blue1 >> 4)); // copy bits to lower sig
green1 =(char) (int)((blockTop & 0xf000) >> 8);
green1 =(char) ( green1 + (green1 >> 4)); // copy bits to lower sig
red1 = (char) (int)(blockTop & 0xf0);
red1 =(char) (red1 + (red1 >> 4)); // copy bits to lower sig
// get base colour for subblock 2
blue2 =(char) (int)((blockTop & 0xf0000) >> 12);
blue2 = (char)( blue2 + (blue2 >> 4)); // copy bits to lower sig
green2 =(char) (int)((blockTop & 0xf00) >> 4);
green2 = (char)(green2 + (green2 >> 4)); // copy bits to lower sig
red2 =(char)(int) ((blockTop & 0xf) << 4);
red2 = (char)(red2 + (red2 >> 4)); // copy bits to lower sig
// System.out.println("b:"+blockTop+"greeqn:"+(int)green2+",:"+(int)blue2+","+(int)red2);
}
// get the modtables for each subblock
modtable1 = (blockTop >> 29) & 0x7;
modtable2 = (blockTop >> 26) & 0x7;
if(!bFlip)/* 2*4 block */
{
for (int a = 0; a< 4; a++) // vertical
{
for (int b = 0; b < 2; b++) // horizontal
{
//*(output + j * x + k) =
//
piex[mark+ a*w+b]=(modifyPixel((int)red1, (int)green1, (int)blue1, b, a, blockBot, (int)modtable1));
//*(output + j * x + k + 2) =
piex[ mark+ a*w+b+2]=
// piex[mark+ a*w+b];
(modifyPixel((int)red2, (int)green2,(int) blue2, b + 2, a, blockBot, (int)modtable2));
//if(offset<120)
// System.out.println("no:"+piex[ mark+ a*w+b+2]);
}
}
}
else/*flip*/
{
for (int a = 0; a< 2; a++) // vertical
{
for (int b = 0; b < 4; b++) // horizontal
{
//*(output + j * x + k) =
piex[ mark+ a*w+b]=(modifyPixel((int)red1, (int)green1, (int)blue1, b, a, blockBot, (int)modtable1));
//*(output + j * x + k + 2) =
piex[ mark+ (a+2)*w+b]=
// piex[ mark+ a*w+b];
(modifyPixel((int)red2, (int)green2,(int) blue2, b ,a+2, blockBot, (int)modtable2));
//
if(offset<120)
//
System.out.println( bDiff+ "_yes:"+ (int)red2+","+(int)green2+","+(int) blue2+","+b+" ,"+(a+2) +":->"+piex[ mark+ (a+2)*w+b]);
//
}
}
}
}
}
return piex;
}
/*
Decompress to ARGB8888
*/
public static byte[] PVRTDecompressETC(PVRTHeader head) throws IOException
{
int[] pix = PVRTDecompressETC_int(head);
ByteArrayOutputStream os = new ByteArrayOutputStream();
MyDataOutPutStream myos = new MyDataOutPutStream(os);
for(int p :pix)
myos.writeInt(p);
return ((ByteArrayOutputStream) myos.getOuputStream()).toByteArray();
}
/* !***********************************************************************
@Function modifyPixel
@Input red Red value of pixel
@Input green Green
value of pixel
@Input blue Blue value of pixel
@Input x Pixel x position
in block @Input y Pixel y position in block
@Input modBlock Values for the
current block
@Input modTable Modulation value
s @Returns Returns actual
pixel colour
@Description Used by ETCTextureDecompress
************************************************************************ */
static int modifyPixel(int red, int green, int blue, int x, int y,
long modBlock, int modTable) {
int index = x * 4 + y, pixelMod;
long mostSig = modBlock << 1;
if (index < 8)
pixelMod =
mod[modTable][(int)(((modBlock >> (index + 24)) & 0x1) +
((mostSig >> (index + 8)) & 0x2))];
else
pixelMod =
mod[modTable][(int)(((modBlock >> (index + 8)) & 0x1) +
((mostSig >> (index - 8)) & 0x2))];
red = _CLAMP_(red + pixelMod, 0, 255);
green = _CLAMP_(green + pixelMod, 0, 255);
blue = _CLAMP_(blue + pixelMod, 0, 255);
return ((red << 16) + (green << 8) + blue) | 0xff000000;
}
private static int _CLAMP_(int pixelMod, int p1, int p2)
{
return (pixelMod)<(p2)? ((pixelMod)<(p1)?(p1):(pixelMod) ) : (p2);
}
}
从PowerSDK里修改成的java版,结合安卓的类可以显示pvr图片
int[] data=PVRTDecompress.PVRTDecompressETC_int(he); Bitmap bmp= Bitmap.createBitmap(data, he.width,he.heigth,Bitmap.Config.ARGB_8888); bmp.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(outname_png));