== Sequencer ==
authorPeter Schlaile <peter@schlaile.de>
Thu, 31 Jan 2008 15:28:16 +0000 (15:28 +0000)
committerPeter Schlaile <peter@schlaile.de>
Thu, 31 Jan 2008 15:28:16 +0000 (15:28 +0000)
Updated image preview a lot:
* Added a histogram-scope
* Added optional title-safe margins
* Re-arranged header, so that only usefull buttons are shown in image
  preview mode
* Added zebra-mode for visual feedback of over-exposure regions
  (helps in before and especially after color correction :)
* Added color-seperation-mode for waveform-display
* Show 10%, 70% and 90% hints in waveform-display

source/blender/include/BSE_seqscopes.h
source/blender/makesdna/DNA_space_types.h
source/blender/src/drawseq.c
source/blender/src/header_seq.c
source/blender/src/seqscopes.c

index 3dd5e49592800932a97c5de5c5062786227adbc3..a2b3c65d6e96c93006e4ba75d6741d8e5c4cd293 100644 (file)
 struct ImBuf;
 
 struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf);
+struct ImBuf *make_sep_waveform_view_from_ibuf(struct ImBuf * ibuf);
 struct ImBuf *make_vectorscope_view_from_ibuf(struct ImBuf * ibuf);
+struct ImBuf *make_zebra_view_from_ibuf(struct ImBuf * ibuf, float perc);
+struct ImBuf *make_histogram_view_from_ibuf(struct ImBuf * ibuf);
 
 #endif
 
index 569a6ffc8aa96d6d74f86ea0c5eb06b596638bd8..c805221567f6cc9b899de2e313c55b46a0a123e9 100644 (file)
@@ -150,7 +150,7 @@ typedef struct SpaceSeq {
        float xof, yof; /* offset for drawing the image preview */
        short mainb, zoom;
        short chanshown;
-       short pad2;
+       short zebra;
        int flag;
        int pad;
 } SpaceSeq;
@@ -618,10 +618,13 @@ typedef struct SpaceImaSel {
 #define SEQ_DRAW_IMG_IMBUF        1
 #define SEQ_DRAW_IMG_WAVEFORM     2
 #define SEQ_DRAW_IMG_VECTORSCOPE  3
+#define SEQ_DRAW_IMG_HISTOGRAM    4
 
 /* sseq->flag */
-#define SEQ_DRAWFRAMES  1
+#define SEQ_DRAWFRAMES   1
 #define SEQ_MARKER_TRANS 2
+#define SEQ_DRAW_COLOR_SEPERATED     4
+#define SEQ_DRAW_SAFE_MARGINS        8
 
 /* space types, moved from DNA_screen_types.h */
 enum {
index abf0f24e89248bef4d8278a9df9ae7628dcbf213..ab77294abea1f2a3806016dc4da8f2f24db2fabf 100644 (file)
@@ -793,6 +793,7 @@ static void draw_image_seq(ScrArea *sa)
        int free_ibuf = 0;
        static int recursive= 0;
        float zoom;
+       float zoomx, zoomy;
 
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glClear(GL_COLOR_BUFFER_BIT);
@@ -837,19 +838,38 @@ static void draw_image_seq(ScrArea *sa)
        
        if(ibuf==NULL) 
                return;
-       if(ibuf->rect_float && ibuf->rect==NULL)
-               IMB_rect_from_float(ibuf);
-       if(ibuf->rect==NULL) 
+
+       if(ibuf->rect==NULL && ibuf->rect_float == NULL) 
                return;
 
-       if (sseq->mainb == SEQ_DRAW_IMG_WAVEFORM) {
-               ibuf = make_waveform_view_from_ibuf(ibuf);
+       switch(sseq->mainb) {
+       case SEQ_DRAW_IMG_IMBUF:
+               if (sseq->zebra != 0) {
+                       ibuf = make_zebra_view_from_ibuf(ibuf, sseq->zebra);
+                       free_ibuf = 1;
+               }
+               break;
+       case SEQ_DRAW_IMG_WAVEFORM:
+               if ((sseq->flag & SEQ_DRAW_COLOR_SEPERATED) != 0) {
+                       ibuf = make_sep_waveform_view_from_ibuf(ibuf);
+               } else {
+                       ibuf = make_waveform_view_from_ibuf(ibuf);
+               }
                free_ibuf = 1;
-       } else if (sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE) {
+               break;
+       case SEQ_DRAW_IMG_VECTORSCOPE:
                ibuf = make_vectorscope_view_from_ibuf(ibuf);
                free_ibuf = 1;
+               break;
+       case SEQ_DRAW_IMG_HISTOGRAM:
+               ibuf = make_histogram_view_from_ibuf(ibuf);
+               free_ibuf = 1;
+               break;
        }
 
+       if(ibuf->rect_float && ibuf->rect==NULL)
+               IMB_rect_from_float(ibuf);
+
        if (sseq->zoom > 0) {
                zoom = sseq->zoom;
        } else if (sseq->zoom == 0) {
@@ -864,13 +884,44 @@ static void draw_image_seq(ScrArea *sa)
 
        /* needed for gla draw */
        glaDefine2DArea(&curarea->winrct);
+
+       zoomx = zoom * ((float)G.scene->r.xasp / (float)G.scene->r.yasp);
+       zoomy = zoom;
        
-       glPixelZoom(zoom * ((float)G.scene->r.xasp / (float)G.scene->r.yasp), zoom);
+       glPixelZoom(zoomx, zoomy);
        
        glaDrawPixelsSafe(x1, y1, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
        
        glPixelZoom(1.0, 1.0);
 
+       /* safety border */
+       if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && 
+           (sseq->flag & SEQ_DRAW_SAFE_MARGINS) != 0) {
+               float fac= 0.1;
+               float x2 = x1 + ibuf->x * zoomx;
+               float y2 = y1 + ibuf->y * zoomy;
+               
+               float a= fac*(x2-x1);
+               x1+= a; 
+               x2-= a;
+       
+               a= fac*(y2-y1);
+               y1+= a;
+               y2-= a;
+       
+               glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
+               setlinestyle(3);
+
+               BIF_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0);
+               
+               uiSetRoundBox(15);
+               gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, 12.0);
+
+               setlinestyle(0);
+               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+       }
+
+
        if (free_ibuf) {
                IMB_freeImBuf(ibuf);
        } 
index 1880484a09f06718064d8fdeab39c8c7ad175aab..a937960036c9b66fc8bed7b1eebfe0e203fed43f 100644 (file)
@@ -658,22 +658,23 @@ void seq_buttons()
                xmax= GetButStringLength("View");
                uiDefPulldownBut(block,seq_viewmenu, NULL, "View", xco, -2, xmax-3, 24, "");
                xco+=xmax;
-
-               xmax= GetButStringLength("Select");
-               uiDefPulldownBut(block,seq_selectmenu, NULL, "Select", xco, -2, xmax-3, 24, "");
-               xco+=xmax;
-
-               xmax= GetButStringLength("Marker");
-               uiDefPulldownBut(block,seq_markermenu, NULL, "Marker", xco, -2, xmax-3, 24, "");
-               xco+=xmax;
+               if (sseq->mainb == 0) {
+                       xmax= GetButStringLength("Select");
+                       uiDefPulldownBut(block,seq_selectmenu, NULL, "Select", xco, -2, xmax-3, 24, "");
+                       xco+=xmax;
+
+                       xmax= GetButStringLength("Marker");
+                       uiDefPulldownBut(block,seq_markermenu, NULL, "Marker", xco, -2, xmax-3, 24, "");
+                       xco+=xmax;
                
-               xmax= GetButStringLength("Add");
-               uiDefPulldownBut(block, seq_addmenu, NULL, "Add", xco, -2, xmax-3, 24, "");
-               xco+= xmax;
+                       xmax= GetButStringLength("Add");
+                       uiDefPulldownBut(block, seq_addmenu, NULL, "Add", xco, -2, xmax-3, 24, "");
+                       xco+= xmax;
 
-               xmax= GetButStringLength("Strip");
-               uiDefPulldownBut(block, seq_editmenu, NULL, "Strip", xco, -2, xmax-3, 24, "");
-               xco+= xmax;
+                       xmax= GetButStringLength("Strip");
+                       uiDefPulldownBut(block, seq_editmenu, NULL, "Strip", xco, -2, xmax-3, 24, "");
+                       xco+= xmax;
+               }
 
                /* end of pull down menus */
                uiBlockSetEmboss(block, UI_EMBOSS);
@@ -685,17 +686,19 @@ void seq_buttons()
                          "|Sequence %x0"
                          "|Image Preview %x1"
                          "|Luma Waveform %x2"
-                         "|Chroma Vectorscope %x3",
+                         "|Chroma Vectorscope %x3"
+                         "|Histogram %x4",
                          xco,0,XIC+10,YIC, &sseq->mainb, 0.0, 3.0, 
                          0, 0, 
                          "Shows the sequence output image preview");
        
        xco+= 8 + XIC+10;
        
-       /* CHANNEL shown in 3D preview */
        if(sseq->mainb) {
                int minchan = 0;
 
+               /* CHANNEL shown in image preview */
+
                if (G.scene->ed && ((Editing*)G.scene->ed)->metastack.first)
                        minchan = -BLI_countlist(&((Editing*)G.scene->ed)->metastack);
 
@@ -705,22 +708,51 @@ void seq_buttons()
                "The channel number shown in the image preview. 0 is the result of all strips combined.");
                
                xco+= 8 + XIC*3.5;
+
+               if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+                       uiDefButS(block, MENU, B_REDR, 
+                                 "Show zebra: %t"
+                                 "|Z 110 %x110"
+                                 "|Z 100 %x100"
+                                 "|Z 95  %x95"
+                                 "|Z 90  %x90"
+                                 "|Z 70  %x70"
+                                 "|Z Off %x0", 
+                                 xco,0,3.0 * XIC, YIC, &sseq->zebra, 
+                                 0,0,0,0, 
+                                 "Show overexposed "
+                                 "areas with zebra stripes");
+
+                       xco+= 8 + XIC*3.0;
+
+                       uiDefButBitI(block, TOG, SEQ_DRAW_SAFE_MARGINS, 
+                                    B_REDR, "T",
+                                    xco,0,XIC,YIC, &sseq->flag, 
+                                    0, 0, 0, 0, 
+                                    "Draw title safe margins in preview");
+                       xco+= 8 + XIC;
+               }
+               
+               if (sseq->mainb == SEQ_DRAW_IMG_WAVEFORM) {
+                       uiDefButBitI(block, TOG, SEQ_DRAW_COLOR_SEPERATED, 
+                                    B_REDR, "CS",
+                                    xco,0,XIC,YIC, &sseq->flag, 
+                                    0, 0, 0, 0, 
+                                    "Seperate color channels in preview");
+                       xco+= 8 + XIC;
+               }
+       } else {
+               /* ZOOM and BORDER */
+               xco+= 8;
+               uiBlockBeginAlign(block);
+               uiDefIconButI(block, TOG, B_VIEW2DZOOM, ICON_VIEWZOOM,  xco,0,XIC,YIC, &viewmovetemp, 0, 0, 0, 0, "Zooms view in and out (Ctrl MiddleMouse)");
+               uiDefIconBut(block, BUT, B_IPOBORDER, ICON_BORDERMOVE,  xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Zooms view to fit area");
+               uiBlockEndAlign(block);
+
+               xco+= 16;
        }
 
-       
-       /* ZOOM and BORDER */
-       xco+= 8;
-       uiBlockBeginAlign(block);
-       uiDefIconButI(block, TOG, B_VIEW2DZOOM, ICON_VIEWZOOM,  xco,0,XIC,YIC, &viewmovetemp, 0, 0, 0, 0, "Zooms view in and out (Ctrl MiddleMouse)");
-       uiDefIconBut(block, BUT, B_IPOBORDER, ICON_BORDERMOVE,  xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Zooms view to fit area");
-       uiBlockEndAlign(block);
-
-       /* CLEAR MEM */
-       xco+= 8;
-
-       /* CLEAR MEM */
-       xco+= 8;
-       uiDefBut(block, BUT, B_SEQCLEAR, "Refresh",     xco+=XIC,0,3*XIC,YIC, 0, 0, 0, 0, 0, "Clears all buffered images in memory");
+       uiDefBut(block, BUT, B_SEQCLEAR, "Refresh", xco,0,3*XIC,YIC, 0, 0, 0, 0, 0, "Clears all buffered images in memory");
 
        uiDrawBlock(block);
 }
index 1fa01a6145ef8cd62bae25078aa49fde14f90e8e..84a92982ab553c2b2996795aef91706ea184e3b5 100644 (file)
@@ -53,6 +53,14 @@ static void scope_put_pixel(unsigned char* table, unsigned char * pos)
        pos[3] = 255;
 }
 
+static void scope_put_pixel_single(unsigned char* table, unsigned char * pos,
+                                  int col)
+{
+       char newval = table[pos[col]];
+       pos[col] = newval;
+       pos[3] = 255;
+}
+
 static void wform_put_line(int w,
                           unsigned char * last_pos, unsigned char * new_pos)
 {
@@ -71,6 +79,67 @@ static void wform_put_line(int w,
        }
 }
 
+static void wform_put_line_single(
+       int w, unsigned char * last_pos, unsigned char * new_pos, int col)
+{
+       if (last_pos > new_pos) {
+               unsigned char* temp = new_pos;
+               new_pos = last_pos;
+               last_pos = temp;
+       }
+
+       while (last_pos < new_pos) {
+               if (last_pos[col] == 0) {
+                       last_pos[col] = 32;
+                       last_pos[3] = 255;
+               }
+               last_pos += 4*w;
+       }
+}
+
+static void wform_put_border(unsigned char * tgt, int w, int h)
+{
+       int x, y;
+
+       for (x = 0; x < w; x++) {
+               unsigned char * p = tgt + 4 * x;
+               p[1] = p[3] = 255.0;
+               p[4 * w + 1] = p[4 * w + 3] = 255.0;
+               p = tgt + 4 * (w * (h - 1) + x);
+               p[1] = p[3] = 255.0;
+               p[-4 * w + 1] = p[-4 * w + 3] = 255.0;
+       }
+
+       for (y = 0; y < h; y++) {
+               unsigned char * p = tgt + 4 * w * y;
+               p[1] = p[3] = 255.0;
+               p[4 + 1] = p[4 + 3] = 255.0;
+               p = tgt + 4 * (w * y + w - 1);
+               p[1] = p[3] = 255.0;
+               p[-4 + 1] = p[-4 + 3] = 255.0;
+       }
+}
+
+static void wform_put_gridrow(unsigned char * tgt, float perc, int w, int h)
+{
+       int i;
+
+       tgt += (int) (perc/100.0 * h) * w * 4;
+
+       for (i = 0; i < w*2; i++) {
+               tgt[0] = 255;
+
+               tgt += 4;
+       }
+}
+
+static void wform_put_grid(unsigned char * tgt, int w, int h)
+{
+       wform_put_gridrow(tgt, 90.0, w, h);
+       wform_put_gridrow(tgt, 70.0, w, h);
+       wform_put_gridrow(tgt, 10.0, w, h);
+}
+
 static struct ImBuf *make_waveform_view_from_ibuf_byte(struct ImBuf * ibuf)
 {
        struct ImBuf * rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect, 0);
@@ -82,6 +151,8 @@ static struct ImBuf *make_waveform_view_from_ibuf_byte(struct ImBuf * ibuf)
        float waveform_gamma = 0.2;
        unsigned char wtable[256];
 
+       wform_put_grid(tgt, w, h);
+
        for (x = 0; x < 256; x++) {
                wtable[x] = (unsigned char) (pow(((float) x + 1)/256, 
                                                 waveform_gamma)*255);
@@ -110,23 +181,7 @@ static struct ImBuf *make_waveform_view_from_ibuf_byte(struct ImBuf * ibuf)
                }
        }
 
-       for (x = 0; x < w; x++) {
-               unsigned char * p = tgt + 4 * x;
-               p[1] = p[3] = 255.0;
-               p[4 * w + 1] = p[4 * w + 3] = 255.0;
-               p = tgt + 4 * (w * (h - 1) + x);
-               p[1] = p[3] = 255.0;
-               p[-4 * w + 1] = p[-4 * w + 3] = 255.0;
-       }
-
-       for (y = 0; y < h; y++) {
-               unsigned char * p = tgt + 4 * w * y;
-               p[1] = p[3] = 255.0;
-               p[4 + 1] = p[4 + 3] = 255.0;
-               p = tgt + 4 * (w * y + w - 1);
-               p[1] = p[3] = 255.0;
-               p[-4 + 1] = p[-4 + 3] = 255.0;
-       }
+       wform_put_border(tgt, w, h);
        
        return rval;
 }
@@ -142,6 +197,8 @@ static struct ImBuf *make_waveform_view_from_ibuf_float(struct ImBuf * ibuf)
        float waveform_gamma = 0.2;
        unsigned char wtable[256];
 
+       wform_put_grid(tgt, w, h);
+
        for (x = 0; x < 256; x++) {
                wtable[x] = (unsigned char) (pow(((float) x + 1)/256, 
                                                 waveform_gamma)*255);
@@ -173,23 +230,7 @@ static struct ImBuf *make_waveform_view_from_ibuf_float(struct ImBuf * ibuf)
                }
        }
 
-       for (x = 0; x < w; x++) {
-               unsigned char * p = tgt + 4 * x;
-               p[1] = p[3] = 255.0;
-               p[4 * w + 1] = p[4 * w + 3] = 255.0;
-               p = tgt + 4 * (w * (h - 1) + x);
-               p[1] = p[3] = 255.0;
-               p[-4 * w + 1] = p[-4 * w + 3] = 255.0;
-       }
-
-       for (y = 0; y < h; y++) {
-               unsigned char * p = tgt + 4 * w * y;
-               p[1] = p[3] = 255.0;
-               p[4 + 1] = p[4 + 3] = 255.0;
-               p = tgt + 4 * (w * y + w - 1);
-               p[1] = p[3] = 255.0;
-               p[-4 + 1] = p[-4 + 3] = 255.0;
-       }
+       wform_put_border(tgt, w, h);
        
        return rval;
 }
@@ -204,6 +245,328 @@ struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf)
 }
 
 
+static struct ImBuf *make_sep_waveform_view_from_ibuf_byte(struct ImBuf * ibuf)
+{
+       struct ImBuf * rval = IMB_allocImBuf(
+               ibuf->x + 3, 515, 32, IB_rect, 0);
+       int x,y;
+       unsigned char* src = (unsigned char*) ibuf->rect;
+       unsigned char* tgt = (unsigned char*) rval->rect;
+       int w = ibuf->x + 3;
+       int sw = ibuf->x/3;
+       int h = 515;
+       float waveform_gamma = 0.2;
+       unsigned char wtable[256];
+
+       wform_put_grid(tgt, w, h);
+
+       for (x = 0; x < 256; x++) {
+               wtable[x] = (unsigned char) (pow(((float) x + 1)/256, 
+                                                waveform_gamma)*255);
+       }
+
+       for (y = 0; y < ibuf->y; y++) {
+               unsigned char * last_p[3] = {0,0,0};
+
+               for (x = 0; x < ibuf->x; x++) {
+                       int c;
+                       unsigned char * rgb = src + 4 * (ibuf->x * y + x);
+                       for (c = 0; c < 3; c++) {
+                               unsigned char * p = tgt;
+                               p += 4 * (w * ((rgb[c] * (h - 3))/255 + 1) 
+                                         + c * sw + x/3 + 1);
+
+                               scope_put_pixel_single(wtable, p, c);
+                               p += 4 * w;
+                               scope_put_pixel_single(wtable, p, c);
+
+                               if (last_p[c] != 0) {
+                                       wform_put_line_single(
+                                               w, last_p[c], p, c);
+                               }
+                               last_p[c] = p;
+                       }
+               }
+       }
+
+       wform_put_border(tgt, w, h);
+       
+       return rval;
+}
+
+static struct ImBuf *make_sep_waveform_view_from_ibuf_float(
+       struct ImBuf * ibuf)
+{
+       struct ImBuf * rval = IMB_allocImBuf(
+               ibuf->x + 3, 515, 32, IB_rect, 0);
+       int x,y;
+       float* src = ibuf->rect_float;
+       unsigned char* tgt = (unsigned char*) rval->rect;
+       int w = ibuf->x + 3;
+       int sw = ibuf->x/3;
+       int h = 515;
+       float waveform_gamma = 0.2;
+       unsigned char wtable[256];
+
+       wform_put_grid(tgt, w, h);
+
+       for (x = 0; x < 256; x++) {
+               wtable[x] = (unsigned char) (pow(((float) x + 1)/256, 
+                                                waveform_gamma)*255);
+       }
+
+       for (y = 0; y < ibuf->y; y++) {
+               unsigned char * last_p[3] = {0, 0, 0};
+
+               for (x = 0; x < ibuf->x; x++) {
+                       int c;
+                       float * rgb = src + 4 * (ibuf->x * y + x);
+                       for (c = 0; c < 3; c++) {
+                               unsigned char * p = tgt;
+                               p += 4 * (w * ((int) (rgb[c] * (h - 3)) + 1)
+                                         + c * sw + x/3 + 1);
+
+                               scope_put_pixel_single(wtable, p, c);
+                               p += 4 * w;
+                               scope_put_pixel_single(wtable, p, c);
+
+                               if (last_p[c] != 0) {
+                                       wform_put_line_single(
+                                               w, last_p[c], p, c);
+                               }
+                               last_p[c] = p;
+                       }
+               }
+       }
+
+       wform_put_border(tgt, w, h);
+       
+       return rval;
+}
+
+struct ImBuf *make_sep_waveform_view_from_ibuf(struct ImBuf * ibuf)
+{
+       if (ibuf->rect_float) {
+               return make_sep_waveform_view_from_ibuf_float(ibuf);
+       } else {
+               return make_sep_waveform_view_from_ibuf_byte(ibuf);
+       }
+}
+
+static void draw_zebra_byte(struct ImBuf * src,struct ImBuf * ibuf, float perc)
+{
+       unsigned int limit = 255 * perc / 100.0;
+       unsigned char * p = (unsigned char*) src->rect;
+       unsigned char * o = (unsigned char*) ibuf->rect;
+       int x;
+       int y;
+
+       for (y = 0; y < ibuf->y; y++) {
+               for (x = 0; x < ibuf->x; x++) {
+                       unsigned char r = *p++;
+                       unsigned char g = *p++;
+                       unsigned char b = *p++;
+                       unsigned char a = *p++;
+
+                       if (r >= limit || g >= limit || b >= limit) {
+                               if (r == limit 
+                                   || g == limit 
+                                   || b == limit 
+                                   || (((x + y) & 0x08) != 0)) {
+                                       r = 255 - r;
+                                       g = 255 - g;
+                                       b = 255 - b;
+                               }
+                       }
+                       *o++ = r;
+                       *o++ = g;
+                       *o++ = b;
+                       *o++ = a;
+               }
+       }
+}
+
+#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.99f*val))
+
+static void draw_zebra_float(struct ImBuf * src,struct ImBuf * ibuf,float perc)
+{
+       float limit = perc / 100.0;
+       float * p = src->rect_float;
+       unsigned char * o = (unsigned char*) ibuf->rect;
+       int x;
+       int y;
+
+       for (y = 0; y < ibuf->y; y++) {
+               for (x = 0; x < ibuf->x; x++) {
+                       float r = *p++;
+                       float g = *p++;
+                       float b = *p++;
+                       float a = *p++;
+
+                       if (r >= limit || g >= limit || b >= limit) {
+                               if (r == limit 
+                                   || g == limit 
+                                   || b == limit 
+                                   || (((x + y) & 0x08) != 0)) {
+                                       r = 1.0 - r;
+                                       g = 1.0 - g;
+                                       b = 1.0 - b;
+                               }
+                       }
+
+                       *o++ = FTOCHAR(r);
+                       *o++ = FTOCHAR(g);
+                       *o++ = FTOCHAR(b);
+                       *o++ = FTOCHAR(a);
+               }
+       }
+}
+
+struct ImBuf * make_zebra_view_from_ibuf(struct ImBuf * src, float perc)
+{
+       struct ImBuf * ibuf = IMB_allocImBuf(src->x, src->y, 32, IB_rect, 0);
+
+       if (src->rect_float) {
+               draw_zebra_float(src, ibuf, perc);
+       } else {
+               draw_zebra_byte(src, ibuf, perc);
+       }
+       return ibuf;
+}
+
+static void draw_histogram_marker(struct ImBuf * ibuf, int x)
+{
+       unsigned char * p = (unsigned char*) ibuf->rect;
+       int barh = ibuf->y * 0.1;
+       int i;
+
+       p += 4 * (x + ibuf->x * (ibuf->y - barh + 1));
+
+       for (i = 0; i < barh-1; i++) {
+               p[0] = p[1] = p[2] = 255;
+               p += ibuf->x * 4;
+       }
+}
+
+static void draw_histogram_bar(struct ImBuf * ibuf, int x,float val, int col)
+{
+       unsigned char * p = (unsigned char*) ibuf->rect;
+       int barh = ibuf->y * val * 0.9;
+       int i;
+
+       p += 4 * (x + ibuf->x);
+
+       for (i = 0; i < barh; i++) {
+               p[col] = 255;
+               p += ibuf->x * 4;
+       }
+}
+
+static struct ImBuf *make_histogram_view_from_ibuf_byte(
+       struct ImBuf * ibuf)
+{
+       struct ImBuf * rval = IMB_allocImBuf(515, 128, 32, IB_rect, 0);
+       int n,c,x,y;
+       unsigned char* src = (unsigned char*) ibuf->rect;
+
+       unsigned int bins[3][256];
+
+       memset(bins, 0, 3 * 256* sizeof(unsigned int));
+
+       for (y = 0; y < ibuf->y; y++) {
+               for (x = 0; x < ibuf->x; x++) {
+                       bins[0][*src++]++;
+                       bins[1][*src++]++;
+                       bins[2][*src++]++;
+                       src++;
+               }
+       }
+
+       n = 0;
+       for (c = 0; c < 3; c++) {
+               for (x = 0; x < 256; x++) {
+                       if (bins[c][x] > n) {
+                               n = bins[c][x];
+                       }
+               }
+       }
+
+       for (c = 0; c < 3; c++) {
+               for (x = 0; x < 256; x++) {
+                       draw_histogram_bar(rval, x*2+1, 
+                                          ((float) bins[c][x])/n, c);
+                       draw_histogram_bar(rval, x*2+2, 
+                                          ((float) bins[c][x])/n, c);
+               }
+       }
+
+       wform_put_border((unsigned char*) rval->rect, rval->x, rval->y);
+       
+       return rval;
+}
+
+static int get_bin_float(float f)
+{
+       if (f < -0.25) {
+               f = -0.25;
+       } else if (f > 1.25) {
+               f = 1.25;
+       }
+
+       return (int) (((f + 0.25) / 1.5) * 512);
+}
+
+static struct ImBuf *make_histogram_view_from_ibuf_float(
+       struct ImBuf * ibuf)
+{
+       struct ImBuf * rval = IMB_allocImBuf(515, 128, 32, IB_rect, 0);
+       int n,c,x,y;
+       float* src = ibuf->rect_float;
+
+       unsigned int bins[3][512];
+
+       memset(bins, 0, 3 * 256* sizeof(unsigned int));
+
+       for (y = 0; y < ibuf->y; y++) {
+               for (x = 0; x < ibuf->x; x++) {
+                       bins[0][get_bin_float(*src++)]++;
+                       bins[1][get_bin_float(*src++)]++;
+                       bins[2][get_bin_float(*src++)]++;
+                       src++;
+               }
+       }
+
+       draw_histogram_marker(rval, get_bin_float(0.0));
+       draw_histogram_marker(rval, get_bin_float(1.0));
+
+       n = 0;
+       for (c = 0; c < 3; c++) {
+               for (x = 0; x < 512; x++) {
+                       if (bins[c][x] > n) {
+                               n = bins[c][x];
+                       }
+               }
+       }
+       for (c = 0; c < 3; c++) {
+               for (x = 0; x < 512; x++) {
+                       draw_histogram_bar(rval, x+1, (float) bins[c][x]/n, c);
+               }
+       }
+
+       wform_put_border((unsigned char*) rval->rect, rval->x, rval->y);
+       
+       return rval;
+}
+
+struct ImBuf *make_histogram_view_from_ibuf(struct ImBuf * ibuf)
+{
+       if (ibuf->rect_float) {
+               return make_histogram_view_from_ibuf_float(ibuf);
+       } else {
+               return make_histogram_view_from_ibuf_byte(ibuf);
+       }
+}
+
 static void vectorscope_put_cross(unsigned char r, unsigned char g, 
                                  unsigned char b, 
                                  char * tgt, int w, int h, int size)