package at.lux.fotoretrieval.retrievalengines; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.text.DecimalFormat; import java.util.*; import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.swing.JProgressBar; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; import at.lux.components.StatusBar; import at.lux.fotoretrieval.ResultListEntry; import at.lux.fotoretrieval.RetrievalToolkit; import at.lux.imageanalysis.ColorLayout; import at.lux.imageanalysis.EdgeHistogram; import at.lux.imageanalysis.JDomVisualDescriptor; import at.lux.imageanalysis.ScalableColor; import at.lux.imageanalysis.VisualDescriptorException; import at.lux.imageanalysis.db.SQLGenerator; import at.lux.imageanalysis.db.SQLGeneratorFactory; import at.lux.fotoannotation.ImageLoader; import com.drew.metadata.exif.ExifReader; import com.drew.metadata.exif.ExifDirectory; import com.drew.metadata.iptc.IptcReader; import com.drew.metadata.iptc.IptcDirectory; import com.drew.metadata.Metadata; import com.drew.metadata.Directory; /* * This file is part of Caliph & Emir. * * Caliph & Emir 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. * * Caliph & Emir 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 Caliph & Emir; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright statement: * -------------------- * (c) 2002-2005 by Mathias Lux (mathias@juggle.at) * http://www.juggle.at, http://caliph-emir.sourceforge.net */ /** * This file is part of Caliph & Emir * Date: 27.10.2005 * Time: 22:11:36 * * @author Mathias Lux, mathias@juggle.at */ public class DatabaseRetrievalEngine extends AbstractRetrievalEngine { private static Logger log = Logger.getLogger(DatabaseRetrievalEngine.class.getName()); private static int MAX_COUNT = 50; private static String driver = "org.apache.derby.jdbc.EmbeddedDriver"; private static SAXBuilder builder = new SAXBuilder(); private static final boolean OPTION_READ_FROM_XML = false; public List<ResultListEntry> getImagesBySemantics(String xPath, Vector objects, String whereToSearch, boolean recursive, JProgressBar progress) { throw new UnsupportedOperationException("Not implemented yet!"); } public List<ResultListEntry> getSimilarImages_fromSet(Set<Element> VisualDescriptorSet, String whereToSearch, boolean recursive, JProgressBar progress) { throw new UnsupportedOperationException("Not implemented yet!"); } public List<ResultListEntry> getSimilarImages(Element visualDescriptor, String whereToSearch, boolean recursive, JProgressBar progress) { List<ResultListEntry> results = new LinkedList<ResultListEntry>(); Namespace xsi = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); String descType = visualDescriptor.getAttributeValue("type", xsi); at.lux.imageanalysis.JDomVisualDescriptor desc = null; if (descType.equals("ColorLayoutType")) { desc = new ColorLayout(visualDescriptor); } else if (descType.equals("EdgeHistogramType")) { try { desc = new EdgeHistogram(visualDescriptor); } catch (VisualDescriptorException e) { e.printStackTrace(); } } else if (descType.equals("ScalableColorType")) { desc = new ScalableColor(visualDescriptor); } else { throw new UnsupportedOperationException("Not implemented yet!"); } if (desc != null) { // retrieve from the database: Connection conn = null; try { Class.forName(driver).newInstance(); conn = DriverManager.getConnection("jdbc:derby:imageDB"); Statement statement = conn.createStatement(); SQLGenerator sqlGenerator = SQLGeneratorFactory.getSQLGenerator(SQLGeneratorFactory.Database.Derby); String searchSelectStatement = sqlGenerator.getSearchSelectStatement(desc); if (progress != null) { progress.setString("Searching in DB ..."); } ResultSet rs = statement.executeQuery(searchSelectStatement); if (progress != null) { progress.setString("Reading results from DB ..."); } int count = 0; SAXBuilder builder = new SAXBuilder(); if (progress != null) { progress.setMinimum(0); progress.setMaximum(MAX_COUNT); progress.setValue(0); } while (rs.next() && count < MAX_COUNT) { String file = rs.getString(1); int index = file.lastIndexOf('.'); String descriptionFilePath = file.substring(0, index) + ".mp7.xml"; File descriptionFile = new File(descriptionFilePath); if (OPTION_READ_FROM_XML && descriptionFile.exists()) { try { Element e = builder.build(descriptionFile).getRootElement(); ResultListEntry entry = new ResultListEntry(rs.getDouble(2), e, descriptionFilePath); results.add(entry); } catch (Exception e1) { log.warning("Could not add entry to results: " + e1.toString()); } } else { String thumbnailPath = file.substring(0, file.lastIndexOf(File.separatorChar) + 1) + "tn_" + file.substring(file.lastIndexOf(File.separatorChar) + 1); File thumbnNail = new File(thumbnailPath); String creatorName="", description="", creationTime="", imageSize = ""; if (file.toLowerCase().endsWith(".jpg")) { Metadata metadata = new Metadata(); File imgFile = new File(file); new ExifReader(imgFile).extract(metadata); new IptcReader(imgFile).extract(metadata); Directory exifDirectory = metadata.getDirectory(ExifDirectory.class); if (metadata.containsDirectory(IptcDirectory.class)) { Directory iptc = metadata.getDirectory(IptcDirectory.class); if (iptc.containsTag(IptcDirectory.TAG_DATE_CREATED)) creationTime = iptc.getString(IptcDirectory.TAG_DATE_CREATED); if (iptc.containsTag(IptcDirectory.TAG_CAPTION)) description = iptc.getString(IptcDirectory.TAG_CAPTION); if (iptc.containsTag(IptcDirectory.TAG_COPYRIGHT_NOTICE)) creatorName = iptc.getString(IptcDirectory.TAG_COPYRIGHT_NOTICE); } if (metadata.containsDirectory(ExifDirectory.class)) { if (exifDirectory.containsTag(ExifDirectory.TAG_DATETIME_ORIGINAL)) creationTime = exifDirectory.getString(ExifDirectory.TAG_DATETIME_ORIGINAL); else if (exifDirectory.containsTag(ExifDirectory.TAG_DATETIME)) creationTime = exifDirectory.getString(ExifDirectory.TAG_DATETIME); else if (exifDirectory.containsTag(ExifDirectory.TAG_DATETIME_DIGITIZED)) creationTime = exifDirectory.getString(ExifDirectory.TAG_DATETIME_DIGITIZED); if (exifDirectory.containsTag(ExifDirectory.TAG_MAKE)) creatorName += exifDirectory.getString(ExifDirectory.TAG_MAKE) + " "; if (exifDirectory.containsTag(ExifDirectory.TAG_MODEL)) creatorName += exifDirectory.getString(ExifDirectory.TAG_MODEL); if (exifDirectory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_WIDTH) && exifDirectory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)) imageSize = exifDirectory.getString(ExifDirectory.TAG_EXIF_IMAGE_WIDTH) + "x" + exifDirectory.getString(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT); } } if (!thumbnNail.exists()) { thumbnailPath = file; } ResultListEntry entry = new ResultListEntry(rs.getDouble(2), thumbnailPath, file, creatorName, description, creationTime, file, imageSize); results.add(entry); } if (progress != null) { progress.setValue(++count); } } } catch (Exception e) { log.warning("Error: " + e.toString()); } finally { try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } return results; } public List<ResultListEntry> getImagesByXPathSearch(String xPath, String whereToSearch, boolean recursive, JProgressBar progress) { throw new UnsupportedOperationException("Not implemented yet!"); } public void indexAllImages(String pathToIndex, StatusBar statusBar) { File f = new File(pathToIndex); if (!f.exists()) return; DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance(); df.setMaximumFractionDigits(0); df.setMinimumIntegerDigits(2); Connection conn = null; try { statusBar.setStatus("Getting database connection."); SQLGenerator gen = SQLGeneratorFactory.getSQLGenerator(SQLGeneratorFactory.Database.Derby); Class.forName(gen.getDriverClassName()).newInstance(); conn = DriverManager.getConnection(gen.getConnectionURL()); Statement statement = conn.createStatement(); statusBar.setStatus("Creating database and tables."); // create tables: // todo: provide a clean entry to the current state of the database. Drop database or something else! String tableCreate = gen.getCreateTableStatement(JDomVisualDescriptor.Type.ColorLayout); try { statement.executeUpdate(tableCreate); } catch (SQLException e) { log.warning("Could not create table for ColorLayout:" + e.toString()); } tableCreate = gen.getCreateTableStatement(JDomVisualDescriptor.Type.EdgeHistogram); try { statement.executeUpdate(tableCreate); } catch (SQLException e) { log.warning("Could not create table for EdgeHistogram:" + e.toString()); } tableCreate = gen.getCreateTableStatement(JDomVisualDescriptor.Type.ScalableColor); try { statement.executeUpdate(tableCreate); } catch (SQLException e) { log.warning("Could not create table for ScalableColor:" + e.toString()); } String[] images = RetrievalToolkit.getAllImages(f, true); double len = images.length; long ms = System.currentTimeMillis(); for (int i = 0; i < images.length; i++) { String image = images[i]; try { String descriptionFile = image.substring(0, image.lastIndexOf('.')) + ".mp7.xml"; File description = new File(descriptionFile); if (description.exists()) { log.finest("Indexing from description file: " + descriptionFile); indexFileFromDescription(descriptionFile, image, gen, statement); } else { log.finest("Indexing from image file: " + image); indexFileFromImage(gen, image, statement); } double percent = ((double) i) / len * 100d; statusBar.setStatus("Finished " + df.format(percent) + "%"); } catch (Exception e) { e.printStackTrace(); } } log.info("ms = " + (System.currentTimeMillis() - ms)); } catch (Exception e) { log.warning(e.toString()); } } private void indexFileFromImage(SQLGenerator gen, String imageFilePath, Statement statement) throws IOException, SQLException { // TODO: The generation of image descriptors from file has to be made from smaller version of the image (speed and memory issues) BufferedImage img = ImageIO.read(new FileInputStream(imageFilePath)); img = ImageLoader.scaleImage(img, 512); ScalableColor sc = new ScalableColor(img); String sql = gen.getInsertStatement(imageFilePath, sc); statement.executeUpdate(sql); EdgeHistogram eh = new EdgeHistogram(img); sql = gen.getInsertStatement(imageFilePath, eh); statement.executeUpdate(sql); ColorLayout cl = new ColorLayout(img); sql = gen.getInsertStatement(imageFilePath, cl); statement.executeUpdate(sql); } private void indexFileFromDescription(String descriptionFilePath, String imageFilePath, SQLGenerator gen, Statement statement) throws JDOMException, IOException, SQLException, VisualDescriptorException { Document document = builder.build(new FileInputStream(descriptionFilePath)); List list = RetrievalToolkit.xpathQuery(document.getRootElement(), "//VisualDescriptor", null); for (int j = 0; j < list.size(); j++) { Element elem = (Element) list.get(j); List atts = elem.getAttributes(); for (Iterator it2 = atts.iterator(); it2.hasNext();) { Attribute att = (Attribute) it2.next(); if (att.getValue().equals("ScalableColorType")) { ScalableColor sc = new ScalableColor(elem); if (sc.getNumberOfCoefficients() == 256) { } else { // load from image file ... log.finest("Fallback from description file to image file for ScalableColor"); BufferedImage img = ImageIO.read(new FileInputStream(imageFilePath)); sc = new ScalableColor(img); } String sql = gen.getInsertStatement(imageFilePath, sc); statement.executeUpdate(sql); } else if (att.getValue().equals("ColorLayoutType")) { ColorLayout cl = new ColorLayout(elem); String sql = gen.getInsertStatement(imageFilePath, cl); statement.executeUpdate(sql); } else if (att.getValue().equals("DominantColorType")) { // nothing to do yet ... } else if (att.getValue().equals("EdgeHistogramType")) { EdgeHistogram eh = new EdgeHistogram(elem); String sql = gen.getInsertStatement(imageFilePath, eh); statement.executeUpdate(sql); } } } } }