summaryrefslogtreecommitdiff
path: root/camlibs/jl2005c
diff options
context:
space:
mode:
authorTheodore Kilgore <kilgota@auburn.edu>2010-04-20 14:41:27 +0000
committerTheodore Kilgore <kilgota@auburn.edu>2010-04-20 14:41:27 +0000
commitbae29870f863054ac44863fcf07eba598f3b21ff (patch)
tree3b45ccb43d38d0568fd2db096ebd37565c2e5db1 /camlibs/jl2005c
parentd11333a841268aa55c5f425054aff715f7ea89e3 (diff)
downloadlibgphoto2-bae29870f863054ac44863fcf07eba598f3b21ff.tar.gz
jl2005c:Decompression enabled. Camlib is fully functional
git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@13007 67ed7778-7388-44ab-90cf-0a291f65f57c
Diffstat (limited to 'camlibs/jl2005c')
-rw-r--r--camlibs/jl2005c/ChangeLog14
-rw-r--r--camlibs/jl2005c/Makefile-files10
-rw-r--r--camlibs/jl2005c/README.jl2005bcd-compression342
-rw-r--r--camlibs/jl2005c/README.jl2005c266
-rw-r--r--camlibs/jl2005c/img_enhance.c252
-rw-r--r--camlibs/jl2005c/img_enhance.h35
-rw-r--r--camlibs/jl2005c/jl2005bcd_decompress.c280
-rw-r--r--camlibs/jl2005c/jl2005bcd_decompress.h30
-rw-r--r--camlibs/jl2005c/jl2005c.c390
-rw-r--r--camlibs/jl2005c/jl2005c.h32
-rw-r--r--camlibs/jl2005c/jpeg_memsrcdest.c309
-rw-r--r--camlibs/jl2005c/jpeg_memsrcdest.h9
-rw-r--r--camlibs/jl2005c/library.c168
13 files changed, 1655 insertions, 482 deletions
diff --git a/camlibs/jl2005c/ChangeLog b/camlibs/jl2005c/ChangeLog
index 9483beef5..b564b5568 100644
--- a/camlibs/jl2005c/ChangeLog
+++ b/camlibs/jl2005c/ChangeLog
@@ -1,3 +1,17 @@
+2010-04-19 Theodore Kilgore <kilgota@auburn.edu>
+ * README.jl2005c: revised.
+ * README.jl2005bcd-compression: added.
+ * img_enhance.[c,h]: added.
+ * jl2005bcd_decompress.[c,h]: added. Decompresses data, autodetects
+ thumbnails if present in raw data, can also process the
+ thumbnails.
+ * jpeg_memsrcdest.[c,h]: added (helper files for decompression).
+ NOTE: Decompression algorithm is completely solved. Camlib
+ should be added as "standard" part of libgphoto2.
+
+2010-04-18 Theodore Kilgore <kilgota@auburn.edu>
+ * library.c: Yet another camera found.
+
2010-04-14 Theodore Kilgore <kilgota@auburn.edu>
* library.c: Yet another camera found.
diff --git a/camlibs/jl2005c/Makefile-files b/camlibs/jl2005c/Makefile-files
index 82fa634c4..2d6547787 100644
--- a/camlibs/jl2005c/Makefile-files
+++ b/camlibs/jl2005c/Makefile-files
@@ -1,11 +1,15 @@
-EXTRA_DIST += jl2005c/README.jl2005c
-camlibdoc_DATA += jl2005c/README.jl2005c
+EXTRA_DIST += jl2005c/README.jl2005c jl2005c/README.jl2005bcd-compression
+camlibdoc_DATA += jl2005c/README.jl2005c jl2005c/README.jl2005bcd-compression
EXTRA_LTLIBRARIES += jl2005c.la
jl2005c_la_SOURCES = jl2005c/library.c\
jl2005c/jl2005c.c\
- jl2005c/jl2005c.h
+ jl2005c/jl2005bcd_decompress.c\
+ jl2005c/jl2005bcd_decompress.h\
+ jl2005c/jl2005c.h\
+ jl2005c/img_enhance.c\
+ jl2005c/img_enhance.h
jl2005c_la_LDFLAGS = $(camlib_ldflags)
jl2005c_la_DEPENDENCIES = $(camlib_dependencies)
jl2005c_la_LIBADD = $(camlib_libadd)
diff --git a/camlibs/jl2005c/README.jl2005bcd-compression b/camlibs/jl2005c/README.jl2005bcd-compression
new file mode 100644
index 000000000..134b74df7
--- /dev/null
+++ b/camlibs/jl2005c/README.jl2005bcd-compression
@@ -0,0 +1,342 @@
+History of the reverse engineering of the compression used in the
+ JL2005B, JL2005C, and JL2005D cameras
+-----------------------------------------------------------
+
+All of these cameras use a compression format which is derived from JPEG
+but is in several respects non-standard, making the job of understanding
+it very difficult.
+
+Thus, after several years have passed by, during which it has been possible
+to get the raw files out of these cameras but not possible to do anything
+with the data in the raw files, a task force was started to deal with the
+problem. The results of the reverse engineering work by Adam Rubin and
+Bertrik Sikken were shared by means of a wiki page with Hans de Goede
+and me (Theodore Kilgore). What is known as of April 10, 2010 is listed
+at
+
+<http://sourceforge.net/apps/mediawiki/gphoto/index.php?title=ImageEncoding
+Jeilin2005CD>
+
+A dump of this page is given below.
+
+The description provided in this webpage was used to write the decompression
+code. The objective was to provide output in a standard, uncompressed bitmap
+format in order to provide the opportunity to apply whatever techniques for
+image enhancement or postprocessing that might be needed. The format chosen
+for this was PPM, used in many other camera libraries in libgphoto2.
+
+Faced with the choice of incorporating a modified variant of libjpeg in
+the decompression code, for ultimate inclusion in libgphoto2/camlibs/jl2005c,
+or else finding a way to use the standard library functions of libjpeg,
+Hans de Goede found a way to use the standard library functions with minimal
+modification.
+
+The details of how the decompression algorithm needs to work are well laid
+out in the dump of the wiki web page (below). See especially the section
+called "Entropy coded data."
+
+A modified version of the file jpeg_memsrcdest.c is part of the
+decompression package here. The copyright notice of the original file is
+preserved inside the file, and it is also copied here:
+
+/*
+ * jpeg_memsrcdest.c and jidctflt.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ *
+ * The authors make NO WARRANTY or representation, either express or implied,
+ * with respect to this software, its quality, accuracy, merchantability, or
+ * fitness for a particular purpose. This software is provided "AS IS", and you,
+ * its user, assume the entire risk as to its quality and accuracy.
+ *
+ * This software is copyright (C) 1991-1998, Thomas G. Lane.
+ * All Rights Reserved except as specified below.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute this
+ * software (or portions thereof) for any purpose, without fee, subject to these
+ * conditions:
+ * (1) If any part of the source code for this software is distributed, then this
+ * README file must be included, with this copyright and no-warranty notice
+ * unaltered; and any additions, deletions, or changes to the original files
+ * must be clearly indicated in accompanying documentation.
+ * (2) If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the work of
+ * the Independent JPEG Group".
+ * (3) Permission for use of this software is granted only if the user accepts
+ * full responsibility for any undesirable consequences; the authors accept
+ * NO LIABILITY for damages of any kind.
+ *
+ * These conditions apply to any software derived from or based on the IJG code,
+ * not just to the unmodified library. If you use our work, you ought to
+ * acknowledge us.
+ *
+ * Permission is NOT granted for the use of any IJG author's name or company name
+ * in advertising or publicity relating to this software or products derived from
+ * it. This software may be referred to only as "the Independent JPEG Group's
+ * software".
+ *
+ * We specifically permit and encourage the use of this software as the basis of
+ * commercial products, provided that all warranty or liability claims are
+ * assumed by the product vendor.
+ */
+
+
+Below is a dump of:
+<http://sourceforge.net/apps/mediawiki/gphoto/index.php?title=ImageEncoding
+Jeilin2005CD>
+Made on 10 April 2010.
+
+mageEncodingJeilin2005CD
+From gphoto
+Jump to: navigation, search
+Contents
+
+ * 1 Introduction
+ * 2 Image format
+ o 2.1 Image header
+ o 2.2 Thumbnail image
+ o 2.3 Entropy coded data
+ + 2.3.1 Huffman table
+ + 2.3.2 Quantisation table
+
+Introduction
+
+This page describes the image format used in cameras with the Jeilin 2005
+B/C/D chip.
+
+This chip stores images in a non-standard JPEG-like format. To understand
+the information on this page, it is recommended to have a basic
+understanding of JPEG compression.
+Image format
+
+The image file seems to consist of the following parts:
+
+ * a 16-byte image header
+ * some kind of thumbnail of the actual image
+ * entropy-coded JPEG-like image data
+
+These parts are described in the following paragraphs.
+Image header
+
+The 16-byte image header is the very first thing in an raw image file
+(copied directly from the PAT) and contains basic image meta-data. All words
+are stored big-endian, and block size is 0x80 bytes for the JL2005B and
+0x200 bytes for the JL2005C and JL2005D chips. "Something happens" means
+that I don't know yet what, if any, the effects are. Additions and
+corrections to this section are welcome!
+Byte Meaning
+0x00 Always observed as zero so far, but something happens if it's 0x01
+or 0x21, and something else happens if it's 0x11.
+0x01 Camera ID or attributes? If bit 4 is set, gamma correction is
+enabled. If a value elsewhere is set, then if bit 7 is set, then bits 2 and
+3 do something.
+0x02 Bit 4: 0 = lower compression ratio, 1 = higher compression ratio
+
+Bits 0-1: resolution of photo (camera-dependent), 00 = CIF or VGA, 01 = QCIF
+or QVGA, 02 = SVGA if supported
+
+All other bits have always been observed as zero so far.
+0x03 Bits 0-6 = image quality factor (100% is best quality), specifics
+below under "Quantization Table"
+
+Bit 7: if set, read the raw file into memory but do not decode it
+0x04 Image height, in units of 8 pixels
+0x05 Image width, in units of 8 pixels
+0x06-0x07 Total size of image data in blocks, including thumbnail if
+any
+0x08 When writing the raw file, if byte 0x03 bit 7 is set (decode image)
+and byte 0x02 bit 4 is set (higher compression), then a workspace area of (
+width * (photo height in pixels - this byte) / 2 ) bytes is allocated,
+instead of width * height.
+
+When reading in the raw file, if byte 0x03 bit 7 is clear and byte 0x02 bit
+4 is clear, the value used later on for image height in pixels follows the
+same equation.
+
+I don't (yet) know why either of these are done.
+0x09 If there's a thumbnail image (as detailed below), the thumbnail's
+length in blocks is this byte divided by four. So far, 0x60 or 0xf0 for this
+byte means a thumbnail (resolution 96x64 or 128x120 pixels respectively).
+The significance of any other value is not known.
+0x0a Another camera ID or attributes? Bits 0-1 do something.
+0x0b Unknown -- always observed as zero so far
+0x0c-0x0d Starting address of photo in storage medium, in blocks.
+0x0e-0x0f Word, function unknown.
+
+(part of this table was derived from the jl2005c code already in gphoto)
+Thumbnail image
+
+Directly following the image header, sometimes, is a thumbnail image. See
+"Image Header" byte 0x09, above, to detect whether one is present.
+
+From observation:
+
+ * JL2005B -- no thumbnails
+ * JL2005C -- some have thumbnails; if so, 96x64 pixels
+ * JL2005D -- many have thumbnails; if so, 128x120 pixels
+
+Note that the aspect ratio of the thumbnails is not necessarily the same as
+that of the picture.
+
+Pixels in the thumbnail are encoded left-to-right, top-to-bottom. Each pixel
+of the thumbnail image is represented by a 16-bit word, big endian encoded,
+with bits assigned to R, G and B components as follows (a.k.a. RGB565):
+
+ * bit 15-11: red
+ * bit 10- 5: green
+ * bit 4 - 0: blue
+
+Entropy coded data
+
+Following the thumbnail image (if present), is the entropy coded data. This
+data looks a bit like the entropy coded data used in JPEG images.
+
+
+The image is sub-divided as follows:
+
+ * The image is divided in vertical strips of 16 pixels wide and height
+ pixels high, so the whole image consists of width/16 strips, encoded
+ from left-to-right.
+ * Each strip is subdivided in MCUs (minimum coded unit) of 16x16 pixels,
+ encoded from top-to-bottom.
+ * Each MCU consists of 4 blocks of 8x8 pixels each, containing pixels
+from the Bayer mosaicing pattern. They appear in the following order:
+ o First the green pixels of the top half of the 16x16 pixel MCU
+ o Then the green pixels of the bottom half of the 16x16 pixel MCU
+ o Then the red pixels for the entire MCU
+ o Finally the blue pixels for the entire MCU
+ * The order of the red, green and blue pixels in the Bayer pattern is as
+ follows: RG/GB. This means the first line of a MCU starts with a red
+ pixel, then a green pixel from the first green line from the first
+ green block. The second line starts with a green pixel from the second
+ green line from the first green block, then a blue pixel.
+
+
+With respect to the encoding:
+
+ * MCUs in a strip are encoded like a JPEG MCU. There are only two
+ huffman tables (one for the DC and for the AC coefficients) and there
+ is only one quantisation table.
+ * The blue and red 8x8 blocks inside an MCU each have a DC coefficient
+ that is differential to the DC coefficient of the same block in the
+ previous MCU, like in standard JPEG.
+ * The two green 8x8 blocks inside an MCU share a single DC coefficient,
+ so the DC coefficient of the first green block is differential to the
+ one from the second block and vice versa.
+ * The DC coefficients in the first MCU in a strip are not differential,
+ but contain the absolute value.
+ * 0xFF bytes in the entropy coded data are followed by 0x00 stuff-bytes,
+just like they are in JPEG.
+ * A strip is encoded as a bunch of MCUs, followed by 0xFFD9 (this is the
+End-Of-Image marker in JPEG) and padded with 0x00 until the next 16-byte
+ aligned address. The start of the entropy coded stream is considered
+to be address 0 in this case.
+ * An image is encoded as a bunch of strips, followed by bogus data until
+the end of the total image data (which is a multiple of 0x80 or 0x200).
+
+Huffman table
+
+The Huffman table used is the recommended table for the luminance component
+from the JPEG specification. In C, encoded as a JPEG DHT table, this looks
+like:
+
+static const unsigned char dht_table[] = {
+ 0xFF, 0xC4,
+ 0x00, 0xD2
+
+ // luma DC
+ 0x00,
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+0x0B,
+
+ // luma AC
+ 0x10,
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
+0x04, 0x00, 0x00, 0x01, 0x7D,
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41,
+0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1,
+0xC1, 0x15, 0x52, 0xD1, 0xF0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19,
+0x1A, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
+0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84,
+0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2,
+0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
+0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
+ 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
+ 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3,
+0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
+ 0xF9, 0xFA
+};
+
+Quantisation table
+
+The magnitude of the elements in the quantisation table in JPEG-like
+encoding basically determines the compromise between image quality and image
+size. A quantisation table with small values results in a high quality but
+large image and a quantisation table with big values results in a low
+quality but small image.
+
+The quantisation table used in the Jeilin encoding is a scaled version of a
+base quantisation table. This base quantisation table is very similar
+(within a few percent) to the one given in the JPEG specification.
+
+The scale factor (in percents) is calculated from the quality value from the
+header (call it q) in the following way:
+
+ * q = 0: scale factor = 5000
+ * 0 < q <= 50: scale factor = 5000 / q
+ * 50 < q <= 100: scale factor = 2 * (100 - q)
+ * q > 100: assume q = 100
+
+Scaling is done by multiplying each element of the table by the scale
+factor, dividing by 100 and rounding to the nearest integer value. The
+minimum value of an element after scaling is 1 and the maximum value is 255.
+Retrieved from
+"http://sourceforge.net/apps/mediawiki/gphoto/index.php?title=ImageEncodingJeilin2005CD"
+Views
+
+ * Page
+ * Discussion
+ * View source
+ * History
+
+Personal tools
+
+Navigation
+
+ * Main Page
+ * Community portal
+ * Current events
+ * Recent changes
+ * Random page
+ * Help
+
+Search
+
+Toolbox
+
+ * What links here
+ * Related changes
+ * Special pages
+ * Printable version
+ * Permanent link
+
+Powered by MediaWiki
+
+ * This page was last modified on 7 April 2010, at 00:05.
+ * This page has been accessed 167 times.
+
+
+© 2010 Geeknet, Inc. Terms of Use Privacy Policy
+
diff --git a/camlibs/jl2005c/README.jl2005c b/camlibs/jl2005c/README.jl2005c
index 01d71f2ea..60e58727e 100644
--- a/camlibs/jl2005c/README.jl2005c
+++ b/camlibs/jl2005c/README.jl2005c
@@ -1,192 +1,144 @@
JEILIN STILLCAM DRIVER
+
Copyright Theodore Kilgore <kilgota@auburn.edu> September 4, 2007. Most recent
-update is April 16, 2009.
+update is April 19, 2010.
-(Everything in libgphoto2/camlibs/jeilin is LGPL-licensed, including this
-README. See any of the source files for a more complete statement of the
+(Everything in libgphoto2/camlibs/jeilin is LGPL-licensed, including this
+README. See any of the source files for a more complete statement of the
license.)
INTRODUCTION
-This driver is intended to support cameras containing the JL2005C chip from
-Jeilin Technologies and also the similar cameras which have in them the
-JL2005B or the JL2005D. The interface is proprietary, and these cameras are
-supported commercially only in Windows. Jeilin Technologies also manufactures
-chips which go into mass storage cameras. Those cameras, not to be confused
-with these, can be accessed directly using mass storage support. The company
-also makes another camera controller chip with proprietary interface, the
-JL2005A. Cameras with that chip are supported in libgphoto2/camlibs/jl2005a.
-Those cameras are much better supported than are the JL2005B/C/D cameras. But
-if you want to read about one of those JL2005A cameras, please look in
-camlibs/jl2005a, not here.
-
-THIS IS EXPERIMENTAL CODE
-
-This code in this directory is included in the source release of libgphoto2,
-from version 2.4.4 onward. However, the code in this directory does not get
-compiled and installed by default. There is a reason for that:
-
-THIS IS EXPERIMENTAL CODE
-
-With the libgphoto2 source tree in hand, you have to follow the instructions
-in INSTALL to compile and install it. If you have never done this procedure,
-then perhaps you would be very well advised to try to do this first without
-attempting to install support for JL2005C cameras. The code in
-libgphoto2/camlibs/jl2005c does not compile by default if you follow only the
-standard procedures, as I said, so do not expect it to be compiled if you did
-not do anything special.
-
-If you really want to compile and install the support for the JL2005C cameras,
-then there are at least two methods:
-
-1. At the ./configure step during the compilation of the main libgphoto2 tree,
-the option
-
-./configure --with-camlibs=all,jl2005c
-
-should to "turn on" the camlib (note that "all" repeats the default option,
-which explicitly excludes the jl2005c so you must explicitly add it here).
-Then you can proceed as normally by doing make, then make install, and the
-JL2005C support will be made and installed with all the rest.
-
-An alternative to the above is
-
-2. If you have already installed the entire libgphoto2 (except for the jl2005c
-library) you can go into libgphoto2/camlibs and (as root or su) from there do
-
-make CAMLIBS="jl2005c.la" install-camlibs
-
-Then, this subdirectory will be compiled and installed with the others.
-
-Once you have installed support for the jl2005c you should be ready to try out
-the camera and to help me to figure out a decent decompression algorithm. For,
-the camera uses data compression, and the method of the compression is unknown.
-
-Oh, if you are not experienced in libgphoto2 type things, you will notice that
-at this point you can only use this camera as root. To solve that problem,
-follow the instructions in libgphoto2/packaging/generic if you are using udev
-(usually associated with using a recent 2.6.x Linux kernel), or if you know
-you are using hotplugging then follow the instructions in
-libgphoto2/packaging/linux-hotplug (probably you use hotplugging only if you
-are still using a 2.4.x Linux kernel). You can either set up a group called
-"camera" or let all users use the camera. Me, I let all users use all cameras
-hooked to my home system, because "all users" pretty much consists of me,
-myself, and I.
-
-As an alternative to what is in the previous paragraph, you can just go to the
-directory /etc/udev/rules.d and edit the existing rules file for libgphoto by
-adding a line for the new camera. To do this, just copy a line which relates to
-some other camera, and change the USB vendor and product numbers to match.
-
+This driver is intended to support the cameras with the USB Vendor:Product
+number 0x0979:0x0227. These cameras all have a controller chip from Jeilin
+Technologies, either the JL2005B or the JL2005C or the JL2005D. Both the
+control interface and the compressed data format of these cameras are
+proprietary, and these cameras are supported commercially only in Windows.
+In spite of some features in common, these cameras also show a very large
+variation. Some of them are very rudimentary, with a maximum resolution
+of 352x288, and there are also more expensive models with a maximum resolution
+of 1280x1024. Some of them have viewing screens on the rear and some
+do not. Some of the cameras also produce separate thumbnails, which, when
+present, are downloaded as part of the raw data for the image. Accommodation
+of this very wide range of features has been a special challenge in writing
+this support library, especially when it seems that not all of the OEM
+software available for a given supported camera will work for all the others.
+
+Jeilin Technologies also manufactures chips which go into mass storage cameras. Those cameras, not to be confused
+with these, can be accessed directly using mass storage support. The company
+also makes another camera controller chip with proprietary interface, the
+JL2005A. Cameras with that chip are supported in libgphoto2/camlibs/jl2005a.
+If you want to read about one of those JL2005A cameras, please look in
+camlibs/jl2005a, not here.
+
+The JL2005C camera library has been included in the release versions of
+libgphoto2 ever since libgphoto2-2.4.4, but it was so configured as not
+to compile by default. The reason for that was that the cameras use a nasty
+data compression algorithm which was very difficult to figure out. So long
+as the data coming out of the camera could not be decompressed, it was not
+of any use to support these cameras except for experimental purposes. This
+situation has recently changed. A task force was set up to deal with the
+problem, and success has been achieved. As of April 2010, it seems to be
+possible reliably to get the photos out of these cameras in usable form.
+For details concerning the solution of the decompression problem, please
+see the file README.jl2005bcd-compression which is supposed to be included
+with the documentation for libgphoto2/camlibs/jl2005c. If for any reason
+you do not have this file, it can be found at <gphoto.svn.sourceforge.net>
+in the directory trunk/libgphoto2/camlibs/jl2005c. My thanks to the other
+members of the team who worked together to solve the longstanding problem.
+Thanks to Adam Rubin and Bertrik Sikken for doing the research needed to
+gather the information found at
+
+<http://sourceforge.net/apps/mediawiki/gphoto/index.php?title=ImageEncoding
+Jeilin2005CD>
+
+And thanks to Hans de Goede for writing the decompression algorithm.
WHAT DOES THIS CAMERA LIBRARY CURRENTLY DO?
-It will hook up the camera, and you ought to be able to download a dump of any
-photo data in it using the command gphoto2 --get-all-raw-data. The main reason
-you might want to do this right now is to participate in the development of
-support for these cameras by experimenting with the still-unknown decompression
-algorithm which they use. Help is welcome. That is why this library is made
-public. Some other infrastructural work has been done, too. The code supports
-the functioning of these cameras sufficiently well, that you ought to be able
-to run gphoto --shell and it even ought to be possible to run a sequence like
-
-get-raw jl_026.ppm
-
-followed by the next gphoto2 shell command
-
-get-raw jl_001.ppm
-
-without corruption of data.
-
-
-I _think_ that I got the data size for the photos all correct, but I am not
-sure about that, for the obvious reason that I cannot do finished photos.
-(Update 01/05/08: It has been verified for the JL2005D, the raw image data
-obtained by the OEM driver is the same as what this code is providing. I have
-been unable to verify this for a JL2005B camera, also unable to verify for a
-JL2005C). The camera does download without glitches all the photos in it, even
-if it is full, and will save them as raw files. I have taken the trouble to
-make each raw file slightly longer by adding the 16-byte line related to it
-which is found in the photo allocation table, the first block of data to be
-downloaded from the camera.
-
-
-The reason why one cannot make finished photos right now is that these
-cameras use a proprietary compression algorithm which Jeilin Technologies is
-currently not interested in sharing with us. Thus, the main purpose of
-posting this driver is to publish the code so that further experimentation and
-development can more easily take place.
-
-
-!!!!!!!!!!!!!!! A SPECIAL WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-How to compute the size and location of a photo's raw data to be downloaded,
-is probably correct now for all of these cameras. However, the basis for this
-computation remains in the realm of guesswork. Be on the lookout for the
-camera taking an inordinate amount of time to do some simple task such as to
-count the number of photos in it using gphoto2 -n. That is probably a sign of
-something previously gone wrong, which has jammed the camera. It may be needed
-to replug it in order to clear the jam.
-
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-ADDITIONAL REMARKS:
-
-These cameras use a proprietary compression algorithm, as already said. As a
-result, progress in the development of this driver will inevitably be slow.
-
-Another challenge is that these cameras use an extremely primitive command
-structure. The only thing that the camera knows how to do is to prepare to
-download all data on it, download all data on it, and to reset prior to being
-disconnected. Therefore, any other functionality has to be based on software
-fakery which fools the hardware. Suppose, for example, that there are ten
-photos in the camera. Then what the camera will do is:
+This library appears to support the basic functionality of all the various
+cameras which are available for testing. It seems to perform reliably at the
+tasks of initializing the camera and providing a graceful exit, downloading
+the raw data, and also conversion of raw data into decompressed output files.
+Cameras which support or do not support thumbnails seem to be reliably
+detected, and the raw data appears to be reliably decompressed. If present,
+thumbnails can also be processed into a finished form. In short, things
+appear basically to work.
+
+HARDWARE CONSTRAINTS:
+
+These cameras use an extremely primitive command structure. The only thing
+that the camera really does know how to do is to prepare to download all data
+on it, then to download all data on it, and then to reset prior to being
+disconnected. Judging by what it does, the OEM software is almost certainly
+built on the assumption that the camera will be initialized, have its data
+dumped exactly once, and then disconnected. Everything else is done on the
+computer with the big blob of data which has been downloaded. Therefore,
+any other functionality has to be based on software fakery which fools the
+hardware into emulating said functionality. Suppose, for example, that there
+are ten photos in the camera. Then what the camera will do is:
-- report the number of photos (ten)
-- tell how much data needs to be downloaded in all (depends on how
much room was taken up by the raw data for all the photos)
-- provide a table with one line for each photo, giving its size, start
location, output height and width, and some kind of code for the
compression method used on it.
-In the next step, one must request all the image data to be downloaded, in
-increments of which there is a maximum size. This does not need to be done
-all at once, so it is possible to download some initial block of the data and
-operate on whatever photos are already obtained, and then download another block.
-However, ALL of the data has to be downloaded before the driver program exits.
-One consequence of this is that the only way a command such as
+In the next step, one must request all the image data for all the ten photos
+to be downloaded. This happens in increments of 64000 bytes, with only the last
+increment permitted to be "short." This does not need to be done all at once;
+it is possible to download some initial block of the data and operate on
+whatever photos are already obtained, keeping anything left over until the next
+block is downloaded. However, ALL of the data must downloaded before the driver
+ program exits. One consequence of this is that the only way commands such as
-gphoto2 --get-raw-data 3
+gphoto2 --get-raw-data 3 or gphoto2 -p 3
can work is to download photos number 1 and 2 and throw away the data before
-downloading the desired number 3 which is to be kept as a raw file,
-and then downloading any data in the camera which comes after photo number 3
-after that, as a standard part of the exit routine. Another consequence is
-that the sequence of downloading number 10, say, followed by number 1 is even
-more complicated. The actual steps required are:
+downloading the desired number 3 which is to be kept, then downloading any
+data in the camera which comes after photo number 3, as part of the exit
+routine. The sequence of downloading number 10, say, followed by number 1 is
+even more complicated. The actual steps required are:
-- initialize the camera
-- download enough data to get photo number 10, throwing away all data
which is not part of photo number 10 but precedes it
-- download the data required for photo number 10
- -- download the rest of the data
+ -- download the rest of the data, if any
-- send a reset sequence to the camera
-- close and reopen the camera's port
- -- run a "rewind" function consisting of a fake repetition of the
- initialization sequence, including downloading again the allocation table
+ -- repeat the initialization sequence
-- download enough data to process photo number 1
- -- download all the rest of the data and throw it away.
+ -- download all the rest of the data and throw it away.
-- send the reset sequence again, and, finally, disconnect
-Finally, if and when the decompression problem is resolved, then it ought to
-become possible to use other programs with this camera, such as a GUI frontend
-for libgphoto2. Any such program used with this camera must be willing to call
-and actually to use the camera_exit() function which is contained in this
-library, else, given the above constraints, it is obvious that the camera would
+In addition to the awkwardness caused by this kind of primitive behavior, it
+puts certain requirements on any program used to handle the camera. Most
+particularly, any program which uses libgphoto2 must be willing to call and
+actually to use the camera_exit() function which is contained in this library.
+Otherwise, given the above constraints, it is obvious that the camera would
not work properly with that frontend program.
+TO DO
+
+There are some parts of the camera command structure which are not completely
+known at this time. For example, the only way known to delete photos on these
+cameras is to use combinations of button pushes on the camera, or to remove
+the batteries (the cameras run on volatile SDRAM, like many other cheap
+cameras). It could be that some of the cameras might possibly support the
+command gphoto2 -D (delete all) to be implemented. It appears unlikely, but
+but the possibility is not completely investigated. Also, some kind of capture
+function could conceivably be made to work. Right now, this is also unknown.
+
+One known functionality of the camera is not completely supported, though. The
+cameras all support a "continuous shooting" mode, in which the camera shoots
+frames until it it is stopped by a button press or runs out of memory. The OEM
+driver software saves the result as an AVI file. Here, the individual frames
+are merely downloaded and saved as individual photos. The intention is to
+support this feature completely, in the future.
WARRANTY?
-Absolutely none. Remember, I did not sell you this software. I have written
-this driver for my own edification and in the sincere hope that it might help
-you to use of your camera. Please see also the warranty clauses
+Absolutely none. Remember, I did not sell you this software. I have written
+this driver for my own edification and in the sincere hope that it might help
+you to use of your camera. Please see also the warranty clauses
in the LGPL license.
diff --git a/camlibs/jl2005c/img_enhance.c b/camlibs/jl2005c/img_enhance.c
new file mode 100644
index 000000000..9caa98c94
--- /dev/null
+++ b/camlibs/jl2005c/img_enhance.c
@@ -0,0 +1,252 @@
+/*
+ * img_enhance.c
+ *
+ * Part of a processor program for raw data from JL2005B/C/D cameras.
+ * Based on previous work for several other cameras.
+ *
+ * Copyright (c) 2010 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * A previous version of the white_balance() function intended for use in
+ * libgphoto2/camlibs/aox is copyright (c) 2008 Amauri Magagna.
+ *
+ * This program 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 General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <gamma.h>
+#include <bayer.h>
+#include "img_enhance.h"
+
+#include <gphoto2/gphoto2.h>
+
+#define GP_MODULE "jl2005c"
+
+#ifndef CLIP
+#define CLIP(x) ((x)<0?0:((x)>255)?255:(x))
+#endif
+
+
+/* ===== White Balance / Color Enhance / Gamma adjust =====
+
+ Get histogram for each color plane
+ Expand to reach 0.5% of white dots in image
+
+ Get new histogram for each color plane
+ Expand to reach 0.5% of black dots in image
+
+ Get new histogram
+ Calculate and apply gamma correction
+
+ If not a dark image:
+ For each dot, increase the color separation
+
+ ========================================================== */
+
+int
+histogram (unsigned char *data, unsigned int size, int *htable_r,
+ int *htable_g, int *htable_b)
+{
+ int x;
+ /* Initializations */
+ for (x = 0; x < 0x100; x++) {
+ htable_r[x] = 0;
+ htable_g[x] = 0;
+ htable_b[x] = 0;
+ }
+ /* Building the histograms */
+ for (x = 0; x < (size * 3); x += 3)
+ {
+
+ htable_r[data[x + 0]]++; /* red histogram */
+ htable_g[data[x + 1]]++; /* green histogram */
+ htable_b[data[x + 2]]++; /* blue histogram */
+ }
+ return 0;
+}
+
+int
+white_balance (unsigned char *data, unsigned int size, float saturation)
+{
+ int x, r, g, b, max, d;
+ double r_factor, g_factor, b_factor, max_factor;
+ int htable_r[0x100], htable_g[0x100], htable_b[0x100];
+ unsigned char gtable[0x100];
+ double new_gamma, gamma = 1.0;
+
+ /* ------------------- GAMMA CORRECTION ------------------- */
+
+ histogram(data, size, htable_r, htable_g, htable_b);
+ x = 1;
+ for (r = 64; r < 192; r++)
+ {
+ x += htable_r[r];
+ x += htable_g[r];
+ x += htable_b[r];
+ }
+ new_gamma = sqrt((double) (x * 1.5) / (double) (size * 3));
+ printf("Provisional gamma correction = %1.2f\n", new_gamma);
+ /* Recalculate saturation factor for later use. */
+ saturation = saturation * new_gamma * new_gamma;
+ printf("saturation = %1.2f\n", saturation);
+ gamma = new_gamma;
+ if (new_gamma < .70)
+ gamma = 0.70;
+ if (new_gamma > 1.2)
+ gamma = 1.2;
+ printf("Gamma correction = %1.2f\n", gamma);
+ gp_gamma_fill_table(gtable, gamma);
+ gp_gamma_correct_single(gtable, data, size);
+ if (saturation < .5 ) /* If so, exit now. */
+ return 0;
+
+ /* ---------------- BRIGHT DOTS ------------------- */
+ max = size / 200;
+ histogram(data, size, htable_r, htable_g, htable_b);
+
+ for (r = 0xfe, x = 0; (r > 32) && (x < max); r--)
+ x += htable_r[r];
+ for (g = 0xfe, x = 0; (g > 32) && (x < max); g--)
+ x += htable_g[g];
+ for (b = 0xfe, x = 0; (b > 32) && (x < max); b--)
+ x += htable_b[b];
+ r_factor = (double) 0xfd / r;
+ g_factor = (double) 0xfd / g;
+ b_factor = (double) 0xfd / b;
+
+ max_factor = r_factor;
+ if (g_factor > max_factor) max_factor = g_factor;
+ if (b_factor > max_factor) max_factor = b_factor;
+ if (max_factor >= 4.0) {
+ /*
+ * We need a little bit of control, here. If max_factor is big
+ * then the photo was very dark, after all.
+ */
+ if (2.0 * b_factor < max_factor)
+ b_factor = max_factor / 2.;
+ if (2.0 * r_factor < max_factor)
+ r_factor = max_factor / 2.;
+ if (2.0 * g_factor < max_factor)
+ g_factor = max_factor/2.;
+ r_factor = (r_factor / max_factor) * 4.0;
+ g_factor = (g_factor / max_factor) * 4.0;
+ b_factor = (b_factor / max_factor) * 4.0;
+ }
+
+ if (max_factor > 1.5)
+ saturation = 0;
+ printf("White balance (bright): ");
+ printf("r=%1d, g=%1d, b=%1d, fr=%1.3f, fg=%1.3f, fb=%1.3f\n",
+ r, g, b, r_factor, g_factor, b_factor);
+ if (max_factor <= 1.4) {
+ for (x = 0; x < (size * 3); x += 3)
+ {
+ d = (data[x + 0] << 8) * r_factor + 8;
+ d >>= 8;
+ if (d > 0xff)
+ d = 0xff;
+ data[x + 0] = d;
+ d = (data[x + 1] << 8) * g_factor + 8;
+ d >>= 8;
+ if (d > 0xff)
+ d = 0xff;
+ data[x + 1] = d;
+ d = (data[x + 2] << 8) * b_factor + 8;
+ d >>= 8;
+ if (d > 0xff)
+ d = 0xff;
+ data[x + 2] = d;
+ }
+ }
+ /* ---------------- DARK DOTS ------------------- */
+ max = size / 200; /* 1/200 = 0.5% */
+ histogram(data, size, htable_r, htable_g, htable_b);
+
+ for (r = 0, x = 0; (r < 96) && (x < max); r++)
+ x += htable_r[r];
+ for (g = 0, x = 0; (g < 96) && (x < max); g++)
+ x += htable_g[g];
+ for (b = 0, x = 0; (b < 96) && (x < max); b++)
+ x += htable_b[b];
+
+ r_factor = (double) 0xfe / (0xff - r);
+ g_factor = (double) 0xfe / (0xff - g);
+ b_factor = (double) 0xfe / (0xff - b);
+
+ printf("White balance (dark): ");
+ printf("r=%1d, g=%1d, b=%1d, fr=%1.3f, fg=%1.3f, fb=%1.3f\n",
+ r, g, b, r_factor, g_factor, b_factor);
+
+ for (x = 0; x < (size * 3); x += 3)
+ {
+ d = (int) 0xff08 - (((0xff - data[x + 0]) << 8) * r_factor);
+ d >>= 8;
+ if (d < 0)
+ d = 0;
+ data[x + 0] = d;
+ d = (int) 0xff08 - (((0xff - data[x + 1]) << 8) * g_factor);
+ d >>= 8;
+ if (d < 0)
+ d = 0;
+ data[x + 1] = d;
+ d = (int) 0xff08 - (((0xff - data[x + 2]) << 8) * b_factor);
+ d >>= 8;
+ if (d < 0)
+ d = 0;
+ data[x + 2] = d;
+ }
+
+ /* ------------------ COLOR ENHANCE ------------------ */
+
+ if(saturation > 0.0) {
+ for (x = 0; x < (size * 3); x += 3)
+ {
+ r = data[x + 0]; g = data[x + 1]; b = data[x + 2];
+ d = (int) (r + g + b) / 3.;
+ if ( r > d )
+ r = r + (int) ((r - d)
+ * (0xff - r) / (0x100 - d)
+ * saturation);
+ else
+ r = r + (int) ((r - d)
+ * (0xff - d) / (0x100 - r)
+ * saturation);
+ if (g > d)
+ g = g + (int) ((g - d)
+ * (0xff - g) / (0x100 - d)
+ * saturation);
+ else
+ g = g + (int) ((g - d)
+ * (0xff - d) / (0x100 - g)
+ * saturation);
+ if (b > d)
+ b = b + (int) ((b - d)
+ * (0xff - b) / (0x100 - d)
+ * saturation);
+ else
+ b = b + (int) ((b - d)
+ * (0xff - d) / (0x100 - b)
+ * saturation);
+ data[x + 0] = CLIP(r);
+ data[x + 1] = CLIP(g);
+ data[x + 2] = CLIP(b);
+ }
+ }
+ return 0;
+}
diff --git a/camlibs/jl2005c/img_enhance.h b/camlibs/jl2005c/img_enhance.h
new file mode 100644
index 000000000..0f0a5938c
--- /dev/null
+++ b/camlibs/jl2005c/img_enhance.h
@@ -0,0 +1,35 @@
+/*
+ * img_enhance.h
+ *
+ * Header file for image processor for raw files from JL2005B/C/D
+ * cameras.
+ *
+ * Copyright (c) 2010 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __IMG_ENHANCE_H__
+#define __IMG_ENHANCE_H__
+
+
+int
+histogram(unsigned char *data, unsigned int size, int *htable_r,
+ int *htable_g, int *htable_b);
+int
+white_balance(unsigned char *data, unsigned int size, float saturation);
+
+#endif
diff --git a/camlibs/jl2005c/jl2005bcd_decompress.c b/camlibs/jl2005c/jl2005bcd_decompress.c
new file mode 100644
index 000000000..37444537c
--- /dev/null
+++ b/camlibs/jl2005c/jl2005bcd_decompress.c
@@ -0,0 +1,280 @@
+/* decompress.c
+ *
+ * Converts raw output from Jeilin JL2005B/C/D into PPM files.
+ *
+ * The jl2005bcd_raw_converter is
+ * Copyright (c) 2010 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * The decompression code used is
+ * Copyright (c) 2010 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program 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.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "jl2005bcd_decompress.h"
+#include "jpeg_memsrcdest.c"
+#include <bayer.h>
+#include "img_enhance.h"
+#include <math.h>
+
+#include <gphoto2/gphoto2.h>
+#include <gphoto2/gphoto2-port.h>
+
+#define GP_MODULE "jl2005c"
+
+
+#define JPEG_HEADER_SIZE 338
+#define JPEG_HEIGHT_OFFSET 94
+
+static int
+find_eoi (uint8_t *jpeg_data, int jpeg_data_idx, int jpeg_data_size)
+{
+ int i;
+
+ for (i = jpeg_data_idx; i < (jpeg_data_size - 1); i++)
+ if (jpeg_data[i] == 0xff && jpeg_data[i + 1] == 0xd9)
+ break;
+
+ if (i >= (jpeg_data_size - 1)) {
+ printf("AAI\n");
+ return -1;
+ }
+
+ return i + 2; /* + 2 -> Point to after EOI marker */
+}
+
+int
+jl2005bcd_decompress (unsigned char *output, unsigned char *input,
+ int inputsize, int get_thumbnail)
+{
+ int out_headerlen;
+ uint16_t *thumb = NULL;
+ unsigned char *header;
+ uint8_t jpeg_stripe[500000];
+ uint8_t out[5000000];
+ unsigned char *jpeg_data;
+ int q, width, height;
+ int thumbnail_width, thumbnail_height;
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_decompress_struct dinfo;
+ struct jpeg_error_mgr jcerr, jderr;
+ JOCTET *jpeg_header = NULL;
+ int outputsize = 0;
+ unsigned long jpeg_header_size = 0;
+ int i, x, y, x1, y1, jpeg_data_size, jpeg_data_idx, eoi, size, ret;
+
+
+ GP_DEBUG("Running jl2005bcd_decompress() function.\n");
+
+ header = input;
+ q = header[3] & 0x7f;
+ height = header[4] * 8;
+ width = header[5] * 8;
+ printf("quality is %d\n", q);
+ printf("size: %dx%d\n", width, height);
+ switch (header[9] & 0xf0) {
+ case 0xf0:
+ thumbnail_width = 128;
+ thumbnail_height = 120;
+ break;
+ case 0x60:
+ thumbnail_width = 96;
+ thumbnail_height = 64;
+ break;
+ default:
+ thumbnail_width = 0;
+ thumbnail_height = 0;
+ }
+ if (header[1] & 3)
+ thumbnail_width = 0;
+ if (get_thumbnail) {
+ if (!thumbnail_width) {
+ GP_DEBUG("No thumbnail is present!\n");
+ return GP_ERROR_NOT_SUPPORTED;
+ } else {
+ thumb = input + 16;
+ for (i = 0; i < thumbnail_width * thumbnail_height;
+ i++) {
+ thumb[i] = ntohs(thumb[i]);
+ out[i * 3 + 0] = (thumb[i] & 0xf800) >> 8;
+ out[i * 3 + 1] = (thumb[i] & 0x07e0) >> 3;
+ out[i * 3 + 2] = (thumb[i] & 0x001f) << 3;
+ }
+
+ out_headerlen = snprintf((char *)output, 256,
+ "P6\n"
+ "# CREATOR: gphoto2, JL2005BCD library\n"
+ "%d %d\n"
+ "255\n",
+ thumbnail_width,
+ thumbnail_height);
+ white_balance (out, thumbnail_width * thumbnail_height,
+ 1.6);
+ memcpy(output + out_headerlen, out,
+ thumbnail_width * thumbnail_height * 3);
+ outputsize = thumbnail_width * thumbnail_height * 3 +
+ out_headerlen;
+ return outputsize;
+ }
+ }
+ /*
+ * And the fun begins, first of all create a dummy jpeg, which we use
+ * to get the headers from to feed to libjpeg when decompressing the
+ * stripes. This way we can use libjpeg's quant table handling
+ * (and built in default huffman tables).
+ */
+ cinfo.err = jpeg_std_error (&jcerr);
+ jpeg_create_compress (&cinfo);
+ jpeg_mem_dest (&cinfo, &jpeg_header, &jpeg_header_size);
+ cinfo.image_width = 16;
+ cinfo.image_height = 16;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ jpeg_set_defaults (&cinfo);
+ /* Make comp[0] (which will be green) 1x2 subsampled */
+ cinfo.comp_info[0].h_samp_factor = 1;
+ cinfo.comp_info[0].v_samp_factor = 2;
+ /* Make comp[1] and [2] use huffman table and quanttable 0, as all
+ * components use luminance settings with the jl2005b/c/d */
+ cinfo.comp_info[1].quant_tbl_no = 0;
+ cinfo.comp_info[1].dc_tbl_no = 0;
+ cinfo.comp_info[1].ac_tbl_no = 0;
+ cinfo.comp_info[2].quant_tbl_no = 0;
+ cinfo.comp_info[2].dc_tbl_no = 0;
+ cinfo.comp_info[2].ac_tbl_no = 0;
+ /* Apply the quality setting from the header */
+ if (q <= 0)
+ i = 5000;
+ else if (q <= 50)
+ i = 5000 / q;
+ else if (q <= 100)
+ i = 2 * (100 - q);
+ else
+ i = 0;
+ jpeg_set_linear_quality(&cinfo, i, TRUE);
+
+ jpeg_start_compress (&cinfo, TRUE);
+ while( cinfo.next_scanline < cinfo.image_height ) {
+ JOCTET row[16 * 3];
+ JSAMPROW row_pointer[1] = { row };
+ jpeg_write_scanlines (&cinfo, row_pointer, 1);
+ }
+ jpeg_finish_compress (&cinfo);
+ jpeg_destroy_compress (&cinfo);
+
+ JSAMPLE green[8 * 16];
+ JSAMPLE red[8 * 8];
+ JSAMPLE blue[8 * 8];
+ JSAMPROW green_row_pointer[16];
+ JSAMPROW red_row_pointer[8];
+ JSAMPROW blue_row_pointer[8];
+
+ for (i = 0; i < 16; i++)
+ green_row_pointer[i] = green + i * 8;
+
+ for (i = 0; i < 8; i++) {
+ red_row_pointer[i] = red + i * 8;
+ blue_row_pointer[i] = blue + i * 8;
+ }
+
+ JSAMPARRAY samp_image[3] = { green_row_pointer,
+ red_row_pointer,
+ blue_row_pointer };
+
+ memcpy(jpeg_stripe, jpeg_header, JPEG_HEADER_SIZE);
+ jpeg_stripe[JPEG_HEIGHT_OFFSET ] = height >> 8;
+ jpeg_stripe[JPEG_HEIGHT_OFFSET + 1] = height;
+ jpeg_stripe[JPEG_HEIGHT_OFFSET + 2] = 0;
+ jpeg_stripe[JPEG_HEIGHT_OFFSET + 3] = 8;
+ free (jpeg_header);
+ jpeg_data = input + 16 + 2 * thumbnail_width * thumbnail_height;
+ jpeg_data_size = inputsize - 16
+ - 2 * thumbnail_width * thumbnail_height;
+
+ jpeg_data_idx = 0;
+
+ memset(out, 0, width * height * 3);
+
+ dinfo.err = jpeg_std_error (&jderr);
+ jpeg_create_decompress (&dinfo);
+ for (x = 0; x < width; x += 16) {
+ eoi = find_eoi(jpeg_data, jpeg_data_idx, jpeg_data_size);
+ if (eoi < 0)
+ return eoi;
+
+ size = eoi - jpeg_data_idx;
+ if ((JPEG_HEADER_SIZE + size) > sizeof(jpeg_stripe)) {
+ printf("AAAIIIIII\n");
+ return 1;
+ }
+ memcpy (jpeg_stripe + JPEG_HEADER_SIZE,
+ jpeg_data + jpeg_data_idx, size);
+
+ jpeg_mem_src (&dinfo, jpeg_stripe, JPEG_HEADER_SIZE + size);
+ jpeg_read_header (&dinfo, TRUE);
+ dinfo.raw_data_out = TRUE;
+#if JPEG_LIB_VERSION >= 70
+ dinfo.do_fancy_upsampling = FALSE;
+#endif
+ jpeg_start_decompress (&dinfo);
+ for (y = 0; y < height; y += 16) {
+ jpeg_read_raw_data (&dinfo, samp_image, 16);
+ for (y1 = 0; y1 < 16; y1 += 2) {
+ for (x1 = 0; x1 < 16; x1 += 2) {
+ out[((y + y1 + 0) * width
+ + x + x1 + 0) * 3]
+ = red[y1 * 4 + x1 / 2];
+ out[((y + y1 + 0) * width
+ + x + x1 + 1) * 3 + 1]
+ = green[y1 * 8 + x1 / 2];
+ out[((y + y1 + 1) * width
+ + x + x1 + 0) * 3 + 1]
+ = green[y1 * 8 + 8 + x1 / 2];
+ out[((y + y1 + 1) * width
+ + x + x1 + 1) * 3 + 2]
+ = blue[y1 * 4 + x1 / 2];
+ }
+ }
+ }
+ jpeg_finish_decompress (&dinfo);
+
+ /* Set jpeg_data_idx for the next stripe */
+ jpeg_data_idx = (jpeg_data_idx + size + 0x0f) & ~0x0f;
+ }
+ jpeg_destroy_decompress(&dinfo);
+
+ ret = gp_ahd_interpolate(out, width, height, BAYER_TILE_BGGR);
+ if (ret < 0) {
+ printf("HEUH?\n");
+ return ret;
+ }
+ white_balance (out, width*height, 1.6);
+
+ out_headerlen = snprintf((char *)output, 256,
+ "P6\n"
+ "# CREATOR: gphoto2, JL2005BCD library\n"
+ "%d %d\n255\n",
+ width,
+ height);
+ GP_DEBUG("out_headerlen = %d\n", out_headerlen);
+ memcpy(output + out_headerlen, out, width * height * 3);
+ outputsize = out_headerlen + width * height * 3;
+ return outputsize;
+}
diff --git a/camlibs/jl2005c/jl2005bcd_decompress.h b/camlibs/jl2005c/jl2005bcd_decompress.h
new file mode 100644
index 000000000..e0c4ac777
--- /dev/null
+++ b/camlibs/jl2005c/jl2005bcd_decompress.h
@@ -0,0 +1,30 @@
+/* jl2005bcd_decompress.h
+ *
+ * Copyright (C) 2006-2010 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __jl2005bcd_decompress_H__
+#define __jl2005bcd_decompress_H__
+
+
+int
+jl2005bcd_decompress(unsigned char *output, unsigned char *input,
+ int inputsize, int get_thumbnail);
+
+#endif
+
diff --git a/camlibs/jl2005c/jl2005c.c b/camlibs/jl2005c/jl2005c.c
index b620a10ce..cb908ea26 100644
--- a/camlibs/jl2005c/jl2005c.c
+++ b/camlibs/jl2005c/jl2005c.c
@@ -1,16 +1,16 @@
/* jl2005c.c
*
- * Copyright (C) 2006 Theodore Kilgore <kilgota@auburn.edu>
+ * Copyright (C) 2006-2010 Theodore Kilgore <kilgota@auburn.edu>
*
* 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
+ * 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.
+ * 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
@@ -32,307 +32,226 @@
#include "jl2005c.h"
-#define GP_MODULE "jl2005c"
+#define GP_MODULE "jl2005c"
-int
-jl2005c_init (Camera *camera, GPPort *port, CameraPrivateLibrary *priv)
+int
+jl2005c_init (Camera *camera, GPPort *port, CameraPrivateLibrary *priv)
{
- unsigned char command[2];
char response;
- char model_string[4];
- unsigned char info[0xe000];
- int info_block_size = 0;
- memset(info,0, sizeof(info));
- memset(command,0,sizeof(command));
+ int model_string = 0;
+ /* Needs to be big enough to hold (0xfff + 3) * 0x10 */
+ unsigned char info[0x10020];
+ const char camera_id[] = {0x4a, 0x4c, 0x32, 0x30, 0x30, 0x35};
+ int alloc_table_size;
+ int attempts = 0;
+restart:
+ alloc_table_size = 0;
+ memset(info, 0, sizeof(info));
GP_DEBUG("Running jl2005c_init\n");
- set_usb_in_endpoint (camera, 0x84);
- gp_port_write (port, "\x08\x00", 2);
- usleep (10000);
- gp_port_write (port, "\x95\x60", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
- model_string[0]=response;
- usleep (10000);
- gp_port_write (port, "\x95\x61", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
- model_string[1]=response;
- usleep (10000);
- gp_port_write (port, "\x95\x62", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
- model_string[2]=response;
- usleep (10000);
- gp_port_write (port,"\x95\x63" , 2);
- usleep (10000);
-gp_port_read (port, &response, 1);
- model_string[3]=response;
- GP_DEBUG("Model string is %02x%02x%02x%02x\n",model_string[0], model_string[1],
- model_string[2], model_string[3]);
- usleep (10000);
- gp_port_write (port, "\x95\x64", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
-
- usleep (10000);
- gp_port_write (port, "\x95\x65", 2);
- usleep (10000);
- gp_port_read (port, &response, 1); /* Number of pix returned here */
- priv->nb_entries = (unsigned)response;
- GP_DEBUG("%d entries in the camera\n", response);
- GP_DEBUG("%d entries in the camera\n", priv->nb_entries);
- info_block_size = ((unsigned)response * 0x10) + 2;
- if (info_block_size%0x200)
- info_block_size += 0x200 - (info_block_size%0x200);
- usleep (10000);
+ if (priv->init_done) {
+ gp_port_close(port);
+ usleep (100000);
+ gp_port_open(port);
+ }
- gp_port_write (port, "\x95\x66", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
- usleep (10000);
- gp_port_write (port, "\x95\x67", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
+ set_usb_in_endpoint (camera, 0x84);
+ gp_port_write (port, "\x08\x00", 2);
usleep (10000);
-
- gp_port_write (port, "\x95\x68", 2);
+ gp_port_write (port, "\x95\x60", 2);
usleep (10000);
gp_port_read (port, &response, 1);
+ model_string = response;
usleep (10000);
-
- gp_port_write (port, "\x95\x69", 2);
+ gp_port_write (port, "\x95\x61", 2);
usleep (10000);
gp_port_read (port, &response, 1);
+ model_string += (response & 0xff) << 8;
usleep (10000);
-
- gp_port_write (port, "\x95\x6a", 2);
+ gp_port_write (port, "\x95\x62", 2);
usleep (10000);
gp_port_read (port, &response, 1);
+ model_string += (response & 0xff) << 16;
usleep (10000);
-
- gp_port_write (port, "\x95\x6b", 2);
+ gp_port_write (port,"\x95\x63" , 2);
usleep (10000);
gp_port_read (port, &response, 1);
+ model_string += (response & 0xff) << 24;
+ GP_DEBUG("Model string is %08x\n", model_string);
usleep (10000);
-
- gp_port_write (port, "\x95\x6c", 2);
+ gp_port_write (port, "\x95\x64", 2);
usleep (10000);
gp_port_read (port, &response, 1);
- priv->data_to_read = (response &0xff)*0x100;
-
- gp_port_write (port, "\x95\x6d", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
- usleep (10000);
-
- priv->data_to_read += (response&0xff);
- priv->data_to_read *= 0x200;
- priv->total_data_in_camera = priv->data_to_read;
- GP_DEBUG ("data_to_read = 0x%lx = %lu\n", priv->data_to_read,
- priv->data_to_read);
- GP_DEBUG ("total_data_in_camera = 0x%lx = %lu\n", priv->data_to_read,
- priv->data_to_read);
-
- gp_port_write (port, "\x95\x6e", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
-
- usleep (10000);
- gp_port_write (port, "\x95\x6f", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
-
- usleep (10000);
- gp_port_write (port, "\x0a\x00", 2);
-
- usleep (10000);
- /* Switch the inep over to 0x82. It stays there ever after. */
- set_usb_in_endpoint (camera, 0x82);
- usleep (10000);
- gp_port_read(port, (char *)info, info_block_size);
- usleep (10000);
- gp_port_write (port, "\x0b\x00",2);
- usleep (10000);
- memmove(priv->info, info, info_block_size);
- priv->model=info[6];
-
- GP_DEBUG("Leaving jl2005c_init\n");
- return GP_OK;
-}
-
-
-int
-jl2005c_rewind (Camera *camera, GPPort *port)
-{
-// gp_port_write (port, "\x0b\x00",2);
- unsigned char command[2];
- char response;
- unsigned char info[0xe000];
- int info_block_size = 0;
- int junk_to_read = 0;
- memset(info,0, sizeof(info));
- memset(command,0,sizeof(command));
- GP_DEBUG("Running jl2005c_rewind\n");
- gp_port_close(port);
- usleep (100000);
- gp_port_open(port);
-
- set_usb_in_endpoint (camera, 0x84);
- gp_port_write (port, "\x08\x00", 2);
-
usleep (10000);
- gp_port_write (port, "\x95\x60", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
- usleep (10000);
- gp_port_write (port, "\x95\x61", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
- usleep (10000);
- gp_port_write (port, "\x95\x62", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
- usleep (10000);
- gp_port_write (port,"\x95\x63" , 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
- usleep (10000);
- gp_port_write (port, "\x95\x64", 2);
- usleep (10000);
- gp_port_read (port, &response, 1);
-
- usleep (10000);
gp_port_write (port, "\x95\x65", 2);
usleep (10000);
gp_port_read (port, &response, 1);
- info_block_size = ((unsigned)response * 0x10) + 2;
- if (info_block_size%0x200)
- info_block_size += 0x200 - (info_block_size%0x200);
+ /* Number of pix returned here, but not reliably reported */
+ priv->nb_entries = response & 0xff;
+ GP_DEBUG("%d frames in the camera (unreliable!)\n", priv->nb_entries);
usleep (10000);
gp_port_write (port, "\x95\x66", 2);
usleep (10000);
- gp_port_read (port, &response, 1);
+ gp_port_read (port, &response, 1);
usleep (10000);
- gp_port_write (port, "\x95\x67", 2);
+ gp_port_write (port, "\x95\x67", 2);
usleep (10000);
gp_port_read (port, &response, 1);
usleep (10000);
- gp_port_write (port, "\x95\x68", 2);
+ gp_port_write (port, "\x95\x68", 2);
usleep (10000);
gp_port_read (port, &response, 1);
usleep (10000);
- gp_port_write (port, "\x95\x69", 2);
+ gp_port_write (port, "\x95\x69", 2);
usleep (10000);
gp_port_read (port, &response, 1);
usleep (10000);
- gp_port_write (port, "\x95\x6a", 2);
+ gp_port_write (port, "\x95\x6a", 2);
usleep (10000);
gp_port_read (port, &response, 1);
usleep (10000);
- gp_port_write (port, "\x95\x6b", 2);
+ gp_port_write (port, "\x95\x6b", 2);
usleep (10000);
gp_port_read (port, &response, 1);
usleep (10000);
- gp_port_write (port, "\x95\x6c", 2);
+ gp_port_write (port, "\x95\x6c", 2);
usleep (10000);
gp_port_read (port, &response, 1);
- junk_to_read = (response &0xff)*0x100;
+ priv->data_to_read = (response & 0xff) * 0x100;
- gp_port_write (port, "\x95\x6d", 2);
+ gp_port_write (port, "\x95\x6d", 2);
usleep (10000);
gp_port_read (port, &response, 1);
usleep (10000);
- junk_to_read += (response&0xff);
- junk_to_read *= 0x200;
- gp_port_write (port, "\x95\x6e", 2);
+ priv->data_to_read += (response&0xff);
+ priv->total_data_in_camera = priv->data_to_read;
+ GP_DEBUG ("blocks_to_read = 0x%lx = %lu\n", priv->data_to_read,
+ priv->data_to_read);
+
+ gp_port_write (port, "\x95\x6e", 2);
usleep (10000);
gp_port_read (port, &response, 1);
+ alloc_table_size = (response & 0xff) * 0x200;
+ GP_DEBUG("alloc_table_size = 0x%02x * 0x200 = 0x%x\n",
+ response & 0xff, (response & 0xff) * 0x200);
usleep (10000);
- gp_port_write (port, "\x95\x6f", 2);
+ gp_port_write (port, "\x95\x6f", 2);
usleep (10000);
gp_port_read (port, &response, 1);
usleep (10000);
gp_port_write (port, "\x0a\x00", 2);
-
usleep (10000);
+ /* Switch the inep over to 0x82. It stays there ever after. */
+ set_usb_in_endpoint (camera, 0x82);
+ usleep (10000);
+ /* Read the first block of the allocation table. */
+ gp_port_read(port, (char *)info, 0x200);
+ if (strncmp(camera_id, (char*)info, 6)) {
+ GP_DEBUG("Error downloading alloc table\n");
+ GP_DEBUG("Init attempted %d times\n", attempts + 1);
+ attempts++;
+ if (attempts == 3) {
+ GP_DEBUG("Third try. Giving up\n");
+ return GP_ERROR;
+ }
+ goto restart;
+ }
- /* Switch the inep over to 0x82. It stays there ever after. */
- set_usb_in_endpoint (camera, 0x82);
- usleep (10000);
- gp_port_read(port, (char *)info, info_block_size);
-
+ /* Now check the number of photos. That is found in byte 13 of line 0
+ * of the allocation table.
+ */
usleep (10000);
+ priv->nb_entries = (info[12] & 0xff) * 0x100 | (info[13] & 0xff);
+ GP_DEBUG("Number of entries is recalculated as %d\n",
+ priv->nb_entries);
+
+ /* Just in case there was a problem, we now recalculate the total
+ * alloc_table_size. */
+ alloc_table_size = priv->nb_entries * 0x10 + 0x30;
+ if (alloc_table_size%0x200)
+ alloc_table_size += 0x200 - (alloc_table_size%0x200);
+ /* However, we have already just now downloaded 0x200 bytes, so
+ * when downloading the rest of the table we correct for that and
+ * just download whatever remains of the information block.
+ */
+ if (alloc_table_size > 0x200)
+ gp_port_read(port, (char *)info + 0x200,
+ alloc_table_size - 0x200);
+ memmove(priv->info, info, alloc_table_size);
+ priv->model=info[6];
+ switch (priv->model) {
+ case 0x43:
+ case 0x44:
+ priv->blocksize = 0x200;
+ break;
+ case 0x42:
+ priv->blocksize = 0x80;
+ break;
+ default:
+ GP_DEBUG("Unknown model, unknown blocksize\n");
+ return GP_ERROR_NOT_SUPPORTED;
+ }
+ GP_DEBUG("camera's blocksize = 0x%x = %d\n", priv->blocksize,
+ priv->blocksize);
+ /* Now a more responsible calculation of the amount of data in the
+ * camera, based upon the allocation table. */
+ priv->data_to_read = info[10] * 0x100 | info[11];
+ priv->data_to_read -= info[8] * 0x100 | info[9];
+ priv->data_to_read *= priv->blocksize;
+ priv->total_data_in_camera = priv->data_to_read;
+ GP_DEBUG ("data_to_read = 0x%lx = %lu\n", priv->data_to_read,
+ priv->data_to_read);
+ GP_DEBUG ("total_data_in_camera = 0x%lx = %lu\n", priv->data_to_read,
+ priv->data_to_read);
+ priv->can_do_capture = 0;
+ if (info[7] & 0x04)
+ priv->can_do_capture = 1;
gp_port_write (port, "\x0b\x00",2);
usleep (10000);
+ priv->bytes_read_from_camera = 0;
+ priv->bytes_put_away = 0;
- GP_DEBUG("Completing jl2005c_rewind\n");
-
- return GP_OK;
+ priv->init_done = 1;
+ GP_DEBUG("Leaving jl2005c_init\n");
+ return GP_OK;
}
-
int
jl2005c_get_pic_data_size (CameraPrivateLibrary *priv, Info *info, int n)
{
int size;
- unsigned char model=priv->model;
- GP_DEBUG("info[48+16*n+7] = %02X\n", info[48+16*n+7]);
- size = info[0x30+0x10*n+6]*0x100+info[0x30+0x10*n+7];
- switch (model) {
- case 0x43:
- case 0x44:
- size *= 0x200;
- break;
- case 0x42:
- size *= 0x80;
- break;
- default:
- GP_DEBUG("Unknown model, unknown size\n");
- return GP_ERROR_NOT_SUPPORTED;
- }
+ GP_DEBUG("info[48+16*n+7] = %02X\n", info[48 + 16 * n + 7]);
+ size = info[0x30 + 0x10 * n + 6] * 0x100 +info[0x30 + 0x10 * n + 7];
+ size *= priv->blocksize;
GP_DEBUG("size = 0x%x = %d\n", size, size);
return (size);
}
unsigned long
-jl2005c_get_start_of_photo(CameraPrivateLibrary *priv, Info *info,
+jl2005c_get_start_of_photo(CameraPrivateLibrary *priv, Info *info,
unsigned int n)
{
unsigned long start;
- unsigned char model = priv->model;
- start = info[0x30+0x10*n+0x0c]*0x100+
- info[0x30+0x10*n+0x0d];
- start -= info[0x30+0x0c]*0x100+
- info[0x30+0x0d];
- switch (model) {
- case 0x43:
- case 0x44:
- start *= 0x200;
- break;
- case 0x42:
- start *= 0x80;
- break;
- default:
- GP_DEBUG("Unknown model\n");
- return GP_ERROR_NOT_SUPPORTED;
- }
+ start = info[0x30 + 0x10 * n + 0x0c] * 0x100 |
+ info[0x30 + 0x10 * n + 0x0d];
+ start -= info[0x30 + 0x0c] * 0x100 | info[0x30 + 0x0d];
+ start *= priv->blocksize;
return start;
}
-int
-set_usb_in_endpoint (Camera *camera, int inep)
+int
+set_usb_in_endpoint (Camera *camera, int inep)
{
GPPortSettings settings;
gp_port_get_settings ( camera ->port, &settings);
@@ -340,51 +259,46 @@ set_usb_in_endpoint (Camera *camera, int inep)
settings.usb.inep = inep;
GP_DEBUG("inep reset to %02X\n", inep);
return gp_port_set_settings ( camera->port, settings);
-}
-
-
-int
-jl2005c_get_picture_data (GPPort *port,
- char *data, int size)
+}
+int
+jl2005c_get_picture_data (GPPort *port, char *data, int size)
{
- /* inep has been reset to 0x82 already and does not get set back */
- /* We have to send 0b 00, presumably to access the data register,
- * when starting to download the first photo only
+ /* inep has been reset to 0x82 already and does not get set back */
+ /* We have to send 0b 00, presumably to access the data register,
+ * when starting to download the first photo only. But this is already
+ * done. So here we just download the data, between sleeps.
*/
usleep (10000);
/*Data transfer begins*/
- gp_port_read (port, data, size);
+ gp_port_read (port, data, size);
usleep (10000);
return GP_OK;
-}
+}
int
jl2005c_reset (Camera *camera, GPPort *port)
{
- int blocksize = 0xfa00;
+ int downloadsize = 0xfa00;
/* These cameras want all data to be dumped. If that is not yet done,
* then do it now, before exiting! */
- while (camera->pl->bytes_read_from_camera <
+ while (camera->pl->bytes_read_from_camera <
camera->pl->total_data_in_camera ) {
if (! camera->pl->data_cache )
camera->pl->data_cache = malloc (0xfa00);
- blocksize=0xfa00;
+ downloadsize=0xfa00;
if (camera->pl->bytes_read_from_camera +0xfa00 >=
- camera->pl->total_data_in_camera )
- blocksize = camera->pl->total_data_in_camera -
+ camera->pl->total_data_in_camera )
+ downloadsize = camera->pl->total_data_in_camera -
camera->pl->bytes_read_from_camera;
- if(blocksize)
+ if(downloadsize)
jl2005c_get_picture_data (
- camera->port,
- (char *) camera->pl->data_cache,
- blocksize);
+ camera->port,
+ (char *) camera->pl->data_cache,
+ downloadsize);
camera->pl->bytes_read_from_camera
- += blocksize;
-
+ += downloadsize;
}
-
-
gp_port_write(port, "\x07\x00", 2);
return GP_OK;
}
diff --git a/camlibs/jl2005c/jl2005c.h b/camlibs/jl2005c/jl2005c.h
index 75bc4f499..fe945433d 100644
--- a/camlibs/jl2005c/jl2005c.h
+++ b/camlibs/jl2005c/jl2005c.h
@@ -1,16 +1,16 @@
/* jl2005c.h
*
- * Copyright (C) 2006 Theodore Kilgore <kilgota@auburn.edu>
+ * Copyright (C) 2006-2010 Theodore Kilgore <kilgota@auburn.edu>
*
* 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
+ * 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.
+ * 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
@@ -28,32 +28,28 @@ typedef unsigned char Info;
struct _CameraPrivateLibrary {
unsigned char model;
-// unsigned char *catalog;
+ unsigned char init_done;
+ int can_do_capture;
+ int blocksize;
int nb_entries;
- int last_fetched_entry;
unsigned long total_data_in_camera;
unsigned long data_to_read;
unsigned char *data_cache;
unsigned long bytes_read_from_camera;
- int data_used_from_block;
unsigned long bytes_put_away;
Info info[0xe000];
};
-int jl2005c_init (Camera *camera, GPPort *port,
- CameraPrivateLibrary *priv);
-int jl2005c_rewind (Camera *camera, GPPort *port);
-int jl2005c_reset (Camera *camera, GPPort *port);
-int jl2005c_get_num_pics (Info *info);
-int jl2005c_get_resolution (Info *info, int n);
+int jl2005c_init (Camera *camera, GPPort *port, CameraPrivateLibrary *priv);
+int jl2005c_reset (Camera *camera, GPPort *port);
+int jl2005c_get_num_pics (Info *info);
-int jl2005c_get_compression (Info *info, int n);
-int jl2005c_get_width (Info *info, int n);
int jl2005c_get_pic_data_size (CameraPrivateLibrary *priv, Info *info, int n);
-unsigned long jl2005c_get_start_of_photo(CameraPrivateLibrary *priv,
+unsigned long jl2005c_get_start_of_photo (CameraPrivateLibrary *priv,
Info *info, unsigned int n);
-int set_usb_in_endpoint (Camera *camera, int inep);
-int jl2005c_get_picture_data (GPPort *port, char *data, int size);
+int set_usb_in_endpoint (Camera *camera, int inep);
+int jl2005c_get_picture_data (GPPort *port, char *data, int size);
+
#endif
diff --git a/camlibs/jl2005c/jpeg_memsrcdest.c b/camlibs/jl2005c/jpeg_memsrcdest.c
new file mode 100644
index 000000000..efe650e9c
--- /dev/null
+++ b/camlibs/jl2005c/jpeg_memsrcdest.c
@@ -0,0 +1,309 @@
+/*
+* memsrc.c
+*
+* Copyright (C) 1994-1996, Thomas G. Lane.
+* This file is part of the Independent JPEG Group's software.
+* For conditions of distribution and use, see the accompanying README file.
+*
+* This file contains decompression data source routines for the case of
+* reading JPEG data from a memory buffer that is preloaded with the entire
+* JPEG file. This would not seem especially useful at first sight, but
+* a number of people have asked for it.
+* This is really just a stripped-down version of jdatasrc.c. Comparison
+* of this code with jdatasrc.c may be helpful in seeing how to make
+* custom source managers for other purposes.
+*/
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include <stdlib.h>
+#include <stdio.h>
+#include <jpeglib.h>
+#include <jerror.h>
+#include "jpeg_memsrcdest.h"
+
+/* libjpeg8 and later come with their own (API compatible) memory source
+ and dest */
+#if JPEG_LIB_VERSION < 80
+
+/* Expanded data source object for memory input */
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ JOCTET eoi_buffer[2]; /* a place to put a dummy EOI */
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+
+/*
+* Initialize source --- called by jpeg_read_header
+* before any data is actually read.
+*/
+
+METHODDEF(void)
+init_source (j_decompress_ptr cinfo)
+{
+ /* No work, since jpeg_mem_src set up the buffer pointer and count.
+ * Indeed, if we want to read multiple JPEG images from one buffer,
+ * this *must* not do anything to the pointer.
+ */
+}
+
+
+/*
+* Fill the input buffer --- called whenever buffer is emptied.
+*
+* In this application, this routine should never be called; if it is called,
+* the decompressor has overrun the end of the input buffer, implying we
+* supplied an incomplete or corrupt JPEG datastream. A simple error exit
+* might be the most appropriate response.
+*
+* But what we choose to do in this code is to supply dummy EOI markers
+* in order to force the decompressor to finish processing and supply
+* some sort of output image, no matter how corrupted.
+*/
+
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+
+ /* Create a fake EOI marker */
+ src->eoi_buffer[0] = (JOCTET) 0xFF;
+ src->eoi_buffer[1] = (JOCTET) JPEG_EOI;
+ src->pub.next_input_byte = src->eoi_buffer;
+ src->pub.bytes_in_buffer = 2;
+
+ return TRUE;
+}
+
+
+/*
+* Skip data --- used to skip over a potentially large amount of
+* uninteresting data (such as an APPn marker).
+*
+* If we overrun the end of the buffer, we let fill_input_buffer deal with
+* it. An extremely large skip could cause some time-wasting here, but
+* it really isn't supposed to happen ... and the decompressor will never
+* skip more than 64K anyway.
+*/
+
+METHODDEF(void)
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ (void) fill_input_buffer(cinfo);
+ /* note we assume that fill_input_buffer will never
+ * return FALSE, so suspension need not be handled.
+ */
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+
+/*
+* An additional method that can be provided by data source modules is the
+* resync_to_restart method for error recovery in the presence of RST markers.
+* For the moment, this source module just uses the default resync method
+* provided by the JPEG library. That method assumes that no backtracking
+* is possible.
+*/
+
+
+/*
+* Terminate source --- called by jpeg_finish_decompress
+* after all data has been read. Often a no-op.
+*
+* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+* application must deal with any cleanup that should happen even
+* for error exit.
+*/
+
+METHODDEF(void)
+term_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+* Prepare for input from a memory buffer.
+*/
+
+GLOBAL(void)
+jpeg_mem_src (j_decompress_ptr cinfo, unsigned char * buffer,
+ unsigned long bufsize)
+{
+ my_src_ptr src;
+
+ /* The source object is made permanent so that a series of JPEG images
+ * can be read from a single buffer by calling jpeg_mem_src
+ * only before the first one.
+ * This makes it unsafe to use this manager and a different source
+ * manager serially with the same JPEG object. Caveat programmer.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
+ JPOOL_PERMANENT,
+ sizeof(my_source_mgr));
+ }
+
+ src = (my_src_ptr) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ /* use default method */
+ src->pub.resync_to_restart = jpeg_resync_to_restart;
+ src->pub.term_source = term_source;
+
+ src->pub.next_input_byte = buffer;
+ src->pub.bytes_in_buffer = bufsize;
+}
+
+
+
+/* Memory destination source modelled after Thomas G. Lane's memory source
+ * support and jdatadst.c
+ *
+ * Copyright (C) 2010, Hans de Goede
+ *
+ * This code may be used under the same conditions as Thomas G. Lane's memory
+ * source (see the copyright header at the top of this file).
+ */
+
+typedef struct {
+ struct jpeg_destination_mgr pub; /* public fields */
+
+ JOCTET **buffer; /* start of buffer */
+ unsigned long buf_size, *outsize;
+} my_destination_mgr;
+
+typedef my_destination_mgr * my_dest_ptr;
+
+#define OUTPUT_BUF_SIZE 32768 /* choose an efficiently fwrite'able size */
+
+
+/*
+ * Initialize destination --- called by jpeg_start_compress
+ * before any data is actually written.
+ */
+
+METHODDEF(void)
+init_destination (j_compress_ptr cinfo)
+{
+ /* No work, since jpeg_mem_dest set up the buffer pointer and count.
+ * Indeed, if we want to write multiple JPEG images to one buffer,
+ * this *must* not do anything to the pointer.
+ */
+}
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * In typical applications, this should write the entire output buffer
+ * (ignoring the current state of next_output_byte & free_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been dumped.
+ *
+ * In applications that need to be able to suspend compression due to output
+ * overrun, a FALSE return indicates that the buffer cannot be emptied now.
+ * In this situation, the compressor will return to its caller (possibly with
+ * an indication that it has not accepted all the supplied scanlines). The
+ * application should resume compression after it has made more room in the
+ * output buffer. Note that there are substantial restrictions on the use of
+ * suspension --- see the documentation.
+ *
+ * When suspending, the compressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_output_byte & free_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point will be regenerated after resumption, so do not
+ * write it out when emptying the buffer externally.
+ */
+
+METHODDEF(boolean)
+empty_output_buffer (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ *dest->buffer = realloc (*dest->buffer,
+ dest->buf_size + OUTPUT_BUF_SIZE);
+ if (!*dest->buffer)
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
+
+ dest->pub.next_output_byte = *dest->buffer + dest->buf_size;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+ dest->buf_size += OUTPUT_BUF_SIZE;
+
+ return TRUE;
+}
+
+/*
+ * Terminate destination --- called by jpeg_finish_compress
+ * after all data has been written. Usually needs to flush buffer.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ *dest->outsize = dest->buf_size - dest->pub.free_in_buffer;
+}
+
+GLOBAL(void)
+jpeg_mem_dest (j_compress_ptr cinfo, unsigned char ** outbuffer,
+ unsigned long * outsize)
+{
+ my_dest_ptr dest;
+
+ /* The destination object is made permanent so that multiple JPEG
+ * images can be written to the same file without re-executing
+ * jpeg_stdio_dest.
+ * This makes it dangerous to use this manager and a different
+ * destination manager serially with the same JPEG object, because
+ * their private object sizes may be different.
+ *
+ * Caveat programmer.
+ */
+ if (cinfo->dest == NULL) { /* first time for this JPEG object? */
+ cinfo->dest = (struct jpeg_destination_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
+ JPOOL_PERMANENT,
+ sizeof(my_destination_mgr));
+ }
+
+ dest = (my_dest_ptr) cinfo->dest;
+ dest->pub.init_destination = init_destination;
+ dest->pub.empty_output_buffer = empty_output_buffer;
+ dest->pub.term_destination = term_destination;
+ dest->buffer = outbuffer;
+ dest->buf_size = *outsize;
+ dest->outsize = outsize;
+
+ if (*dest->buffer == NULL || dest->buf_size == 0) {
+ /* Allocate initial buffer */
+ *dest->buffer = malloc(OUTPUT_BUF_SIZE);
+ if (*dest->buffer == NULL)
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+ dest->buf_size = OUTPUT_BUF_SIZE;
+ }
+
+ dest->pub.next_output_byte = *dest->buffer;
+ dest->pub.free_in_buffer = dest->buf_size;
+}
+
+#endif
diff --git a/camlibs/jl2005c/jpeg_memsrcdest.h b/camlibs/jl2005c/jpeg_memsrcdest.h
new file mode 100644
index 000000000..e97118246
--- /dev/null
+++ b/camlibs/jl2005c/jpeg_memsrcdest.h
@@ -0,0 +1,9 @@
+#include <jpeglib.h>
+
+void
+jpeg_mem_src (j_decompress_ptr cinfo, unsigned char * buffer,
+ unsigned long bufsize);
+
+void
+jpeg_mem_dest (j_compress_ptr cinfo, unsigned char ** outbuffer,
+ unsigned long * outsize);
diff --git a/camlibs/jl2005c/library.c b/camlibs/jl2005c/library.c
index e94d2448f..783828326 100644
--- a/camlibs/jl2005c/library.c
+++ b/camlibs/jl2005c/library.c
@@ -24,9 +24,7 @@
#include <stdio.h>
#include <string.h>
-#include <bayer.h>
-#include <gamma.h>
-
+#include "jl2005bcd_decompress.h"
#include <gphoto2/gphoto2.h>
@@ -60,6 +58,7 @@ struct {
{"Sakar no. 75379", GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
{"Sakar no. 81890", GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
{"Sakar no. 91379", GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
+ {"Sakar no. 98379", GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
{"Sakar Kidz-Cam no. 88379", GP_DRIVER_STATUS_EXPERIMENTAL,
0x0979, 0x0227},
{"Sakar clipshot no. 1169x", GP_DRIVER_STATUS_EXPERIMENTAL,
@@ -79,7 +78,7 @@ struct {
GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
{"Vivitar Freelance", GP_DRIVER_STATUS_EXPERIMENTAL,
0x0979, 0x0227},
- {NULL,0,0,0,0}
+ {NULL,0,0,0}
};
int
@@ -121,14 +120,15 @@ camera_summary (Camera *camera, CameraText *summary, GPContext *context)
int num_pics;
num_pics = camera->pl->nb_entries;
GP_DEBUG("camera->pl->nb_entries = %i\n",camera->pl->nb_entries);
- sprintf (summary->text,
+ sprintf(summary->text,
_("This camera contains a Jeilin JL2005%c chipset.\n"
"The number of photos in it is %i. \n"),
camera->pl->model, num_pics);
return GP_OK;
}
-static int camera_manual (Camera *camera, CameraText *manual, GPContext *context)
+static int
+camera_manual (Camera *camera, CameraText *manual, GPContext *context)
{
strcpy(manual->text,
_(
@@ -182,11 +182,11 @@ get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
{
Camera *camera = user_data;
int w, h = 0, b = 0, k;
- unsigned char *pic_data, *pic_buffer;
+ unsigned char *pic_data, *pic_buffer, *pic_output = NULL;
int HEADERSIZE=16;
- unsigned char compressed;
+ int outputsize;
unsigned long start_of_photo;
- unsigned int blocksize = 0;
+ unsigned int downloadsize = 0;
int filled = 0;
GP_DEBUG ("Downloading pictures!\n");
@@ -195,29 +195,32 @@ get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
/* Get the number of the photo on the camera */
k = gp_filesystem_number (camera->fs, "/", filename, context);
- /* Determine the "compression" setting from the PAT table */
- compressed = (camera->pl->info[48+16*k+2]>>4) & 0x0f;
- h = camera->pl->info[48+16*k+4];
- w = camera->pl->info[48+16*k+5];
+ h = camera->pl->info[48 + 16 * k + 4] << 3;
+ w = camera->pl->info[48 + 16 * k + 5] << 3;
GP_DEBUG ("height is %i\n", h);
b = jl2005c_get_pic_data_size(camera->pl, camera->pl->info, k);
- GP_DEBUG("b = %i = 0x%x bytes\n", b,b);
+ GP_DEBUG("b = %i = 0x%x bytes\n", b, b);
start_of_photo = jl2005c_get_start_of_photo(camera->pl,
camera->pl->info, k);
GP_DEBUG("start_of_photo number %i = 0x%lx \n", k,start_of_photo);
- pic_buffer = malloc (b+16);
+ pic_buffer = malloc(b + HEADERSIZE);
if (!pic_buffer) return GP_ERROR_NO_MEMORY;
- memset (pic_buffer, 0, b+16);
- GP_DEBUG ("buffersize b+16 = %i = 0x%x bytes\n", b+16,b+16);
- /* copy info line for photo from allocation table, as header */
- memcpy(pic_buffer, camera->pl->info+48+16*k, 16);
- /* Camera can download in blocks of 0xfa00, with last block possibly
- * smaller. So first we set up a cache of that size (if not done
- * already) to hold raw data.
+ memset(pic_buffer, 0, b + HEADERSIZE);
+ GP_DEBUG("buffersize b + 16 = %i = 0x%x bytes\n", b + 16, b + 16);
+ /* Copy info line for photo from allocation table, as header */
+ memcpy(pic_buffer, camera->pl->info + 48 + 16 * k, 16);
+ pic_data = pic_buffer + HEADERSIZE;
+
+ /*
+ * Camera can download in blocks of 0xfa00, with only the last block
+ * possibly smaller. So first we set up a cache of that size
+ * (if it is not set up already) to hold raw data. If one tries
+ * instead to download one photo at a time, the camera will misbehave;
+ * data will be lost or corrupted. The dog will bite you, too.
*/
- pic_data = pic_buffer+HEADERSIZE;
+
if (!(camera->pl->data_cache)) {
camera->pl->data_cache = malloc (0xfa00);
}
@@ -227,45 +230,51 @@ get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
}
/* Is there data in the cache, or not? If yes, read from it into the
- * current photo, immediately. Update settings. But first a sanity
- * check.
+ * current photo, immediately. Update settings. But first two sanity
+ * checks.
*/
if (start_of_photo < camera->pl->bytes_put_away) {
GP_DEBUG("photo number %i starts in a funny place!\n",k);
- /* Trouble. Start over again. */
+ /* We need to start all over again to get this photo. */
jl2005c_reset(camera, camera->port);
- jl2005c_rewind (camera, camera->port);
- camera->pl->bytes_read_from_camera=0;
+ jl2005c_init (camera, camera->port, camera->pl);
}
if (start_of_photo + b > camera->pl->total_data_in_camera) {
- GP_DEBUG("photo number %i ends in a funny place!\n",k);
- GP_DEBUG("Blocksize may be wrong for this camera\n");
+ GP_DEBUG("Photo runs past end of data. Exiting. \n");
+ GP_DEBUG("Block size may be wrong for this camera\n");
return (GP_ERROR);
}
-
- /* This while loop is entered if the photo number k-1 was not requested
+ /*
+ * This while loop is entered if the photo number k-1 was not requested
* and thus has not been downloaded. The camera's rudimentary hardware
* obliges us to download all data consecutively and toss whatever
- * portion of said data that we do not intend to use.
+ * portion of said data that we do not intend to use. The rudimentary
+ * hardware also does not like to stop downloading at the end of one
+ * photo and then to start on the next. It wants to keep getting data
+ * in size 0xfa00 increments, and only the last block can be smaller.
+ * To do otherwise will cause data to be lost or corrupted.
+ *
+ * Whoever tries to simplify this convoluted and ugly procedure is
+ * warned that the obvious simplifications, while much prettier,
+ * just won't work. A kutya harap.
*/
while (camera->pl->bytes_read_from_camera <= start_of_photo) {
-
camera->pl->data_to_read = camera->pl->total_data_in_camera
- camera->pl->bytes_read_from_camera;
- blocksize = 0xfa00;
- if (camera->pl->data_to_read < blocksize)
- blocksize = camera->pl->data_to_read;
- GP_DEBUG("blocksize = 0x%x\n", blocksize);
- if(blocksize)
+ downloadsize = 0xfa00;
+ if (camera->pl->data_to_read < downloadsize)
+ downloadsize = camera->pl->data_to_read;
+ GP_DEBUG("downloadsize = 0x%x\n", downloadsize);
+ if (downloadsize)
jl2005c_get_picture_data (
camera->port,
(char *) camera->pl->data_cache,
- blocksize);
- camera->pl->bytes_read_from_camera += blocksize;
+ downloadsize);
+ camera->pl->bytes_read_from_camera += downloadsize;
}
- camera->pl->bytes_put_away=start_of_photo;
+ camera->pl->bytes_put_away = start_of_photo;
if (camera->pl->bytes_read_from_camera > start_of_photo) {
if(start_of_photo + b <= camera->pl->bytes_read_from_camera) {
@@ -273,12 +282,14 @@ get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
+ (start_of_photo % 0xfa00)
, b);
camera->pl->bytes_put_away += b;
- /* Photo data is contained in what is already
+ /*
+ * Photo data is contained in what is already
* downloaded.
* Jump immediately to process the photo.
- */
+ */
} else {
- /* photo starts in one block and ends in another */
+ /* Photo starts in one 0xfa00-sized download and ends
+ * in another */
filled = camera->pl->bytes_read_from_camera
- start_of_photo;
@@ -293,18 +304,19 @@ get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
camera->pl->data_to_read = camera->pl->total_data_in_camera
- camera->pl->bytes_read_from_camera;
- blocksize = 0xfa00;
- if (camera->pl->data_to_read < blocksize)
- blocksize = camera->pl->data_to_read;
- GP_DEBUG("blocksize = 0x%x\n", blocksize);
- if(blocksize)
+ downloadsize = 0xfa00;
+ if (camera->pl->data_to_read < downloadsize)
+ downloadsize = camera->pl->data_to_read;
+ GP_DEBUG("downloadsize = 0x%x\n", downloadsize);
+ if (downloadsize)
jl2005c_get_picture_data (
camera->port,
(char *) camera->pl->data_cache,
- blocksize);
- camera->pl->bytes_read_from_camera += blocksize;
+ downloadsize);
+ camera->pl->bytes_read_from_camera += downloadsize;
- if (camera->pl->bytes_read_from_camera >= start_of_photo + b ) {
+ if (camera->pl->bytes_read_from_camera >=
+ start_of_photo + b ) {
GP_DEBUG("THIS ONE?\n");
memcpy(pic_data + filled, camera->pl->data_cache,
b - filled);
@@ -312,20 +324,45 @@ get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
break;
} else {
GP_DEBUG("THIS ONE??\n");
- if (!blocksize)
+ if (!downloadsize)
break;
- memcpy(pic_data + filled,
- camera->pl->data_cache, blocksize);
- camera->pl->bytes_put_away += blocksize;
- filled += blocksize;
+ memcpy(pic_data + filled,
+ camera->pl->data_cache, downloadsize);
+ camera->pl->bytes_put_away += downloadsize;
+ filled += downloadsize;
}
}
- if (GP_FILE_TYPE_RAW == type) {
+ if (type == GP_FILE_TYPE_RAW) {
gp_file_set_mime_type(file, GP_MIME_RAW);
- gp_file_set_data_and_size(file, (char *)pic_buffer , b + 16);
+ gp_file_set_data_and_size(file, (char *)pic_buffer, b + 16);
return GP_OK;
- } else return GP_ERROR_NOT_SUPPORTED;
+ } else if (type == GP_FILE_TYPE_PREVIEW) {
+ if (!camera->pl->can_do_capture)
+ return GP_ERROR_NOT_SUPPORTED;
+ outputsize = (pic_buffer[9] & 0xf0) * 192 + 256;
+ if (outputsize == 256)
+ return GP_ERROR_NOT_SUPPORTED;
+ pic_output = calloc(outputsize, 1);
+ if (!pic_output)
+ return GP_ERROR_NO_MEMORY;
+ outputsize = jl2005bcd_decompress(pic_output, pic_buffer,
+ b + 16, 1);
+ gp_file_set_mime_type(file, GP_MIME_PPM);
+ gp_file_set_data_and_size(file, (char *)pic_output,
+ outputsize);
+ } else if (type == GP_FILE_TYPE_NORMAL) {
+ outputsize = 3 * w * h + 256;
+ pic_output = calloc(outputsize, 1);
+ if (!pic_output)
+ return GP_ERROR_NO_MEMORY;
+ outputsize = jl2005bcd_decompress(pic_output, pic_buffer,
+ b + 16, 0);
+ gp_file_set_mime_type(file, GP_MIME_PPM);
+ gp_file_set_data_and_size(file, (char *)pic_output,
+ outputsize);
+ } else
+ return GP_ERROR_NOT_SUPPORTED;
return GP_OK;
}
@@ -353,7 +390,7 @@ static CameraFilesystemFuncs fsfuncs = {
};
int
-camera_init(Camera *camera, GPContext *context)
+camera_init (Camera *camera, GPContext *context)
{
GPPortSettings settings;
int ret = 0;
@@ -363,7 +400,7 @@ camera_init(Camera *camera, GPContext *context)
camera->functions->summary = camera_summary;
camera->functions->about = camera_about;
camera->functions->exit = camera_exit;
-
+
GP_DEBUG ("Initializing the camera\n");
ret = gp_port_get_settings(camera->port,&settings);
if (ret < 0) return ret;
@@ -397,13 +434,12 @@ camera_init(Camera *camera, GPContext *context)
if (!camera->pl) return GP_ERROR_NO_MEMORY;
memset (camera->pl, 0, sizeof (CameraPrivateLibrary));
/* Connect to the camera */
- camera->pl->bytes_read_from_camera = 0;
camera->pl->total_data_in_camera=0;
camera->pl->data_to_read = 0;
- camera->pl->data_used_from_block = 0;
camera->pl->bytes_put_away = 0;
camera->pl->data_cache = NULL;
- jl2005c_init (camera,camera->port, camera->pl);
+ camera->pl->init_done = 0;
+ jl2005c_init (camera, camera->port, camera->pl);
return GP_OK;
}