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