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