Pentax raw support

Zach Bagnall <[email protected]> Fri, 12 Aug 2005 22:13:35 +1200
Newsgroups gmane.comp.gnome.apps.gqview.devel
Message-ID <[email protected]>
Hi all.

In keeping with the new format_xyz.[ch] scheme, attached is a first run 
at support for the Pentax PEF raw format. This was adapted from the 
format_fuji.[ch] files crossbred with some dcparse.c code.

It works fine for me with files from the Pentax *ist DS. Apparently the 
files from the *ist D are slightly different. I don't have any D files 
to test with but have put in a request on the dpreview forum.

Critisism? It's probably larger than it needs to be for starters.. and 
I'm not sure if more is required on the EXIF part - essential EXIF info 
is shown in GQview.

Zach.
gqview-2.1.1-ptx_pl1.diff (text/plain, 8 KB)
diff -urN gqview-2.1.1/src/Makefile.am gqview-2.1.1-ptx/src/Makefile.am
--- gqview-2.1.1/src/Makefile.am	2005-06-11 05:10:14.000000000 +1200
+++ gqview-2.1.1-ptx/src/Makefile.am	2005-08-12 17:21:22.000000000 +1200
@@ -92,6 +92,8 @@
 	format_nikon.h	\
 	format_olympus.c	\
 	format_olympus.h	\
+	format_pentax.c	\
+	format_pentax.h	\
 	format_raw.c	\
 	format_raw.h	\
 	fullscreen.c	\
diff -urN gqview-2.1.1/src/filelist.c gqview-2.1.1-ptx/src/filelist.c
--- gqview-2.1.1/src/filelist.c	2005-06-07 19:30:05.000000000 +1200
+++ gqview-2.1.1-ptx/src/filelist.c	2005-08-12 17:21:22.000000000 +1200
@@ -214,6 +214,7 @@
 	filter_add_if_missing("crw", "Canon raw format", ".crw;.cr2", TRUE);
 	filter_add_if_missing("raf", "Fujifilm raw format", ".raf", TRUE);
 	filter_add_if_missing("nef", "Nikon raw format", ".nef", TRUE);
+	filter_add_if_missing("pef", "Pentax raw format", ".pef", TRUE);
 }
 
 static GList *filter_to_list(const gchar *extensions)
diff -urN gqview-2.1.1/src/format_pentax.c gqview-2.1.1-ptx/src/format_pentax.c
--- gqview-2.1.1/src/format_pentax.c	1970-01-01 12:00:00.000000000 +1200
+++ gqview-2.1.1-ptx/src/format_pentax.c	2005-08-12 17:21:23.000000000 +1200
@@ -0,0 +1,223 @@
+/*
+ *  GQView
+ *  (C) 2005 John Ellis
+ *
+ *  Authors:
+ *    Original version 2005 Lars Ellenberg, base on dcraw by David coffin.
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "intl.h"
+
+#include "format_pentax.h"
+#include "format_raw.h"
+
+#include "exif.h"
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * Raw (PEF) embedded jpeg extraction for Pentax
+ *-----------------------------------------------------------------------------
+ */
+
+struct ptx_thumb_meta {
+  long offset;
+  long length;
+};
+
+long ptx_dget2(unsigned char **data_ptr, int le) {
+  int a = 0, b = 0;
+
+  a = *((*data_ptr)++);
+  b = *((*data_ptr)++);
+
+  return (le)
+    ? a + (b << 8)
+    : (a << 8) + b;
+}
+
+long ptx_dget4(unsigned char **data_ptr, int le) {
+  int a, b, c, d;
+
+  a = *((*data_ptr)++);
+  b = *((*data_ptr)++);
+  c = *((*data_ptr)++);
+  d = *((*data_ptr)++);
+
+  return (le)
+    ? a + (b << 8) + (c << 16) + (d << 24)
+    : (a << 24) + (b << 16) + (c << 8) + d;
+}
+
+
+int find_thumb(unsigned char *data, unsigned char **seek_ptr, struct ptx_thumb_meta *thumb, int level, int le) {
+  unsigned char *save, *save2;
+  int entries, tag, type, count, slen, val, i;
+  int comp=0;
+
+  int found_offset = 0, found_length = 0;
+
+  entries = ptx_dget2(seek_ptr, le);
+
+  while (entries--) {
+    save = *seek_ptr;
+    tag  = ptx_dget2(seek_ptr, le);
+    type = ptx_dget2(seek_ptr, le);
+    count= ptx_dget4(seek_ptr, le);
+
+    slen = count > 128 ? 128 : count;
+
+    save2 = *seek_ptr;
+
+    val = (type == 3)			/* short int */
+      ? ptx_dget2(seek_ptr, le)
+      : ptx_dget4(seek_ptr, le);
+
+    *seek_ptr = save2;
+
+    switch (tag) {
+    case 0x14a:			/* SubIFD tag */
+      save2 = *seek_ptr;
+
+      for (i = 0; i < count; i++) {
+        // printf("ptx: Reading SubIFD %d..\n", i);
+
+        *seek_ptr = save2 + i * 4;
+        *seek_ptr = data + ptx_dget4(seek_ptr, le);
+
+        if( find_thumb(data, seek_ptr, thumb, level+1, le) == 1 )
+          return 1;
+      }
+      break;
+    case 0x201:
+      thumb->offset = val;
+      found_offset = 1;
+      break;
+    case 0x202:
+      thumb->length = val;
+      found_length = 1;
+      break;
+    }
+
+    *seek_ptr = save + 12;
+  }
+
+  return found_offset && found_length ? 1 : 0;
+}
+
+
+gint format_pentax_raw(unsigned char *data, const guint len,
+		     guint *image_offset, guint *exif_offset)
+{
+	guint io = 0;
+	guint eo = 0;
+
+    unsigned char *seeking;
+    int order = 0, le = 0;
+    int ifd = 0;
+    long ifd_off = 0;
+
+    struct ptx_thumb_meta cur_thumb, best_thumb;
+
+    seeking = data;
+
+    order = ptx_dget2(&seeking, 0);
+
+    if(order == 0x4949) {
+      // printf("ptx: Byte order: little-endian\n");
+      le = 1;
+    }
+    else if(order == 0x4D4D) {
+      // printf("ptx: Byte order: big-endian\n");
+      le = 0;
+    }
+    else {
+      printf("ptx: Unknown byte order: 0x%04X! Assuming big-endian..\n", order);
+      le = 0;
+    }
+
+
+    int marker = ptx_dget2(&seeking, le);
+
+    if(marker == 42) {
+      // printf("ptx: TIFF format confirmed\n");
+    }
+    else {
+      printf("ptx: TIFF marker not found: %d\n", marker);
+      return FALSE;
+    }
+
+
+    // seeking = data;
+
+    best_thumb.length = 0;
+
+    while(ifd_off = ptx_dget4(&seeking, le)) {
+      seeking = data + ifd_off;
+
+      // printf("ptx: Reading IFD %d..\n", ifd++);
+
+      if( find_thumb(data, &seeking, &cur_thumb, 0, le) == 1 ) {
+        // printf("ptx: Found a thumbnail\n");
+
+        // simple fitness test: biggest means best 
+        if(cur_thumb.length > best_thumb.length) {
+          best_thumb.offset = cur_thumb.offset;
+          best_thumb.length = cur_thumb.length;
+        }
+      }
+    }
+    
+    if(best_thumb.length > 0) {
+      // printf("ptx: Best thumbnail found: Offset: 0x%08X; Length: %ld bytes.\n", best_thumb.offset, best_thumb.length);
+
+      io = best_thumb.offset;
+
+      /* verify jpeg marker */
+      if (memcmp(data+io, "\xff\xd8\xff", 3) != 0) {
+		return FALSE;
+      }
+    }
+    else {
+      // printf("ptx: No thumbnail found.\n");
+    }
+
+    /* EXIF info is always in the first TIFF segment */
+    eo = 0;
+
+	if (image_offset) *image_offset = io;
+	if (exif_offset) *exif_offset = eo;
+
+	// printf("ptx: raw Pentax format file\n");
+
+	return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * EXIF Makernote for Pentax
+ *-----------------------------------------------------------------------------
+ */
+
+gint format_pentax_makernote(ExifData *exif, unsigned char *tiff, guint offset,
+			   guint size, ExifByteOrder bo)
+{
+    return FALSE;
+}
+
diff -urN gqview-2.1.1/src/format_pentax.h gqview-2.1.1-ptx/src/format_pentax.h
--- gqview-2.1.1/src/format_pentax.h	1970-01-01 12:00:00.000000000 +1200
+++ gqview-2.1.1-ptx/src/format_pentax.h	2005-08-12 17:21:23.000000000 +1200
@@ -0,0 +1,37 @@
+/*
+ *  GQView
+ *  (C) 2005 John Ellis
+ *
+ *  Authors:
+ *    Original version 2005 Lars Ellenberg, base on dcraw by David coffin.
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+#ifndef __FORMAT_PENTAX_H
+#define __FORMAT_PENTAX_H
+
+
+#include "exif.h"
+
+
+gint format_pentax_raw(unsigned char *data, const guint len,
+		     guint *image_offset, guint *exif_offset);
+
+
+#define FORMAT_RAW_PENTAX { "pef", \
+			  FORMAT_RAW_MATCH_TIFF_MAKE, 0, "PENTAX Corporation ", 19, \
+			  "Pentax raw", format_pentax_raw }
+
+
+gint format_pentax_makernote(ExifData *exif, unsigned char *tiff, guint offset,
+			   guint size, ExifByteOrder bo);
+
+#define FORMAT_EXIF_PENTAX { FORMAT_EXIF_MATCH_MAKERNOTE, "PENTAX Corporation ", 19, "Pentax", format_pentax_makernote }
+
+
+
+#endif
+
diff -urN gqview-2.1.1/src/format_raw.c gqview-2.1.1-ptx/src/format_raw.c
--- gqview-2.1.1/src/format_raw.c	2005-06-13 11:25:08.000000000 +1200
+++ gqview-2.1.1-ptx/src/format_raw.c	2005-08-12 17:21:23.000000000 +1200
@@ -32,6 +32,7 @@
 #include "format_fuji.h"
 #include "format_nikon.h"
 #include "format_olympus.h"
+#include "format_pentax.h"
 
 
 /* so that debugging is honored */
@@ -53,6 +54,7 @@
 	FORMAT_RAW_CANON,
 	FORMAT_RAW_FUJI,
 	FORMAT_RAW_NIKON,
+	FORMAT_RAW_PENTAX,
 	{ NULL, 0, 0, NULL, 0, NULL, NULL }
 };
 
@@ -71,6 +73,7 @@
 	FORMAT_EXIF_FUJI,
 	FORMAT_EXIF_NIKON,
 	FORMAT_EXIF_OLYMPUS,
+	FORMAT_EXIF_PENTAX,
 	{ 0, NULL, 0, NULL }
 };