安卓版的pvr图片查看
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));