//
// GetMetadataForFile.m
// DjVu
//
// Created by Jeff Sickel on 9/6/06.
// Copyright (c) 2006 Corpus Callosum Corporation. All rights reserved.
//
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#import <Foundation/Foundation.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "libdjvu/miniexp.h"
#include "libdjvu/ddjvuapi.h"
ddjvu_context_t *ctx;
ddjvu_document_t *doc;
#pragma mark -
void
handle(int wait)
{
const ddjvu_message_t *msg;
if (!ctx)
return;
if (wait)
msg = ddjvu_message_wait(ctx);
while ((msg = ddjvu_message_peek(ctx)))
{
switch(msg->m_any.tag)
{
case DDJVU_ERROR:
NSLog(@"%s", msg->m_error.message);
if (msg->m_error.filename)
NSLog(@"'%s:%d'",
msg->m_error.filename, msg->m_error.lineno);
return;
break; // never gets here
default:
break;
}
ddjvu_message_pop(ctx);
}
}
#pragma mark -
void
mdprint(NSMutableString *str, miniexp_t r)
{
if (miniexp_consp(r)) {
while (miniexp_consp(r)) {
mdprint(str, miniexp_car(r));
r = miniexp_cdr(r);
}
} else if (miniexp_stringp(r)) {
[str appendFormat:@" %s", miniexp_to_str(r)];
}
}
void
mdfprint(FILE *str, miniexp_t r)
{
if (miniexp_consp(r)) {
while (miniexp_consp(r)) {
mdfprint(str, miniexp_car(r));
r = miniexp_cdr(r);
}
} else if (miniexp_stringp(r)) {
fprintf(str, " %s", miniexp_to_str(r));
}
}
#pragma mark -
/* -----------------------------------------------------------------------------
Get metadata attributes from file
This function's job is to extract useful information your file format supports
and return it as a dictionary
----------------------------------------------------------------------------- */
Boolean GetMetadataForFile(void* thisInterface,
CFMutableDictionaryRef attributes,
CFStringRef contentTypeUTI,
CFStringRef pathToFile)
{
Boolean result = NO;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSProcessInfo *pinfo = nil;
NSString *path = (NSString *)pathToFile;
NSMutableDictionary *dictionary = (NSMutableDictionary *)attributes;
int npages;
miniexp_t expr;
pinfo = [NSProcessInfo processInfo];
if (! (ctx = ddjvu_context_create([[pinfo processName] cStringUsingEncoding:NSASCIIStringEncoding]))) {
NSLog(@"Cannot create djvu conext for '%@'.", path);
goto pop;
}
if (! (doc = ddjvu_document_create_by_filename(ctx, [path fileSystemRepresentation], TRUE))) {
NSLog(@"Cannot open djvu document '%@'.", path);
goto pop;
}
while (! ddjvu_document_decoding_done(doc))
handle(TRUE);
/* Pull any available metadata from the file at the specified path */
/* Return the attribute keys and attribute values in the dict */
/* Return TRUE if successful, FALSE if there was no data provided */
npages = ddjvu_document_get_pagenum(doc);
if (npages) {
int i;
ddjvu_status_t r;
ddjvu_pageinfo_t info;
double f = 1.0;
NSMutableString *buf = [NSMutableString string];
for (i=0; i<npages; i++) {
while ((expr=ddjvu_document_get_pagetext(doc,i,"page")) == miniexp_dummy)
handle(TRUE);
if (expr)
mdprint(buf, expr);
}
if ([buf length]) {
// if it has searchable text content... it's really not just an image
// we really want these to show up as documents
NSMutableArray *typeTree = [dictionary objectForKey:@"kMDItemContentTypeTree"];
if (typeTree && [typeTree containsObject:@"public.image"]) {
[typeTree removeObject:@"public.image"];
}
[dictionary setObject:buf forKey:(NSString *)kMDItemTextContent];
}
// this could be com.lizardtech.djvu or org.djvuzone.djvulibre.djvu
// either way still needs to pick up the files from com.lizardtech.djvu
// seems that public.djvu keeps getting picked up
/*
if (kCFCompareEqualTo != CFStringCompare(contentTypeUTI, CFSTR("com.lizardtech.djvu"), kCFCompareCaseInsensitive))
[dictionary setObject:@"org.djvuzone.djvulibre.djvu" forKey:(NSString *)kMDItemContentType];
// this is cheat that would purge the 'public.djvu' but then we need to
// figure out what to do about the actual kMDItemContentType to use
NSString *contentType = [dictionary objectForKey:(NSString*)kMDItemContentType];
if (contentType && [contentType isEqualToString:@"public.djvu"]) {
[dictionary removeObjectForKey:(NSString*)kMDItemContentType];
}
*/
while ((r = ddjvu_document_get_pageinfo(doc, 0, &info)) < DDJVU_JOB_OK)
handle(TRUE);
if (r >= DDJVU_JOB_FAILED)
goto pop;
f = 72.0 / (double)info.dpi;
#define DjAddIntKey(n,k) \
[dictionary setObject:[NSNumber numberWithInt:n] forKey:(NSString *)k]
DjAddIntKey(npages, kMDItemNumberOfPages);
DjAddIntKey(info.height, kMDItemPixelHeight);
DjAddIntKey(info.width, kMDItemPixelWidth);
DjAddIntKey((int)(f * info.height), kMDItemPageHeight);
DjAddIntKey((int)(f * info.width), kMDItemPageWidth);
[dictionary setObject:[NSString stringWithFormat:@"%d", info.version]
forKey:(NSString *)kMDItemVersion];
/** Image orientation:
0: no rotation 1: 90 degrees counter-clockwise
2: 180 degrees 3: 270 degrees counter-clockwise
trying to map to kMDItemOrientation:
Values are 0 is "Landscape" or 1 is "Portrait"
*/
DjAddIntKey(!(info.rotation), kMDItemOrientation);
[dictionary setObject:@"DjVu File" forKey:(NSString *)kMDItemKind];
// implement in next release ---
// kMDItemDescription
// kMDItemCodecs ??
result = YES;
}
pop:
if (doc)
ddjvu_document_release(doc);
if (ctx)
ddjvu_context_release(ctx);
[pool release];
return result;
}