1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
//
// 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;
}
|