simplify thumbnail reading and remove some warnings
[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[12];
44         int bhead[24/sizeof(int)]; /* max size on 64bit */
45         char endian, pointer_size;
46         char endian_switch;
47         int sizeof_bhead ;
48
49         /* read the blend file header */
50         if(gzread(gzfile, buf, 12) != 12)
51                 return NULL;
52         if(strncmp(buf, "BLENDER", 7))
53                 return NULL;
54
55         if(buf[7]=='-')
56                 pointer_size= 8;
57         else if(buf[7]=='_')
58                 pointer_size= 4;
59         else
60                 return NULL;
61
62          sizeof_bhead = 16 + pointer_size;
63
64         if(buf[8]=='V')
65                 endian= B_ENDIAN; /* big: PPC */
66         else if(buf[8]=='v')
67                 endian= L_ENDIAN; /* little: x86 */
68         else
69                 return NULL;
70
71         endian_switch = ((ENDIAN_ORDER != endian)) ? 1 : 0;
72
73         while(gzread(gzfile, bhead, sizeof_bhead) == sizeof_bhead) {
74                 if(endian_switch)
75                         SWITCH_INT(bhead[1]); /* length */
76
77                 if (bhead[0]==REND) {
78                         gzseek(gzfile, bhead[1], SEEK_CUR); /* skip to the next */
79                 }
80                 else {
81                         break;
82                 }
83         }
84
85         /* using 'TEST' since new names segfault when loading in old blenders */
86         if(bhead[0] == TEST) {
87                 ImBuf *img= NULL;
88                 int size[2];
89
90                 if(gzread(gzfile, size, sizeof(size)) != sizeof(size))
91                         return NULL;
92
93                 if(endian_switch) {
94                         SWITCH_INT(size[0]);
95                         SWITCH_INT(size[1]);
96                 }
97                 /* length */
98                 bhead[1] -= sizeof(int) * 2;
99
100                 /* inconsistant image size, quit early */
101                 if(bhead[1] != size[0] * size[1] * sizeof(int))
102                         return NULL;
103         
104                 /* finally malloc and read the data */
105                 img= IMB_allocImBuf(size[0], size[1], 32, IB_rect | IB_metadata, 0);
106         
107                 if(gzread(gzfile, img->rect, bhead[1]) != bhead[1]) {
108                         IMB_freeImBuf(img);
109                         img= NULL;
110                 }
111         
112                 return img;
113         }
114         
115         return NULL;
116 }
117
118 ImBuf *IMB_loadblend_thumb(const char *path)
119 {
120         gzFile gzfile;
121
122         /* not necessarily a gzip */
123         gzfile = gzopen(path, "rb");
124
125         if (NULL == gzfile ) {
126                 return NULL;
127         }
128         else {
129                 ImBuf *img= loadblend_thumb(gzfile);
130
131                 /* read ok! */
132                 gzclose(gzfile);
133
134                 return img;
135         }
136 }
137
138 /* add a fake passepartout overlay to a byte buffer, use for blend file thumbnails */
139 #define MARGIN 2
140
141 void IMB_overlayblend_thumb(unsigned int *thumb, int width, int height, float aspect)
142 {
143         unsigned char *px= (unsigned char *)thumb;
144         int margin_l = MARGIN;
145         int margin_b = MARGIN;
146         int margin_r = width - MARGIN;
147         int margin_t = height - MARGIN;
148
149         if(aspect < 1.0f) {
150                 margin_l= (int)((width - ((float)width * aspect)) / 2.0f);
151                 margin_l += MARGIN;
152                 CLAMP(margin_l, MARGIN, (width/2));
153                 margin_r = width - margin_l;
154         }
155         else if (aspect > 1.0f) {
156                 margin_b= (int)((height - ((float)height / aspect)) / 2.0f);
157                 margin_b += MARGIN;
158                 CLAMP(margin_b, MARGIN, (height/2));
159                 margin_t = height - margin_b;
160         }
161
162         {       
163                 int x, y;
164                 int hline, vline;
165                 int stride_x= (margin_r - margin_l) - 2;
166                 
167                 for(y=0; y < height; y++) {
168                         for(x=0; x < width; x++, px+=4) {
169                                 if((x > margin_l && x < margin_r) && (y > margin_b && y < margin_t)) {
170                                         /* interior. skip */
171                                         x  += stride_x;
172                                         px += stride_x * 4;
173                                 } else if(      (hline=(((x == margin_l || x == margin_r)) && y >= margin_b && y <= margin_t)) ||
174                                                         (vline=(((y == margin_b || y == margin_t)) && x >= margin_l && x <= margin_r))
175                                 ) {
176                                         /* dashed line */
177                                         if((hline && y % 2) || (vline && x % 2)) {
178                                                 px[0]= px[1]= px[2]= 0;
179                                                 px[3] = 255;
180                                         }
181                                 }
182                                 else {
183                                         /* outside, fill in alpha, like passepartout */
184                                         px[0] *= 0.5f;
185                                         px[1] *= 0.5f;
186                                         px[2] *= 0.5f;
187                                         px[3] = (px[3] * 0.5f) + 96;
188                                 }
189                         }
190                 }
191         }
192 }