You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BmpImage.java 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.image;
  19. // Java
  20. import java.io.IOException;
  21. import java.awt.color.ColorSpace;
  22. import org.apache.commons.io.IOUtils;
  23. /**
  24. * Bitmap image.
  25. * This supports loading a bitmap image into bitmap data.
  26. *
  27. * @see AbstractFopImage
  28. * @see FopImage
  29. */
  30. public class BmpImage extends AbstractFopImage {
  31. /**
  32. * Create a bitmap image with the image data.
  33. *
  34. * @param imgInfo the image information
  35. */
  36. public BmpImage(FopImage.ImageInfo imgInfo) {
  37. super(imgInfo);
  38. }
  39. /**
  40. * Load the bitmap.
  41. * This laods the bitmap data from the bitmap image.
  42. *
  43. * @return true if it was loaded successfully
  44. */
  45. protected boolean loadBitmap() {
  46. int wpos = 18;
  47. int hpos = 22; // offset positioning for w and height in bmp files
  48. int[] headermap = new int[54];
  49. int filepos = 0;
  50. byte[] palette = null;
  51. try {
  52. boolean eof = false;
  53. while ((!eof) && (filepos < 54)) {
  54. int input = inputStream.read();
  55. if (input == -1) {
  56. eof = true;
  57. } else {
  58. headermap[filepos++] = input;
  59. }
  60. }
  61. if (headermap[28] == 4 || headermap[28] == 8) {
  62. int palettesize = 1 << headermap[28];
  63. palette = new byte[palettesize * 3];
  64. int countr = 0;
  65. while (!eof && countr < palettesize) {
  66. int count2 = 2;
  67. while (!eof && count2 >= -1) {
  68. int input = inputStream.read();
  69. if (input == -1) {
  70. eof = true;
  71. } else if (count2 >= 0) {
  72. palette[countr * 3 + count2] = (byte)(input & 0xFF);
  73. }
  74. count2--;
  75. filepos++;
  76. }
  77. countr++;
  78. }
  79. }
  80. } catch (IOException ex) {
  81. log.error("Error while loading image (Bmp): " + ex.getMessage(), ex);
  82. IOUtils.closeQuietly(inputStream);
  83. inputStream = null;
  84. return false;
  85. }
  86. // gets h & w from headermap
  87. this.width = headermap[wpos]
  88. + headermap[wpos + 1] * 256
  89. + headermap[wpos + 2] * 256 * 256
  90. + headermap[wpos + 3] * 256 * 256 * 256;
  91. this.height = headermap[hpos]
  92. + headermap[hpos + 1] * 256
  93. + headermap[hpos + 2] * 256 * 256
  94. + headermap[hpos + 3] * 256 * 256 * 256;
  95. int imagestart = headermap[10]
  96. + headermap[11] * 256
  97. + headermap[12] * 256 * 256
  98. + headermap[13] * 256 * 256 * 256;
  99. this.bitsPerPixel = headermap[28];
  100. this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
  101. int bytes = 0;
  102. if (this.bitsPerPixel == 1) {
  103. bytes = (this.width + 7) / 8;
  104. } else if (this.bitsPerPixel == 24) {
  105. bytes = this.width * 3;
  106. } else if (this.bitsPerPixel == 4 || this.bitsPerPixel == 8) {
  107. bytes = this.width / (8 / this.bitsPerPixel);
  108. } else {
  109. log.error("Image (" + ""
  110. + ") has " + this.bitsPerPixel
  111. + " which is not a supported BMP format.");
  112. return false;
  113. }
  114. if ((bytes & 0x03) != 0) {
  115. bytes |= 0x03;
  116. bytes++;
  117. }
  118. // Should take care of the ColorSpace and bitsPerPixel
  119. this.bitmaps = new byte[this.width * this.height * 3];
  120. int[] temp = new int[bytes * this.height];
  121. try {
  122. int input;
  123. int count = 0;
  124. inputStream.skip((long)(imagestart - filepos));
  125. while ((input = inputStream.read()) != -1) {
  126. if (count >= temp.length) {
  127. log.warn("Data longer than expected while loading image");
  128. break;
  129. } else {
  130. temp[count++] = input;
  131. }
  132. }
  133. } catch (IOException ex) {
  134. log.error("Error while loading image (Bmp): " + ex.getMessage(), ex);
  135. return false;
  136. } finally {
  137. IOUtils.closeQuietly(inputStream);
  138. inputStream = null;
  139. }
  140. for (int i = 0; i < this.height; i++) {
  141. int x = 0;
  142. int j = 0;
  143. while (j < bytes) {
  144. int p = temp[(this.height - i - 1) * bytes + j];
  145. if (this.bitsPerPixel == 24 && x < this.width) {
  146. int countr = 2;
  147. do {
  148. this.bitmaps[3 * (i * this.width + x) + countr]
  149. = (byte)(temp[(this.height - i - 1) * bytes + j] & 0xFF);
  150. j++;
  151. } while (--countr >= 0)
  152. ;
  153. x++;
  154. } else if (this.bitsPerPixel == 1) {
  155. for (int countr = 0;
  156. countr < 8 && x < this.width; countr++) {
  157. if ((p & 0x80) != 0) {
  158. this.bitmaps[3 * (i * this.width + x)] = (byte) 0xFF;
  159. this.bitmaps[3 * (i * this.width + x) + 1] = (byte) 0xFF;
  160. this.bitmaps[3 * (i * this.width + x) + 2] = (byte) 0xFF;
  161. } else {
  162. this.bitmaps[3 * (i * this.width + x)] = (byte) 0;
  163. this.bitmaps[3 * (i * this.width + x) + 1] = (byte) 0;
  164. this.bitmaps[3 * (i * this.width + x) + 2] = (byte) 0;
  165. }
  166. p <<= 1;
  167. x++;
  168. }
  169. j++;
  170. } else if (this.bitsPerPixel == 4) {
  171. for (int countr = 0;
  172. countr < 2 && x < this.width; countr++) {
  173. int pal = ((p & 0xF0) >> 4) * 3;
  174. this.bitmaps[3 * (i * this.width + x)] = palette[pal];
  175. this.bitmaps[3 * (i * this.width + x) + 1] = palette[pal + 1];
  176. this.bitmaps[3 * (i * this.width + x) + 2] = palette[pal + 2];
  177. p <<= 4;
  178. x++;
  179. }
  180. j++;
  181. } else if (this.bitsPerPixel == 8) {
  182. if (x < this.width) {
  183. p *= 3;
  184. this.bitmaps[3 * (i * this.width + x)] = palette[p];
  185. this.bitmaps[3 * (i * this.width + x) + 1] = palette[p + 1];
  186. this.bitmaps[3 * (i * this.width + x) + 2] = palette[p + 2];
  187. j++;
  188. x++;
  189. } else {
  190. j = bytes;
  191. }
  192. } else {
  193. j++;
  194. }
  195. }
  196. }
  197. // This seems really strange to me, but I noticed that
  198. // JimiImage hardcodes bitsPerPixel to 8. If I do not
  199. // do this Acrobat is unable to read the resultant PDF,
  200. // so we will hardcode this...
  201. this.bitsPerPixel = 8;
  202. return true;
  203. }
  204. }