📄 bmpimagewriter.java
字号:
// Partially filled last byte, if any if (scanlineBytes%8 > 0) { pixel = 0; for (int j=0; j<scanlineBytes%8; j++) { pixel |= (pixels[l++] << (7 - j)); } bpixels[k++] = (byte)pixel; } stream.write(bpixels, 0, (scanlineBytes+7)/8); break; case 4: if (compressionType == BMPConstants.BI_RLE4){ byte[] bipixels = new byte[scanlineBytes]; for (int h=0; h<scanlineBytes; h++) { bipixels[h] = (byte)pixels[l++]; } encodeRLE4(bipixels, scanlineBytes); }else { for (int j=0; j<scanlineBytes/2; j++) { pixel = (pixels[l++] << 4) | pixels[l++]; bpixels[k++] = (byte)pixel; } // Put the last pixel of odd-length lines in the 4 MSBs if ((scanlineBytes%2) == 1) { pixel = pixels[l] << 4; bpixels[k++] = (byte)pixel; } stream.write(bpixels, 0, (scanlineBytes+1)/2); } break; case 8: if(compressionType == BMPConstants.BI_RLE8) { for (int h=0; h<scanlineBytes; h++) { bpixels[h] = (byte)pixels[l++]; } encodeRLE8(bpixels, scanlineBytes); }else { for (int j=0; j<scanlineBytes; j++) { bpixels[j] = (byte)pixels[l++]; } stream.write(bpixels, 0, scanlineBytes); } break; case 16: if (spixels == null) spixels = new short[scanlineBytes / numBands]; /* * We expect that pixel data comes in RGB order. * We will assemble short pixel taking into account * the compression type: * * BI_RGB - the RGB order should be maintained. * BI_BITFIELDS - use bitPos array that was built * according to bitfields masks. */ for (int j = 0, m = 0; j < scanlineBytes; m++) { spixels[m] = 0; if (compressionType == BMPConstants.BI_RGB) { /* * please note that despite other cases, * the 16bpp BI_RGB requires the RGB data order */ spixels[m] = (short) (((0x1f & pixels[j ]) << 10) | ((0x1f & pixels[j + 1]) << 5) | ((0x1f & pixels[j + 2]) )); j += 3; } else { for(int i = 0 ; i < numBands; i++, j++) { spixels[m] |= (((pixels[j]) << bitPos[i]) & bitMasks[i]); } } } stream.writeShorts(spixels, 0, spixels.length); break; case 24: if (numBands == 3) { for (int j=0; j<scanlineBytes; j+=3) { // Since BMP needs BGR format bpixels[k++] = (byte)(pixels[l+2]); bpixels[k++] = (byte)(pixels[l+1]); bpixels[k++] = (byte)(pixels[l]); l+=3; } stream.write(bpixels, 0, scanlineBytes); } else { // Case where IndexColorModel had > 256 colors. int entries = icm.getMapSize(); byte r[] = new byte[entries]; byte g[] = new byte[entries]; byte b[] = new byte[entries]; icm.getReds(r); icm.getGreens(g); icm.getBlues(b); int index; for (int j=0; j<scanlineBytes; j++) { index = pixels[l]; bpixels[k++] = b[index]; bpixels[k++] = g[index]; bpixels[k++] = b[index]; l++; } stream.write(bpixels, 0, scanlineBytes*3); } break; case 32: if (ipixels == null) ipixels = new int[scanlineBytes / numBands]; if (numBands == 3) { /* * We expect that pixel data comes in RGB order. * We will assemble int pixel taking into account * the compression type. * * BI_RGB - the BGR order should be used. * BI_BITFIELDS - use bitPos array that was built * according to bitfields masks. */ for (int j = 0, m = 0; j < scanlineBytes; m++) { ipixels[m] = 0; if (compressionType == BMPConstants.BI_RGB) { ipixels[m] = ((0xff & pixels[j + 2]) << 16) | ((0xff & pixels[j + 1]) << 8) | ((0xff & pixels[j ]) ); j += 3; } else { for(int i = 0 ; i < numBands; i++, j++) { ipixels[m] |= (((pixels[j]) << bitPos[i]) & bitMasks[i]); } } } } else { // We have two possibilities here: // 1. we are writing the indexed image with bitfields // compression (this covers also the case of BYTE_BINARY) // => use icm to get actual RGB color values. // 2. we are writing the gray-scaled image with BI_BITFIELDS // compression // => just replicate the level of gray to color components. for (int j = 0; j < scanlineBytes; j++) { if (icm != null) { ipixels[j] = icm.getRGB(pixels[j]); } else { ipixels[j] = pixels[j] << 16 | pixels[j] << 8 | pixels[j]; } } } stream.writeInts(ipixels, 0, ipixels.length); break; } // Write out the padding if (compressionType == BMPConstants.BI_RGB){ for(k=0; k<padding; k++) { stream.writeByte(0); } } } private void encodeRLE8(byte[] bpixels, int scanlineBytes) throws IOException{ int runCount = 1, absVal = -1, j = -1; byte runVal = 0, nextVal =0 ; runVal = bpixels[++j]; byte[] absBuf = new byte[256]; while (j < scanlineBytes-1) { nextVal = bpixels[++j]; if (nextVal == runVal ){ if(absVal >= 3 ){ /// Check if there was an existing Absolute Run stream.writeByte(0); stream.writeByte(absVal); incCompImageSize(2); for(int a=0; a<absVal;a++){ stream.writeByte(absBuf[a]); incCompImageSize(1); } if (!isEven(absVal)){ //Padding stream.writeByte(0); incCompImageSize(1); } } else if(absVal > -1){ /// Absolute Encoding for less than 3 /// treated as regular encoding /// Do not include the last element since it will /// be inclued in the next encoding/run for (int b=0;b<absVal;b++){ stream.writeByte(1); stream.writeByte(absBuf[b]); incCompImageSize(2); } } absVal = -1; runCount++; if (runCount == 256){ /// Only 255 values permitted stream.writeByte(runCount-1); stream.writeByte(runVal); incCompImageSize(2); runCount = 1; } } else { if (runCount > 1){ /// If there was an existing run stream.writeByte(runCount); stream.writeByte(runVal); incCompImageSize(2); } else if (absVal < 0){ // First time.. absBuf[++absVal] = runVal; absBuf[++absVal] = nextVal; } else if (absVal < 254){ // 0-254 only absBuf[++absVal] = nextVal; } else { stream.writeByte(0); stream.writeByte(absVal+1); incCompImageSize(2); for(int a=0; a<=absVal;a++){ stream.writeByte(absBuf[a]); incCompImageSize(1); } // padding since 255 elts is not even stream.writeByte(0); incCompImageSize(1); absVal = -1; } runVal = nextVal; runCount = 1; } if (j == scanlineBytes-1){ // EOF scanline // Write the run if (absVal == -1){ stream.writeByte(runCount); stream.writeByte(runVal); incCompImageSize(2); runCount = 1; } else { // write the Absolute Run if(absVal >= 2){ stream.writeByte(0); stream.writeByte(absVal+1); incCompImageSize(2); for(int a=0; a<=absVal;a++){ stream.writeByte(absBuf[a]); incCompImageSize(1); } if (!isEven(absVal+1)){ //Padding stream.writeByte(0); incCompImageSize(1); } } else if(absVal > -1){ for (int b=0;b<=absVal;b++){ stream.writeByte(1); stream.writeByte(absBuf[b]); incCompImageSize(2); } } } /// EOF scanline stream.writeByte(0); stream.writeByte(0); incCompImageSize(2); } } } private void encodeRLE4(byte[] bipixels, int scanlineBytes) throws IOException { int runCount=2, absVal=-1, j=-1, pixel=0, q=0; byte runVal1=0, runVal2=0, nextVal1=0, nextVal2=0; byte[] absBuf = new byte[256]; runVal1 = bipixels[++j]; runVal2 = bipixels[++j]; while (j < scanlineBytes-2){ nextVal1 = bipixels[++j]; nextVal2 = bipixels[++j]; if (nextVal1 == runVal1 ) { //Check if there was an existing Absolute Run if(absVal >= 4){ stream.writeByte(0); stream.writeByte(absVal - 1); incCompImageSize(2); // we need to exclude last 2 elts, similarity of // which caused to enter this part of the code for(int a=0; a<absVal-2;a+=2){ pixel = (absBuf[a] << 4) | absBuf[a+1]; stream.writeByte((byte)pixel); incCompImageSize(1); } // if # of elts is odd - read the last element if(!(isEven(absVal-1))){ q = absBuf[absVal-2] << 4| 0; stream.writeByte(q); incCompImageSize(1); } // Padding to word align absolute encoding if ( !isEven((int)Math.ceil((absVal-1)/2)) ) { stream.writeByte(0); incCompImageSize(1); } } else if (absVal > -1){ stream.writeByte(2); pixel = (absBuf[0] << 4) | absBuf[1]; stream.writeByte(pixel); incCompImageSize(2); } absVal = -1; if (nextVal2 == runVal2){ // Even runlength runCount+=2; if(runCount == 256){ stream.writeByte(runCount-1); pixel = ( runVal1 << 4) | runVal2; stream.writeByte(pixel); incCompImageSize(2); runCount =2; if(j< scanlineBytes - 1){ runVal1 = runVal2; runVal2 = bipixels[++j]; } else { stream.writeByte(01); int r = runVal2 << 4 | 0; stream.writeByte(r); incCompImageSize(2); runCount = -1;/// Only EOF required now } } } else { // odd runlength and the run ends here // runCount wont be > 254 since 256/255 case will // be taken care of in above code. runCount++; pixel = ( runVal1 << 4) | runVal2; stream.writeByte(runCount); stream.writeByte(pixel); incCompImageSize(2); runCount = 2; runVal1 = nextVal2; // If end of scanline if (j < scanlineBytes -1){ runVal2 = bipixels[++j]; }else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -