summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Image.cc169
1 files changed, 167 insertions, 2 deletions
diff --git a/lib/Image.cc b/lib/Image.cc
index d098de3..a2e7a7c 100644
--- a/lib/Image.cc
+++ b/lib/Image.cc
@@ -4,6 +4,120 @@
#include "Image.h"
#include "gettext.h"
+#ifdef HAVE_LIBJPEG
+#include "jpeglib.h"
+#include "jerror.h"
+
+extern "C" {
+
+typedef struct {
+ struct jpeg_destination_mgr pub; /* public fields */
+
+ Handle * outfile; /* target stream */
+ JOCTET * buffer; /* start of buffer */
+} my_destination_mgr;
+
+#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
+#define SIZEOF(object) ((size_t) sizeof(object))
+
+
+typedef my_destination_mgr * my_dest_ptr;
+
+METHODDEF(void)
+init_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ /* Allocate the output buffer --- it will be released when done with image */
+ dest->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+}
+
+METHODDEF(boolean)
+empty_output_buffer (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ if (dest->outfile->write(dest->buffer, OUTPUT_BUF_SIZE) !=
+ (size_t) OUTPUT_BUF_SIZE)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+
+ return TRUE;
+}
+
+METHODDEF(void)
+term_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+ size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
+
+ /* Write any data remaining in the buffer */
+ if (datacount > 0) {
+ if (dest->outfile->write(dest->buffer, datacount) != datacount)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ }
+}
+
+GLOBAL(void)
+jpeg_handle_dest (j_compress_ptr cinfo, Handle * outfile)
+{
+ 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->outfile = outfile;
+}
+
+}
+#endif
+
+typedef unsigned char Byte;
+typedef unsigned short int Word;
+typedef unsigned long int DWord;
+
+struct TGAHeader {
+ Byte IDLength;
+ Byte ColorMapType;
+ Byte ImageType;
+ Word CM_FirstEntry;
+ Word CM_Length;
+ Byte CM_EntrySize;
+ Word IS_XOrigin;
+ Word IS_YOrigin;
+ Word IS_Width;
+ Word IS_Height;
+ Byte IS_Depth;
+ Byte IS_Descriptor;
+} PACKED;
+
+struct TGAFooter {
+ DWord ExtOffset;
+ DWord DevOffset;
+ char Sig[18];
+} PACKED;
+
+
Image::Image(unsigned int ax, unsigned int ay) : x(ax), y(ay), img((Color *) malloc(x * y * sizeof(Color))) {
Fill();
}
@@ -42,6 +156,10 @@ void Image::SetPixel(unsigned int px, unsigned int py, Color c) {
img[x * py + px] = c;
}
+unsigned char * Image::GetBuffer() {
+ return (unsigned char *) img;
+}
+
#ifndef WORDS_BIGENDIAN
#define WORDS_BIGENDIAN 0
#else
@@ -49,8 +167,11 @@ void Image::SetPixel(unsigned int px, unsigned int py, Color c) {
#define WORDS_BIGENDIAN 1
#endif
-bool Image::Prepare(unsigned int f) {
- if (GetSize()) return false;
+bool Image::Prepare(unsigned int f) throw (GeneralException) {
+ int ix, iy;
+
+ if (GetSize())
+ throw GeneralException("Image already prepared.");
switch (f) {
case FORMAT_TGA_BASIC:
@@ -81,7 +202,51 @@ bool Image::Prepare(unsigned int f) {
return true;
break;
+ case FORMAT_JPEG:
+#ifndef HAVE_LIBJPEG
+ throw GeneralException("You can't create a jpeg image when the library libjpeg isn't linked in.");
+#else
+ {
+ char * rgb_buffer = (char *) malloc(x * y * 3);
+ for (iy = 0; iy < y; y++) {
+ for (ix = 0; ix < x; x++) {
+ rgb_buffer[(ix + iy * x) * 3 + 0] = img[ix + iy * x].R;
+ rgb_buffer[(ix + iy * x) * 3 + 1] = img[ix + iy * x].G;
+ rgb_buffer[(ix + iy * x) * 3 + 2] = img[ix + iy * x].B;
+ }
+ }
+
+ struct jpeg_compress_struct cinfo;
+ JSAMPROW row_pointer[1];
+ struct jpeg_error_mgr jerr;
+
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ jpeg_handle_dest(&cinfo, this);
+
+ cinfo.image_width = x;
+ cinfo.image_height = y;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, 9, TRUE /* limit to baseline-JPEG values */);
+
+ jpeg_start_compress(&cinfo, TRUE);
+
+ int row_stride = x * 3;
+
+ while (cinfo.next_scanline < cinfo.image_height) {
+ row_pointer[0] = (JSAMPLE *) &rgb_buffer[cinfo.next_scanline * row_stride];
+ (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ }
+#endif
+ break;
default:
+ throw GeneralException("Image format unkown.");
return false;
}
}