1 /*
2  * @(#)BMP.java - carries BMP stuff, access from 'all sides'
3  *
4  * Copyright (c) 2004-2005 by dvb.matt, All Rights Reserved.
5  *
6  * This file is part of ProjectX, a free Java based demux utility.
7  * By the authors, ProjectX is intended for educational purposes only,
8  * as a non-commercial test project.
9  *
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  */
26 
27 package net.sourceforge.dvb.projectx.subtitle;
28 
29 
30 //DM24042004 081.7 int02 introduced
31 
32 import java.io.BufferedOutputStream;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 
36 import java.util.ArrayList;
37 import java.util.Hashtable;
38 import java.util.Enumeration;
39 
40 public class BMP extends Object {
41 
42 	private static final byte defaultHeader[] = {
43 		0x42, 0x4D, //'B','M'
44 		0, 0, 0, 0, // real filesize 32bit, little endian (real size*3 + header(0x36))
45 		0, 0, 0, 0,
46 		0x36, 0, 0, 0, //bitmap info size
47 		0x28, 0, 0, 0,
48 		0, 0, 0, 0, //hsize
49 		0, 0, 0, 0, //vsize
50 		1, 0,  //nplane
51 		0x18, 0, //bitcount 24b
52 		0, 0, 0, 0, //ncompr
53 		0, 0, 0, 0, //image bytesize
54 		(byte)0x88, 0xB, 0, 0, //nxpm 75dpi
55 		(byte)0x88, 0xB, 0, 0, //nypm 75dpi
56 		0, 0, 0, 0, //nclrused
57 		0, 0, 0, 0  //nclrimp
58 	};
59 
60 	private static Hashtable bmps = new Hashtable();
61 
BMP()62 	private BMP()
63 	{}
64 
getContents()65 	public static String getContents()
66 	{
67 		return bmps.toString();
68 	}
69 
getKeys()70 	public static Enumeration getKeys()
71 	{
72 		return bmps.keys();
73 	}
74 
isEmpty()75 	public static boolean isEmpty()
76 	{
77 		return bmps.isEmpty();
78 	}
79 
clear()80 	public static void clear()
81 	{
82 		bmps.clear();
83 	}
84 
savePixels(Bitmap bitmap)85 	public static void savePixels(Bitmap bitmap)
86 	{
87 		bmps.put("" + bitmap.getId(), bitmap);
88 	}
89 
getBitmap(int id)90 	public static Bitmap getBitmap(int id)
91 	{
92 		return (Bitmap)bmps.get("" + id);
93 	}
94 
littleEndian(byte[] array, int aPos, int value)95 	private static void littleEndian(byte[] array, int aPos, int value)
96 	{
97 		for (int a=0; a<4; a++)
98 			array[aPos+a] = (byte)(value>>(a*8) & 0xFF);
99 	}
100 
buildBMP_24bit(String outfile, String key)101 	public static void buildBMP_24bit(String outfile, String key) throws IOException
102 	{
103 		Bitmap bitmap = (Bitmap)bmps.get(key);
104 
105 		if (bitmap == null)
106 			return;
107 
108 		int width = bitmap.getWidth();
109 		int height = bitmap.getHeight();
110 		int size = 3 * width * height + height * (width & 3);
111 
112 		if (size == 0)
113 			return;
114 
115 		int pixels[] = bitmap.getPixel();
116 
117 		BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream( outfile + ".bmp"), 65535);
118 
119 		byte BMPheader[] = new byte[defaultHeader.length];
120 		System.arraycopy(defaultHeader, 0, BMPheader, 0, defaultHeader.length);
121 
122 		byte RGB_24bit[] = new byte[3];
123 
124 		littleEndian(BMPheader , 2, (0x36 + size));
125 		littleEndian(BMPheader , 18, width);
126 		littleEndian(BMPheader , 22, height);
127 		littleEndian(BMPheader , 34, size);
128 
129 		out.write(BMPheader);
130 
131 		for (int a = height-1; a >= 0; a--)
132 		{
133 			for (int b = 0; b < width; b++)
134 			{
135 				for (int c = 0; c < 3; c++)
136 					RGB_24bit[c] = (byte)(pixels[b + a * width]>>(c * 8) & 0xFF);
137 
138 				out.write(RGB_24bit);
139 			}
140 
141 			out.write(new byte[width & 3]); //padding bytes
142 		}
143 
144 		out.flush();
145 		out.close();
146 	}
147 
buildBMP_palettized(String outfile, String key, ArrayList color_table_array, int palette)148 	public static String buildBMP_palettized(String outfile, String key, ArrayList color_table_array, int palette) throws IOException
149 	{
150 		return buildBMP_palettized(outfile, (Bitmap)bmps.get(key), color_table_array, palette);
151 	}
152 
buildBMP_palettized(String outfile, Bitmap bitmap, ArrayList color_table_array, int palette)153 	public static String buildBMP_palettized(String outfile, Bitmap bitmap, ArrayList color_table_array, int palette) throws IOException
154 	{
155 		if (bitmap == null)
156 			return "";
157 
158 		palette = 256; //still fixed!
159 
160 		int width = bitmap.getWidth();
161 		int height = bitmap.getHeight();
162 		int size = palette * 4 + width * height + height * (width & 3);
163 
164 		if (size == 0)
165 			return "";
166 
167 		outfile += ".bmp";
168 
169 		BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(outfile), 65535);
170 
171 		byte BMPheader[] = new byte[defaultHeader.length];
172 		System.arraycopy(defaultHeader, 0, BMPheader, 0, defaultHeader.length);
173 
174 		byte RGB_4bit = 0; // 1 pixel_index
175 
176 		if (palette == 256)
177 			BMPheader[28] = 8;
178 		else
179 			BMPheader[28] = 4;
180 
181 
182 		littleEndian(BMPheader , 2, (0x36 + size));
183 		littleEndian(BMPheader , 10, (0x36 + palette * 4)); //pixel start
184 		littleEndian(BMPheader , 18, width);
185 		littleEndian(BMPheader , 22, height);
186 		littleEndian(BMPheader , 34, size);
187 
188 		out.write(BMPheader);
189 
190 		Object color_table[] = color_table_array.toArray();
191 		byte base_color_index[] = new byte[4];
192 
193 		//paletize 256 * 4byte BGR0 indices
194 		for (int a=0, color; a < palette; a++)
195 		{
196 			if (a < color_table.length)
197 			{
198 				color = 0xFFFFFF & Integer.parseInt(color_table[a].toString());
199 
200 				for (int b=0; b < 3; b++)
201 					base_color_index[b] = (byte)(0xFF & color>>(b<<3));
202 			}
203 
204 			out.write(base_color_index);
205 		}
206 
207 		color_table = null;
208 
209 		int pixels[] = bitmap.getPixel();
210 
211 		for (int a = height - 1; a >= 0; a--)
212 		{
213 			for (int b = 0, val = 0; b < width; b++)
214 			{
215 				out.write(0xFF & getColorIndex(pixels[b + a * width], color_table_array));
216 			}
217 
218 			out.write(new byte[width & 3]); //padding bytes
219 		}
220 
221 		out.flush();
222 		out.close();
223 
224 		return outfile;
225 	}
226 
getColorIndex(int color, ArrayList color_table)227 	private static int getColorIndex(int color, ArrayList color_table)
228 	{
229 		String color_str = "" + color;
230 		int index = color_table.indexOf(color_str);
231 
232 		if (index != -1)
233 			return index;
234 
235 		return (color_table.size() - 1);
236 	}
237 
write_ColorTable(String outfile, ArrayList color_table_array, int palette)238 	public static String write_ColorTable(String outfile, ArrayList color_table_array, int palette) throws IOException
239 	{
240 		Object color_table[] = color_table_array.toArray();
241 		byte base_color_index[] = new byte[4];
242 
243 		outfile += ".spf";
244 
245 		palette = 256; //still fixed!
246 
247 		BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(outfile), 65535);
248 
249 		//palettize number * 4byte BGR0 indices (e.g.256 or 16)
250 		for (int a=0, color; a < palette; a++)
251 		{
252 			if (a < color_table.length)
253 			{
254 				color = 0xFFFFFF & Integer.parseInt(color_table[a].toString());
255 
256 				for (int b=0; b < 3; b++)
257 					base_color_index[b] = (byte)(0xFF & color>>(b<<3));
258 			}
259 
260 			out.write(base_color_index);
261 		}
262 
263 		color_table = null;
264 
265 		out.flush();
266 		out.close();
267 
268 		return outfile;
269 	}
270 }