package org.jaudiotagger.tag.asf; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.MetadataDescriptor; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.util.logging.Logger; /** * Encapsulates the WM/Pictures provides some convenience methods for decoding * the binary data it contains * * The value of a WM/Pictures metadata descriptor is as follows: * * byte0 Picture Type byte1-4 Length of the image data mime type encoded as * UTF-16LE null byte null byte description encoded as UTF-16LE (optional) null * byte null byte image data */ public class AsfTagCoverField extends AbstractAsfTagImageField { /** * Logger Object */ public final static Logger LOGGER = Logger .getLogger("org.jaudiotagger.audio.asf.tag"); /** * Description */ private String description; /** * We need this to retrieve the buffered image, if required */ private int endOfName = 0; /** * Image Data Size as read */ private int imageDataSize; /** * Mimetype of binary */ private String mimeType; /** * Picture Type */ private int pictureType; /** * Create New Image Field * * @param imageData * @param pictureType * @param description * @param mimeType */ public AsfTagCoverField(final byte[] imageData, final int pictureType, final String description, final String mimeType) { super(new MetadataDescriptor(AsfFieldKey.COVER_ART.getFieldName(), MetadataDescriptor.TYPE_BINARY)); this.getDescriptor() .setBinaryValue( createRawContent(imageData, pictureType, description, mimeType)); } /** * Creates an instance from a metadata descriptor * * @param source * The metadata descriptor, whose content is published.<br> */ public AsfTagCoverField(final MetadataDescriptor source) { super(source); if (!source.getName().equals(AsfFieldKey.COVER_ART.getFieldName())) { throw new IllegalArgumentException( "Descriptor description must be WM/Picture"); } if (source.getType() != MetadataDescriptor.TYPE_BINARY) { throw new IllegalArgumentException("Descriptor type must be binary"); } try { processRawContent(); } catch (final UnsupportedEncodingException uee) { // Should never happen throw new RuntimeException(uee); // NOPMD by Christian Laireiter on 5/9/09 5:45 PM } } private byte[] createRawContent(final byte[] data, final int pictureType, final String description, String mimeType) { // NOPMD by Christian Laireiter on 5/9/09 5:46 PM this.description = description; this.imageDataSize = data.length; this.pictureType = pictureType; this.mimeType = mimeType; // Get Mimetype from data if not already setField if (mimeType == null) { mimeType = ImageFormats.getMimeTypeForBinarySignature(data); // Couldnt identify lets default to png because probably error in // code because not 100% sure how to identify // formats if (mimeType == null) { LOGGER.warning(ErrorMessage.GENERAL_UNIDENITIFED_IMAGE_FORMAT .getMsg()); mimeType = ImageFormats.MIME_TYPE_PNG; } } final ByteArrayOutputStream baos = new ByteArrayOutputStream(); // PictureType baos.write(pictureType); // ImageDataSize baos.write(org.jaudiotagger.audio.generic.Utils .getSizeLEInt32(data.length), 0, 4); // mimetype byte[] mimeTypeData; try { mimeTypeData = mimeType.getBytes(AsfHeader.ASF_CHARSET.name()); } catch (final UnsupportedEncodingException uee) { // Should never happen throw new RuntimeException("Unable to find encoding:" // NOPMD by Christian Laireiter on 5/9/09 5:45 PM + AsfHeader.ASF_CHARSET.name()); } baos.write(mimeTypeData, 0, mimeTypeData.length); // Seperator baos.write(0x00); baos.write(0x00); // description if (description != null && description.length() > 0) { byte[] descriptionData; try { descriptionData = description.getBytes(AsfHeader.ASF_CHARSET .name()); } catch (final UnsupportedEncodingException uee) { // Should never happen throw new RuntimeException("Unable to find encoding:" // NOPMD by Christian Laireiter on 5/9/09 5:45 PM + AsfHeader.ASF_CHARSET.name()); } baos.write(descriptionData, 0, descriptionData.length); } // Seperator (always write whther or not we have descriptor field) baos.write(0x00); baos.write(0x00); // Image data baos.write(data, 0, data.length); return baos.toByteArray(); } public String getDescription() { return this.description; } @Override public int getImageDataSize() { return this.imageDataSize; } public String getMimeType() { return this.mimeType; } public int getPictureType() { return this.pictureType; } /** * @return the raw image data only */ @Override public byte[] getRawImageData() { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(getRawContent(), this.endOfName, this.toWrap .getRawDataSize() - this.endOfName); return baos.toByteArray(); } private void processRawContent() throws UnsupportedEncodingException { // PictureType this.pictureType = this.getRawContent()[0]; // ImageDataSize this.imageDataSize = org.jaudiotagger.audio.generic.Utils.getIntLE(this .getRawContent(), 1, 2); // Set Count to after picture type,datasize and two byte nulls int count = 5; this.mimeType = null; this.description = null; // Optional int endOfMimeType = 0; while (count < this.getRawContent().length - 1) { if (getRawContent()[count] == 0 && getRawContent()[count + 1] == 0) { if (this.mimeType == null) { this.mimeType = new String(getRawContent(), 5, (count) - 5, "UTF-16LE"); endOfMimeType = count + 2; } else if (this.description == null) { this.description = new String(getRawContent(), endOfMimeType, count - endOfMimeType, "UTF-16LE"); this.endOfName = count + 2; break; } } count += 2; // keep on two byte word boundary } } }