notepad_thumbnail.cpp

Go to the documentation of this file.
00001 /*
00002  * File Name: notepad_filestore.cpp
00003  */
00004 
00005 /*
00006  * This file is part of notepad.
00007  *
00008  * notepad is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * notepad is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2010 IREX Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 #include "config.h"
00028 #include <gtk/gtk.h>
00029 #include <libermetadb/ermetadb.h>
00030 
00031 #include "log.h"
00032 #include "notepad_utils.h"
00033 #include "notepad_thumbnail.h"
00034 
00035 #include "notepad_filestore.h"
00036 #include "notepad_doc.h"
00037 #include "notepad_ipc.h"
00038 
00039 #include "notepad_pages.h" // TODO elimitate
00040 
00041 
00042 namespace notepad
00043 {
00044 
00045     // Columns in database table thumbnails.
00046     static const char* THUMBNAIL_COLUMNS[CThumbnail::THUMBNAIL_COUNT] =
00047     {
00048         "thumb_data_mini", // not used
00049         "thumb_data_small",
00050         "thumb_data_medium",
00051         "thumb_data_large" // not used
00052     };
00053 
00054 
00055     // store thumbnails in globaldb
00056     void CThumbnail::storeThumbnail(CFileStore& filestore, CNotepadPages& pages, gint margin)
00057     {
00058         LOGPRINTF("entry");
00059 
00060         // Create table.
00061         metadata_table* values = metadata_table_new();
00062         int             values_index = -1;
00063         if (values == NULL)
00064         {
00065             WARNPRINTF("exit failed metadata_table");
00066             return;
00067         }
00068 
00069         // convert pixmap to pixbuf
00070         GdkImage* cover = pages.get_page(1);
00071         
00072         if (cover == 0 || cover->width == 0 || cover->height == 0)
00073         {
00074             WARNPRINTF("trying to thumbnail an uninitialized page");
00075             return;
00076         }
00077 
00078         GdkPixbuf* raw_bmp = gdk_pixbuf_get_from_image(NULL,
00079                                                        cover,
00080                                                        gdk_colormap_get_system(),
00081                                                        margin, margin,
00082                                                        0, 0,
00083 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00084                                                        cover->width - margin,
00085 #endif
00086 #if MACHINE_IS_DR800S || MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
00087                                                        cover->width - 2*margin, 
00088 #endif
00089                                                        cover->height - margin);
00090 
00091         if (raw_bmp == NULL)
00092         {
00093             WARNPRINTF("Error creating pixbuf.");
00094             return;
00095         }
00096 
00097         // rotate if in landscape
00098         np_rotation rotation = ipc_get_rotation();
00099         GdkPixbuf* rotated_bmp = 0;
00100         switch (rotation) 
00101         {
00102             case NP_CLOCKWISE:
00103                 rotated_bmp = gdk_pixbuf_rotate_simple(raw_bmp, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
00104                 g_object_unref(raw_bmp);
00105                 raw_bmp = rotated_bmp;
00106                 break;
00107             case NP_ANTICLOCKWISE:
00108                 rotated_bmp = gdk_pixbuf_rotate_simple(raw_bmp, GDK_PIXBUF_ROTATE_CLOCKWISE);
00109                 g_object_unref(raw_bmp);
00110                 raw_bmp = rotated_bmp;
00111                 break;
00112             case NP_PORTRAIT:
00113             default:
00114                 break;
00115         }
00116 
00117         // From pixbuf to blobs. 
00118         for (int size = 0; size <= THUMBNAIL_COUNT; size++)
00119         {
00120             if (size != THUMBNAIL_SMALL && size != THUMBNAIL_MEDIUM)
00121             {
00122                 continue; // pass the unused sizes
00123             }
00124 
00125             // Calculate thumbnail size, conserve aspect ratio.
00126             int w = getWidth(static_cast<ThumbnailSize>(size));
00127             int h = getHeight(static_cast<ThumbnailSize>(size));
00128             int raw_w = gdk_pixbuf_get_width(raw_bmp);
00129             int raw_h = gdk_pixbuf_get_height(raw_bmp);
00130             float zoom_w = ((float)w) / ((float)raw_w);
00131             float zoom_h = ((float)h) / ((float)raw_h);
00132             if (zoom_w < zoom_h)
00133             {
00134                 h = static_cast<int> (( ((float)raw_h) * zoom_w) + 0.5);
00135             }
00136             else
00137             {
00138                 w = static_cast<int> (( ((float)raw_w) * zoom_h) + 0.5);
00139             }
00140 
00141             // Scale down the rendered bitmap.
00142             GdkPixbuf* scaled_bmp = gdk_pixbuf_scale_simple(raw_bmp, w, h, GDK_INTERP_BILINEAR);
00143 
00144             // Enforce thin lines to clip to black
00145             enhance(scaled_bmp, w, h);
00146 
00147             // Draw rectangle around the pixbuf.
00148             drawRectangle(scaled_bmp, w, h);
00149 
00150             gchar* blob = NULL;
00151             gsize  blob_size = 0;
00152 
00153             // Add column according to the size.
00154             if (gdk_pixbuf_save_to_buffer(scaled_bmp, &blob, &blob_size, "png", NULL, NULL))
00155             {
00156                 metadata_table_add_column(values, THUMBNAIL_COLUMNS[size]);
00157                 values_index++;
00158 
00159                 metadata_table_set_blob(values, values_index, blob, blob_size);
00160             }
00161 
00162             g_object_unref(scaled_bmp);
00163         }
00164 
00165         // write thumbnails to global database
00166         const char* mountpoint = ipc_get_mountpoint();
00167         erMetadb global_db = ermetadb_global_open(mountpoint, FALSE);
00168         if (global_db == 0) 
00169         {
00170             WARNPRINTF("open globaldb for writing thumbnail failed.");
00171             return;
00172         }
00173         gchar* dir  = filestore.getFileNameDirPart();
00174         gchar* file = filestore.getFileNameFilePart();
00175 
00176         int rc = ermetadb_global_change_file(global_db, dir, file, values);
00177         if (rc != ER_OK) 
00178         {
00179             WARNPRINTF("cannot update global db");
00180         }
00181         ermetadb_close(global_db);
00182         g_free(dir);
00183         g_free(file);
00184 
00185         // Clean up.
00186         if (raw_bmp)
00187         {
00188             g_object_unref(raw_bmp);
00189         }
00190         metadata_table_free(values);
00191 
00192         LOGPRINTF("exit");
00193         return;
00194     }
00195 
00196 
00197     // functions for drawing the rectangle around the thumbnail
00198     void CThumbnail::putPixel(GdkPixbuf* pixbuf, gint x, gint y)
00199     {
00200         gint channel    = gdk_pixbuf_get_n_channels(pixbuf);
00201         gint rowstride  = gdk_pixbuf_get_rowstride(pixbuf);
00202         guchar* pixel   = gdk_pixbuf_get_pixels(pixbuf);
00203         guchar* p       = pixel + y * rowstride + x * channel;
00204         p[0] = 0; //r
00205         p[1] = 0; //g
00206         p[2] = 0; //b
00207     }
00208 
00209     void CThumbnail::enhance(GdkPixbuf* pixbuf, gint width, gint height)
00210     {
00211         gint channel    = gdk_pixbuf_get_n_channels(pixbuf);
00212         gint rowstride  = gdk_pixbuf_get_rowstride(pixbuf);
00213         guchar* pixel   = gdk_pixbuf_get_pixels(pixbuf);
00214 
00215         for (gint x = 0; x < width; x++)
00216         {
00217             for (gint y = 0; y < height; y++)
00218             {
00219                 guchar* p = pixel + y * rowstride + x * channel;
00220 
00221                 // Set not-white to black
00222                 if (p[0] + p[1] + p[2] < 3*0xFF) 
00223                 {
00224                     p[0] = 0; //r
00225                     p[1] = 0; //g
00226                     p[2] = 0; //b
00227                 }
00228             }
00229         }
00230     }
00231 
00232     void CThumbnail::drawRectangle(GdkPixbuf* pixbuf, gint width, gint height) 
00233     { 
00234         g_assert(pixbuf != 0);
00235         gint w = width -1; // right line 1px before to fit width
00236         gint h = height -1; // lower line 1px before to fit height
00237         for (gint x = 0; x < width; x++)
00238         {
00239             putPixel(pixbuf, x, 0);
00240             putPixel(pixbuf, x, h);
00241         }
00242         for (gint y = 0; y < height; y++)
00243         {
00244             putPixel(pixbuf, 0, y);
00245             putPixel(pixbuf, w, y);
00246         }
00247     }
00248 
00249     gint CThumbnail::getWidth(const ThumbnailSize size)
00250     {
00251         switch (size)
00252         {
00253             case THUMBNAIL_SMALL:
00254                 return 60;
00255             case THUMBNAIL_MEDIUM:
00256                 return 120;
00257             case THUMBNAIL_LARGE: // not used
00258                 return 300;
00259             default:
00260                 return 300;
00261         }
00262     }
00263 
00264     gint CThumbnail::getHeight(const ThumbnailSize size)
00265     {
00266         switch (size)
00267         {
00268             case THUMBNAIL_SMALL:
00269                 return 60;
00270             case THUMBNAIL_MEDIUM:
00271                 return 120;
00272             case THUMBNAIL_LARGE: // not used
00273                 return 300;
00274             default:
00275                 return 300;
00276         }
00277     }
00278 
00279 }
00280 
00281 
Generated by  doxygen 1.6.2-20100208