sequencer outline, credits on a black background wasnt easy to see.
[blender.git] / source / blender / imbuf / intern / thumbs_blend.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Campbell Barton.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <string.h>
26
27 #include "zlib.h"
28
29 #include "BKE_utildefines.h"
30 #include "BKE_global.h"
31
32 #include "IMB_imbuf_types.h"
33 #include "IMB_imbuf.h"
34 #include "IMB_thumbs.h"
35
36 #include "MEM_guardedalloc.h"
37
38 /* extracts the thumbnail from between the 'REND' and the 'GLOB'
39  * chunks of the header, dont use typical blend loader because its too slow */
40
41 static ImBuf *loadblend_thumb(gzFile gzfile)
42 {
43         char buf[8];
44         int code= 0;
45         char endian, pointer_size;
46         char endian_switch;
47         int len, im_len, x, y;
48         ImBuf *img= NULL;
49
50
51         /* read the blend file header */
52         if(gzread(gzfile, buf, 8) != 8)
53                 return NULL;
54         if(strncmp(buf, "BLENDER", 7))
55                 return NULL;
56
57         if(buf[7]=='-')
58                 pointer_size= 8;
59         else if(buf[7]=='_')
60                 pointer_size= 4;
61         else
62                 return NULL;
63
64         /* read the next 4 bytes, only need the first char, ignore the version */
65         /* endian and vertsion (ignored) */
66         if(gzread(gzfile, buf, 4) != 4)
67                 return NULL;
68
69         if(buf[0]=='V')
70                 endian= B_ENDIAN; /* big: PPC */
71         else if(buf[0]=='v')
72                 endian= L_ENDIAN; /* little: x86 */
73         else
74                 return NULL;
75
76         while(gzread(gzfile, &code, sizeof(int)) == sizeof(int)) {
77                 endian_switch = ((ENDIAN_ORDER != endian)) ? 1 : 0;
78
79                 if(gzread(gzfile, buf, sizeof(int)) != sizeof(int))
80                         return NULL;
81
82                 len = *( (int *)((void *)buf) );
83
84                 if(endian_switch)
85                         SWITCH_INT(len);
86
87                 /* finally read the rest of the bhead struct, pointer and 2 ints */
88                 if(gzread(gzfile, buf, pointer_size) != pointer_size)
89                         return NULL;
90                 if(gzread(gzfile, buf, sizeof(int) * 2) != sizeof(int) * 2)
91                         return NULL;
92
93                 /* we dont actually care whats in the bhead */
94                 if (code==REND) {
95                         gzseek(gzfile, len, SEEK_CUR); /* skip to the next */
96                 }
97                 else {
98                         break;
99                 }
100         }
101
102         /* using 'TEST' since new names segfault when loading in old blenders */
103         if(code != TEST)
104                 return NULL;
105
106         if(gzread(gzfile, &x, sizeof(int)) != sizeof(int))
107                 return NULL;
108         if(gzread(gzfile, &y, sizeof(int)) != sizeof(int))
109                 return NULL;
110
111         len -= sizeof(int) * 2;
112
113         if(endian_switch) {
114                 SWITCH_INT(x);
115                 SWITCH_INT(y);
116         }
117
118         /* inconsistant image size, quit early */
119         im_len = x * y * sizeof(int);
120         if(im_len != len)
121                 return NULL;
122
123         /* finally malloc and read the data */
124         img= IMB_allocImBuf(x, y, 32, IB_rect | IB_metadata, 0);
125
126         if(gzread(gzfile, img->rect, len) != len) {
127                 IMB_freeImBuf(img);
128                 img= NULL;
129         }
130
131         return img;
132 }
133
134 ImBuf *IMB_loadblend_thumb(const char *path)
135 {
136         gzFile gzfile;
137
138         /* not necessarily a gzip */
139         gzfile = gzopen(path, "rb");
140
141         if (NULL == gzfile ) {
142                 return NULL;
143         }
144         else {
145                 ImBuf *img= loadblend_thumb(gzfile);
146
147                 /* read ok! */
148                 gzclose(gzfile);
149
150                 return img;
151         }
152 }
153
154 /* add a fake passepartout overlay to a byte buffer, use for blend file thumbnails */
155 #define MARGIN 2
156
157 void IMB_overlayblend_thumb(unsigned int *thumb, int width, int height, float aspect)
158 {
159         unsigned char *px= (unsigned char *)thumb;
160         int margin_l = MARGIN;
161         int margin_b = MARGIN;
162         int margin_r = width - MARGIN;
163         int margin_t = height - MARGIN;
164
165         if(aspect < 1.0f) {
166                 margin_l= (int)((width - ((float)width * aspect)) / 2.0f);
167                 margin_l += MARGIN;
168                 CLAMP(margin_l, MARGIN, (width/2));
169                 margin_r = width - margin_l;
170         }
171         else if (aspect > 1.0f) {
172                 margin_b= (int)((height - ((float)height / aspect)) / 2.0f);
173                 margin_b += MARGIN;
174                 CLAMP(margin_b, MARGIN, (height/2));
175                 margin_t = height - margin_b;
176         }
177
178         {       
179                 int x, y;
180                 int hline, vline;
181                 int stride_x= (margin_r - margin_l) - 2;
182                 
183                 for(y=0; y < height; y++) {
184                         for(x=0; x < width; x++, px+=4) {
185                                 if((x > margin_l && x < margin_r) && (y > margin_b && y < margin_t)) {
186                                         /* interior. skip */
187                                         x  += stride_x;
188                                         px += stride_x * 4;
189                                 } else if(      (hline=(((x == margin_l || x == margin_r)) && y >= margin_b && y <= margin_t)) ||
190                                                         (vline=(((y == margin_b || y == margin_t)) && x >= margin_l && x <= margin_r))
191                                 ) {
192                                         /* dashed line */
193                                         if((hline && y % 2) || (vline && x % 2)) {
194                                                 px[0]= px[1]= px[2]= 0;
195                                                 px[3] = 255;
196                                         }
197                                 }
198                                 else {
199                                         /* outside, fill in alpha, like passepartout */
200                                         px[0] *= 0.5f;
201                                         px[1] *= 0.5f;
202                                         px[2] *= 0.5f;
203                                         px[3] = (px[3] * 0.5f) + 96;
204                                 }
205                         }
206                 }
207         }
208 }