05-06-2010 10:42 PM
yuusaku wrote:please try:
http://acodapella.blogspot.com/2010/05/reading-bbt
humbsdat-thumbnail.html
This doesn't seem to always work. I'm looking at thumbs116x116.dat in UltraEdit. If you search for the word "/samples", you can see where each picture starts. I'm assuming that the pictures binary data starts somewhere near after the filename ends (.png.rem). On of the files has FF D8 FF E1 right after the filename. Others don't seem to have a header like that and looking at the data, there isn't even any exif data in the binary stream, so it doesn't seem to be an exif/jpeg file in the data stream - it's something else. That's the confusing spot. The data stream seems to have different type of objects in it. I also don't know if the data stream has any type of length data for the not exif objects stored in it. I can provide a copy of my thumbs116x116.dat file if anyone wants to have a peek.
Jeff
05-08-2010 01:08 AM
in my case, i found that one image could have multiple EXIFs stored within the .dat.
http://acodapella.blogspot.com/2010/05/thumbs116x1
this code snippet skips to next file of the same directory as soon as it finds the first occurence of the EXIF
not sure does this reader work for your .dat, feel free to improve it.
07-25-2010 12:03 PM
Has anyone found a solution to this problem as I have this problem as well.
I have tried this BBThumbs.dat usage but it seems to be very slow as well. Nowhere near as fast as rims delivered image selectors and my phone becomes unresponsive.
07-25-2010 12:34 PM - edited 07-25-2010 01:26 PM
I never really played around with BBThumbs.dat (<= 4.7) but I have played around with thumbsXXXxXXX.dat (5.0 >). The format I figured out is as follows:
0: [short] 2: [int] 6: [int] "bunch of tags up until Reserved1 == 0" Tag: 0: Reserved1: [short] 2: path length [int] 6: name length [int] 10: data length [int] 14: [int] 18: [int] 22: [int] 26: "gap" (zero in value) [byte] 27: Path [ASCII the length of Path Length] 27 + path length: Name [ASCII the length of Name Length] 27 + path length + name length: Image data [byte[] the length of Data Length] 27 + path length + name length + data length: "gap" (value of 17 if another tag exists) [byte] 27 + path length + name length + data length + 1: [short]
If you can understand that.
Example reader:
private class TagGroup
{
public int Reserved1;
public int Reserved2;
public Vector Tags;
public TagGroup(InputStream st, long length) throws IOException
{
DataInputStream br = new DataInputStream(st);
if (br.readShort() != 1570) //8710 for big-endian
{
//Not valid dataBase
return;
}
Reserved1 = reverseEndian(br.readInt());
Reserved2 = reverseEndian(br.readInt());
Tags = new Vector();
long pos;
while (length > (pos = length - st.available())) //No the best way to do it but it gets the job done if all data is avalible.
{
st.mark(Integer.MAX_VALUE); //Again, not the best but if supported it gets the job done
Tag g = new Tag(br);
if (g.Reserved1 == 0)
{
st.reset();
break;
}
Tags.addElement(g);
}
//Not sure what other tags are
}
public static int reverseEndian(int value)
{
return ((value >> 24) & 0xFF) | (((value >> 16) & 0xFF) << 8) | (((value >> 8) & 0xFF) << 16) | ((value & 0xFF) << 24);
}
public static short reverseEndian(short value)
{
return (short)(((value >> 8) & 0xFF) | ((value & 0xFF) << 8));
}
public static char[] readChars(DataInputStream br, int count) throws IOException
{
char[] chars = new char[count];
for(int i = 0; i < count; i++)
{
chars[i] = br.readChar();
}
return chars;
}
}
private class Tag
{
public short Reserved1;
public int PathLength;
public int NameLength;
public int DataLength;
public int Reserved2;
public int Reserved3;
public int Reserved4;
public String Path;
public String Name;
public byte[] Image;
public short Reserved5;
public Tag(DataInputStream br) throws IOException
{
Reserved1 = TagGroup.reverseEndian(br.readShort());
PathLength = TagGroup.reverseEndian(br.readInt());
NameLength = TagGroup.reverseEndian(br.readInt());
DataLength = TagGroup.reverseEndian(br.readInt());
Reserved2 = TagGroup.reverseEndian(br.readInt());
Reserved3 = TagGroup.reverseEndian(br.readInt());
Reserved4 = TagGroup.reverseEndian(br.readInt());
int b = br.read(); //Gap (0)
Path = new String(TagGroup.readChars(br, PathLength));
Name = new String(TagGroup.readChars(br, NameLength));
if (b != 0 && Reserved1 != 0)
{
System.out.println("Invalid gap for " + Path + Name);
}
Image = new byte[DataLength];
br.read(Image);
b = br.read(); //Gap (17)
if (b != 17 && Reserved1 != 0)
{
System.out.println("Invalid 2nd gap for " + Path + Name);
}
Reserved5 = br.readShort();
}
}
08-04-2010 01:02 PM
thanks for the code....
Wonderfull as bb developers we have to resort to hacks like this which may not work in future OS's.
At least in OS6.0 rim seems to have provided api's for decent pickers.
http://www.blackberry.com/developers/docs/6.0.0api
Its in 5.0 but for images that filepicker is not particularly usefull unless you like micro thumbs.
This one at least gives you option of a view type VIEW_PICTURES which hopefully sizes thumbs nicely.
For pre os5.0, any suggestions on how to display thumbs in a file picker which works with large amount of images efficiently?
You can't load them all up and display them in a dialog. Its just way to slow.
Looking closely at rims picture dialog it seems to grab new thumbs when you scroll and clears ones from memory ones that are no longer visible.
Creating a blank bitmap as a place holder for 100's is thumbs from a dir listing slows down the application greatly so my guess is that they are only adding bitmaps for visible thumbs and removing bitmaps for ones no longer visible.
But even still they are being rendered incredibly fast. I have not been able to duplicate that type of speed. Even when reading from thumbs dat files instead of the original file.
05-12-2011 11:14 AM
I know this is an old thread but I have an update to my previous code. Missed what seems like a data "end point" and for one reason or another I was reversing the endian of the values.
Updated code:
public class TagGroup
{
public int Reserved1;
public int Reserved2;
public Vector Tags;
public TagGroup(InputStream st, long length) throws IOException
{
DataInputStream br = new DataInputStream(st);
if (br.readShort() != 8710)
{
//Not valid dataBase
return;
}
Reserved1 = br.readInt();
Reserved2 = br.readInt();
Tags = new Vector();
long pos = 0;
while (length > pos)
{
st.mark(Integer.MAX_VALUE); //Again, not the best but if supported it gets the job done
Tag g = new Tag(br);
pos += g.getSize();
if (g.Reserved1 == 0)
{
st.reset();
break;
}
Tags.addElement(g);
if(g.Reserved1 == 8720)
{
//Appears to be a new tag database
break;
}
}
//Not sure what other tags are
}
public static char[] readChars(DataInputStream br, int count) throws IOException
{
char[] chars = new char[count];
for(int i = 0; i < count; i++)
{
chars[i] = (char)br.read();
}
return chars;
}
}
public class Tag
{
public short Reserved1;
public int PathLength;
public int NameLength;
public int DataLength;
public int Reserved2;
public int Reserved3;
public int Reserved4;
public String Path;
public String Name;
public byte[] Image;
public short Reserved5;
public Tag(DataInputStream br) throws IOException
{
Reserved1 = br.readShort();
PathLength = br.readInt();
NameLength = br.readInt();
DataLength = br.readInt();
Reserved2 = br.readInt();
Reserved3 = br.readInt();
Reserved4 = br.readInt();
int b = br.read(); //Gap (0)
Path = new String(TagGroup.readChars(br, PathLength));
Name = new String(TagGroup.readChars(br, NameLength));
if (b != 0 && Reserved1 != 0)
{
System.out.println("Invalid gap for " + Path + Name);
}
Image = new byte[DataLength];
br.read(Image);
b = br.read(); //Gap (17)
if (b != 17 && Reserved1 != 0 && Reserved1 != 8720)
{
System.out.println("Invalid 2nd gap for " + Path + Name);
}
Reserved5 = br.readShort();
}
public int getSize()
{
return (2 * 2) + (6 * 4) + PathLength + NameLength + DataLength;
}
}