-
Notifications
You must be signed in to change notification settings - Fork 325
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for QuickTake 100/150 (#936)
* Add support for QuickTake 100/150 - Summary - Get/Set configuration - Get preview - Get PPM files - Get raw files (QTK format) Serial protocol reference: https://www.colino.net/wordpress/en/archives/2023/10/29/the-apple-quicktake-100-serial-communication-protocol/ QTKT / QTKN decoding algorithms from dcraw (GPL licensed). * Fix theorical integer overflows * Fix license after careful re-reading of dcraw's license * Fix quality mode index * Fix Quicktake 150 thumbnails * Fix unused variables and document thumbnail formats
- Loading branch information
1 parent
5858949
commit 9a07ec3
Showing
12 changed files
with
1,637 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,6 +84,9 @@ scanner. | |
Hans de Goede <[email protected]> | ||
ST2205 Picture Frame support (and usbdiskdirect port driver). | ||
|
||
Colin Leroy-Mira <[email protected]> | ||
Apple QuickTake 1x0 driver. | ||
|
||
========================================================================= | ||
git migration authors | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# -*- Makefile-automake -*- | ||
|
||
#EXTRA_DIST += %reldir%/ChangeLog | ||
|
||
|
||
EXTRA_LTLIBRARIES += quicktake1x0.la | ||
|
||
quicktake1x0_la_SOURCES = | ||
quicktake1x0_la_SOURCES += %reldir%/quicktake1x0.c | ||
quicktake1x0_la_SOURCES += %reldir%/qtk-thumbnail-decoder.c | ||
quicktake1x0_la_SOURCES += %reldir%/qtkt-decoder.c | ||
quicktake1x0_la_SOURCES += %reldir%/qtkn-decoder.c | ||
quicktake1x0_la_SOURCES += %reldir%/qtk-helpers.c | ||
quicktake1x0_la_SOURCES += %reldir%/quicktake1x0.h | ||
|
||
quicktake1x0_la_CFLAGS = $(camlib_cflags) | ||
quicktake1x0_la_CPPFLAGS = $(camlib_cppflags) | ||
quicktake1x0_la_DEPENDENCIES = $(camlib_dependencies) | ||
quicktake1x0_la_LDFLAGS = $(camlib_ldflags) | ||
quicktake1x0_la_LIBADD = $(camlib_libadd) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* qtk-helpers.c | ||
* | ||
Copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net | ||
* Copyright 2023, Colin Leroy-Mira <[email protected]> | ||
* | ||
* getbithuff() heavily inspired from dcraw.c. | ||
* | ||
* This library is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 2 of the License, or (at your option) any later version. | ||
* | ||
* This library 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 | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with this library; if not, write to the | ||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
* Boston, MA 02110-1301 USA | ||
*/ | ||
#include "config.h" | ||
|
||
#include "quicktake1x0.h" | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
#include <gphoto2/gphoto2-library.h> | ||
#include <libgphoto2/bayer.h> | ||
|
||
/* Write a basic .qtk header. This is imperfect and may not allow to open the | ||
* raw files we generate with the official, vintage Quicktake software, but it | ||
* is enough for dcraw to open and convert it. | ||
*/ | ||
void | ||
qtk_raw_header(unsigned char *data, const char *pic_format) | ||
{ | ||
char hdr[] = {0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x04,0x00,0x00,0x73,0xE4,0x00,0x01}; | ||
|
||
memcpy(hdr, pic_format, 4); | ||
memcpy(data, hdr, sizeof hdr); | ||
} | ||
|
||
char *qtk_ppm_header(int width, int height) { | ||
char *header = malloc(128); | ||
if (header == NULL) | ||
return NULL; | ||
|
||
snprintf(header, 127, | ||
"P6\n%d %d\n%d\n", | ||
width, height, 255); | ||
|
||
return header; | ||
} | ||
|
||
int qtk_ppm_size(int width, int height) { | ||
char *header; | ||
int len; | ||
|
||
header = qtk_ppm_header(width, height); | ||
if (header == NULL) { | ||
return GP_ERROR_NO_MEMORY; | ||
} | ||
|
||
len = (width * height * 3) + strlen(header); | ||
free(header); | ||
|
||
return len; | ||
} | ||
|
||
unsigned char getbithuff (int nbits, unsigned char **raw, ushort *huff) | ||
{ | ||
static unsigned bitbuf = 0; | ||
static int vbits = 0; | ||
unsigned char c; | ||
int h; | ||
unsigned char *ptr; | ||
|
||
if (nbits == -1) { | ||
bitbuf = 0; | ||
vbits = 0; | ||
return 0; | ||
} | ||
|
||
ptr = *raw; | ||
if (vbits < nbits) { | ||
c = *ptr; | ||
ptr++; (*raw)++; | ||
bitbuf = (bitbuf << 8) + c; | ||
vbits += 8; | ||
} | ||
c = bitbuf << (32-vbits) >> (32-nbits); | ||
|
||
if (!huff) | ||
vbits -= nbits; | ||
else { | ||
h = huff[c]; | ||
vbits -= h >> 8; | ||
c = (unsigned char) h; | ||
} | ||
|
||
return c; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/* qtkt-decoder.c | ||
* | ||
* Copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net | ||
* Copyright 2023, Colin Leroy-Mira <[email protected]> | ||
* | ||
* QTKT decoder heavily inspired from dcraw.c. | ||
* | ||
* This library is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 2 of the License, or (at your option) any later version. | ||
* | ||
* This library 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 | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with this library; if not, write to the | ||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
* Boston, MA 02110-1301 USA | ||
*/ | ||
#include "config.h" | ||
|
||
#include "quicktake1x0.h" | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
#include <gphoto2/gphoto2-library.h> | ||
|
||
static int qt100_thumbnail_decode(unsigned char *raw, unsigned char **out) { | ||
int s, v, p1, p2, r, g, b, len; | ||
char *header; | ||
unsigned char *ptr; | ||
|
||
header = qtk_ppm_header(QT1X0_THUMB_WIDTH, QT1X0_THUMB_HEIGHT); | ||
|
||
len = qtk_ppm_size(QT1X0_THUMB_WIDTH, QT1X0_THUMB_HEIGHT); | ||
*out = ptr = calloc(1, len); | ||
if (ptr == NULL) { | ||
free(header); | ||
return GP_ERROR_NO_MEMORY; | ||
} | ||
|
||
strcpy((char *)ptr, header); | ||
ptr += strlen(header); | ||
free(header); | ||
|
||
/* The 2400 bytes buffer represent 80x60 pixels at 4bpp. | ||
* It is very logical to decode as each half-byte represents | ||
* the next pixel. | ||
*/ | ||
for (s = 0; s < QT1X0_THUMB_SIZE; s++) { | ||
v = raw[s]; | ||
|
||
p1 = ((v >> 4) & 0b00001111) << 4; | ||
p2 = ((v >> 0) & 0b00001111) << 4; | ||
|
||
/* FIXME do color thumbnails */ | ||
r = g = b = p1; | ||
*ptr++ = r; | ||
*ptr++ = g; | ||
*ptr++ = b; | ||
|
||
r = g = b = p2; | ||
*ptr++ = r; | ||
*ptr++ = g; | ||
*ptr++ = b; | ||
} | ||
|
||
return GP_OK; | ||
} | ||
|
||
static int qt150_thumbnail_decode(unsigned char *raw, unsigned char **out) { | ||
int len; | ||
char *header; | ||
unsigned char *ptr; | ||
unsigned char *cur_in; | ||
unsigned char line[QT1X0_THUMB_WIDTH*2], *cur_out; | ||
int i, a, b, c, d, y; | ||
|
||
header = qtk_ppm_header(QT1X0_THUMB_WIDTH, QT1X0_THUMB_HEIGHT); | ||
|
||
len = qtk_ppm_size(QT1X0_THUMB_WIDTH, QT1X0_THUMB_HEIGHT); | ||
*out = ptr = calloc(1, len); | ||
if (ptr == NULL) { | ||
free(header); | ||
return GP_ERROR_NO_MEMORY; | ||
} | ||
|
||
strcpy((char *)ptr, header); | ||
ptr += strlen(header); | ||
free(header); | ||
|
||
/* The 2400 bytes buffer represent 80x60 pixels at 4bpp. | ||
* It is harder to decode as the half-bytes do not | ||
* represent one pixel after the other. | ||
* Every 80 bytes represent 2 lines. The first 60 bytes | ||
* (120 half-bytes) represent pixels at: | ||
* 0,y ; 1,y ; 0,y+1 ; 2,y ; 3,y ; 2,y+1 ; etc | ||
* The last 20 bytes (40 half-bytes) represent the pixels | ||
* at 1,y+1 ; 3,y+1 ; 5,y+1 ; etc | ||
*/ | ||
cur_in = raw; | ||
for (y = 0; y < QT1X0_THUMB_HEIGHT; y+=2) { | ||
cur_out = line; | ||
for (i = 0; i < QT1X0_THUMB_WIDTH; i++) { | ||
c = *cur_in++; | ||
a = (((c>>4) & 0b00001111) << 4); | ||
b = (((c) & 0b00001111) << 4); | ||
*cur_out++ = a; | ||
*cur_out++ = b; | ||
} | ||
cur_out = line; | ||
|
||
for (i = 0; i < QT1X0_THUMB_WIDTH * 2; ) { | ||
if (i < QT1X0_THUMB_WIDTH*3/2) { | ||
a = *cur_out++; | ||
b = *cur_out++; | ||
c = *cur_out++; | ||
|
||
*(ptr) = a; | ||
*(ptr + 3) = b; | ||
*(ptr + 3*QT1X0_THUMB_WIDTH) = c; | ||
ptr++; | ||
|
||
*(ptr) = a; | ||
*(ptr + 3) = b; | ||
*(ptr + 3*QT1X0_THUMB_WIDTH) = c; | ||
ptr++; | ||
|
||
*(ptr) = a; | ||
*(ptr + 3) = b; | ||
*(ptr + 3*QT1X0_THUMB_WIDTH) = c; | ||
ptr++; | ||
|
||
i+=3; | ||
ptr+=3; | ||
} else { | ||
i++; | ||
ptr += 3; | ||
|
||
d = *cur_out++; | ||
*(ptr++) = d; | ||
*(ptr++) = d; | ||
*(ptr++) = d; | ||
} | ||
} | ||
} | ||
|
||
return GP_OK; | ||
} | ||
|
||
int qtk_thumbnail_decode(unsigned char *raw, unsigned char **out, Quicktake1x0Model model) { | ||
if (model == QUICKTAKE_MODEL_100) { | ||
return qt100_thumbnail_decode(raw, out); | ||
} else { | ||
return qt150_thumbnail_decode(raw, out); | ||
} | ||
} |
Oops, something went wrong.