Java tutorial
/* * TV-Browser * Copyright (C) 04-2003 Martin Oberhauser (darras@users.sourceforge.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * CVS information: * $RCSfile$ * $Source$ * $Date: 2010-06-28 19:33:48 +0200 (Mon, 28 Jun 2010) $ * $Author: bananeweizen $ * $Revision: 6662 $ */ package tvbrowserdataservice.file; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.plugins.jpeg.JPEGImageWriteParam; import javax.imageio.stream.ImageOutputStream; import org.apache.commons.lang.StringUtils; import util.io.FileFormatException; import util.io.IOUtilities; import util.misc.HashCodeUtilities; import util.ui.UiUtilities; import devplugin.ProgramFieldType; /** * @author Til Schneider, www.murfman.de */ public class ProgramField implements Cloneable { private static final Logger mLog = Logger.getLogger(ProgramField.class.getName()); private static final String TEXT_CHARSET = "UTF-8"; private int mTypeId; private ProgramFieldType mType; private byte[] mData; private int mDataFormat; /** * Maximum Size of Images. Images get resized to this * size if they exceed the limit */ private static final int MAX_IMAGE_SIZE_X = 150; /** * Maximum Size of Images. Images get resized to this * size if they exceed the limit */ private static final int MAX_IMAGE_SIZE_Y = 150; public ProgramField() { mDataFormat = ProgramFieldType.UNKNOWN_FORMAT; mType = null; } /** * Used for creating an instance of ProgramField to * read/store the additional ProgramFrame id in. * * @param o Dummy parameter. * @since 2.2.2 */ protected ProgramField(Object o) { mDataFormat = ProgramFieldType.UNKNOWN_FORMAT; mTypeId = 255; } public static ProgramField create(ProgramFieldType type, String text) { if (StringUtils.isEmpty(text)) { return null; } ProgramField p = new ProgramField(); p.setType(type); p.setTextData(text); return p; } public static ProgramField create(ProgramFieldType type, byte[] data) { if ((data == null) || (data.length == 0)) { return null; } ProgramField p = new ProgramField(); p.setType(type); if (type == ProgramFieldType.PICTURE_TYPE) { // If the FieldType is a Picture it has to be resized and recompressed byte[] newdata = recreateImage(data); if (newdata == null) { return null; } p.setBinaryData(newdata); } else { p.setBinaryData(data); } return p; } /** * This Function loads an image using imageio, * resizes it to the Max-Size of Images in TVBrowser and * stores it as an compressed jpg. * <p/> * If the Image is smaller than the Max-Size, it isn't altered * * @param data Image-Data * @return resized Image-Data */ private static byte[] recreateImage(byte[] data) { byte[] newdata = null; BufferedImage image = null; try { // Read Image image = ImageIO.read(new ByteArrayInputStream(data)); int curx = image.getWidth(null); int cury = image.getHeight(null); // If the Size is < than max, use the original Data to reduce compression // artefacts if ((curx <= MAX_IMAGE_SIZE_X) && (cury <= MAX_IMAGE_SIZE_Y)) { return data; } int newx = MAX_IMAGE_SIZE_X; int newy = (int) ((MAX_IMAGE_SIZE_X / (float) curx) * cury); if (newy > MAX_IMAGE_SIZE_Y) { newy = MAX_IMAGE_SIZE_Y; newx = (int) ((MAX_IMAGE_SIZE_Y / (float) cury) * curx); } BufferedImage tempPic = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = tempPic.createGraphics(); g2d.drawImage(image, null, null); g2d.dispose(); BufferedImage newImage = UiUtilities.scaleIconToBufferedImage(tempPic, newx, newy); ByteArrayOutputStream out = new ByteArrayOutputStream(); // Find a jpeg writer ImageWriter writer = null; Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpg"); if (iter.hasNext()) { writer = iter.next(); } if (writer != null) { // Prepare output file ImageOutputStream ios = ImageIO.createImageOutputStream(out); writer.setOutput(ios); JPEGImageWriteParam param = new JPEGImageWriteParam(null); param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionQuality(0.85f); // Write the image writer.write(null, new IIOImage(newImage, null, null), param); // Cleanup ios.flush(); writer.dispose(); ios.close(); newdata = out.toByteArray(); } else { mLog.severe("No JPEG-Exporter found. Image is not stored in Data"); } } catch (IOException e) { e.printStackTrace(); newdata = null; } return newdata; } public static ProgramField create(ProgramFieldType type, int value) { ProgramField p = new ProgramField(); p.setType(type); if (type.getFormat() == ProgramFieldType.TIME_FORMAT) { p.setTimeData(value); } else { p.setIntData(value); } return p; } public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException exc) { // This will never happen, since this class implements Cloneable return null; } } public int getTypeId() { return mTypeId; } public ProgramFieldType getType() { if (mType == null) { mType = ProgramFieldType.getTypeForId(mTypeId); } return mType; } /** * @param type */ public void setType(ProgramFieldType type) { mType = type; mTypeId = type.getTypeId(); } /** * Is used for a field in an update file that should be deleted. */ public void removeData() { mDataFormat = ProgramFieldType.UNKNOWN_FORMAT; mData = null; } public byte[] getBinaryData() { return mData; } /** * @param data */ public void setBinaryData(byte[] data) { mDataFormat = ProgramFieldType.BINARY_FORMAT; mData = data; } public String getTextData() { if (mData == null) { return null; } try { return new String(mData, TEXT_CHARSET); } catch (UnsupportedEncodingException exc) { // This will never happen, because UTF-8 is always supported mLog.log(Level.SEVERE, "Charset " + TEXT_CHARSET + " is not supported", exc); return null; } } public void setTextData(String text) { mDataFormat = ProgramFieldType.TEXT_FORMAT; try { mData = text.getBytes(TEXT_CHARSET); } catch (UnsupportedEncodingException exc) { // This will never happen, because UTF-8 is always supported mLog.log(Level.SEVERE, "Charset " + TEXT_CHARSET + " is not supported", exc); } } public int getIntData() { return dataToInt(mData); } public void setIntData(int value) { mDataFormat = ProgramFieldType.INT_FORMAT; mData = intToData(value); } public int getTimeData() { return dataToInt(mData); } public void setTimeData(int minutesAfter1970) { mDataFormat = ProgramFieldType.TIME_FORMAT; mData = intToData(minutesAfter1970); } /** * Gets a String representation of the data value. * * @return the data value as String. */ public String getDataAsString() { if (mDataFormat == ProgramFieldType.TEXT_FORMAT) { return new StringBuilder("'").append(getTextData()).append("'").toString(); } else if (mDataFormat == ProgramFieldType.INT_FORMAT) { return Integer.toString(getIntData()); } else if (mDataFormat == ProgramFieldType.TIME_FORMAT) { int time = getTimeData(); int hours = time / 60; int minutes = time % 60; return new StringBuilder().append(hours).append(':').append((minutes < 10) ? "0" : "").append(minutes) .toString(); } else if (mDataFormat == ProgramFieldType.BINARY_FORMAT) { return "(binary)"; } else { return "(unknown)"; } } private static int dataToInt(byte[] data) { if (data == null) { return 0; } return ((data[0] & 0xFF) << (3 * 8)) | ((data[1] & 0xFF) << (2 * 8)) | ((data[2] & 0xFF) << (1 * 8)) | ((data[3] & 0xFF) << (0 * 8)); } private static byte[] intToData(int value) { byte[] data = new byte[4]; data[0] = (byte) (value >> (3 * 8)); data[1] = (byte) (value >> (2 * 8)); data[2] = (byte) (value >> (1 * 8)); data[3] = (byte) (value >> (0 * 8)); return data; } private void checkFormat() throws FileFormatException { // Check whether the field data has the right format if (!getType().isRightFormat(mDataFormat)) { throw new FileFormatException("The field '" + getType().getName() + "' must have the " + ProgramFieldType.getFormatName(getType().getFormat()) + " but it has the " + ProgramFieldType.getFormatName(mDataFormat)); } } public void readFromStream(InputStream stream) throws IOException, FileFormatException { mTypeId = stream.read(); mType = null; mDataFormat = ProgramFieldType.UNKNOWN_FORMAT; int dataLength = ((stream.read() & 0xFF) << 16) | ((stream.read() & 0xFF) << 8) | (stream.read() & 0xFF); if (dataLength == 0) { mData = null; } else { mData = IOUtilities.readBinaryData(stream, dataLength); } } public void writeToStream(OutputStream stream) throws IOException, FileFormatException { writeToStream(stream, true); } /** * Writes the data to a stream. * * @param stream The stream to write on * @param check If the format should be checked * @throws IOException Thrown if something goes wrong. * @throws FileFormatException Thrown if something goes wrong. * @since 2.2.2 */ protected void writeToStream(OutputStream stream, boolean check) throws IOException, FileFormatException { // Check whether the field has the right format if (check) { checkFormat(); } stream.write(mTypeId); if (mData == null) { stream.write(0); // Length highest byte stream.write(0); // Length middle byte stream.write(0); // Length lowest byte } else { // Write the data length stream.write((byte) (mData.length >> 16)); stream.write((byte) (mData.length >> 8)); stream.write((byte) (mData.length)); // Write the data stream.write(mData); } } public boolean equals(Object obj) { if (obj instanceof ProgramField) { ProgramField field = (ProgramField) obj; if (getTypeId() != field.getTypeId()) { return false; } return Arrays.equals(mData, field.mData); } else { return false; } } @Override public int hashCode() { int result = HashCodeUtilities.hash(getTypeId()); result = HashCodeUtilities.hash(result, mData); return result; } }