1<?php
2/**
3 * MyBB 1.8
4 * Copyright 2014 MyBB Group, All Rights Reserved
5 *
6 * Website: http://www.mybb.com
7 * License: http://www.mybb.com/about/license
8 *
9 */
10
11/**
12 * Generates a thumbnail based on specified dimensions (supports png, jpg, and gif)
13 *
14 * @param string $file the full path to the original image
15 * @param string $path the directory path to where to save the new image
16 * @param string $filename the filename to save the new image as
17 * @param integer $maxheight maximum hight dimension
18 * @param integer $maxwidth maximum width dimension
19 * @return array thumbnail on success, error code 4 on failure
20 */
21function generate_thumbnail($file, $path, $filename, $maxheight, $maxwidth)
22{
23	$thumb = array();
24
25	if(!function_exists("imagecreate"))
26	{
27		$thumb['code'] = 3;
28		return $thumb;
29	}
30
31	$imgdesc = getimagesize($file);
32	$imgwidth = $imgdesc[0];
33	$imgheight = $imgdesc[1];
34	$imgtype = $imgdesc[2];
35	$imgattr = $imgdesc[3];
36	$imgbits = isset($imgdesc['bits']) ? $imgdesc['bits'] : null;
37	$imgchan = isset($imgdesc['channels']) ? $imgdesc['channels'] : null;
38
39	if($imgwidth == 0 || $imgheight == 0)
40	{
41		$thumb['code'] = 3;
42		return $thumb;
43	}
44	if(($imgwidth >= $maxwidth) || ($imgheight >= $maxheight))
45	{
46		check_thumbnail_memory($imgwidth, $imgheight, $imgtype, $imgbits, $imgchan);
47
48		if($imgtype == 3)
49		{
50			if(@function_exists("imagecreatefrompng"))
51			{
52				$im = @imagecreatefrompng($file);
53			}
54		}
55		elseif($imgtype == 2)
56		{
57			if(@function_exists("imagecreatefromjpeg"))
58			{
59				$im = @imagecreatefromjpeg($file);
60			}
61		}
62		elseif($imgtype == 1)
63		{
64			if(@function_exists("imagecreatefromgif"))
65			{
66				$im = @imagecreatefromgif($file);
67			}
68		}
69		else
70		{
71			$thumb['code'] = 3;
72			return $thumb;
73		}
74		if(!$im)
75		{
76			$thumb['code'] = 3;
77			return $thumb;
78		}
79		$scale = scale_image($imgwidth, $imgheight, $maxwidth, $maxheight);
80		$thumbwidth = $scale['width'];
81		$thumbheight = $scale['height'];
82		$thumbim = @imagecreatetruecolor($thumbwidth, $thumbheight);
83
84		if(!$thumbim)
85		{
86			$thumbim = @imagecreate($thumbwidth, $thumbheight);
87			$resized = true;
88		}
89
90		// Attempt to preserve the transparency if there is any
91		if($imgtype == 3)
92		{
93			// A PNG!
94			imagealphablending($thumbim, false);
95			imagefill($thumbim, 0, 0, imagecolorallocatealpha($thumbim, 0, 0, 0, 127));
96
97			// Save Alpha...
98			imagesavealpha($thumbim, true);
99		}
100		elseif($imgtype == 1)
101		{
102			// Transparent GIF?
103			$trans_color = imagecolortransparent($im);
104			if($trans_color >= 0 && $trans_color < imagecolorstotal($im))
105			{
106				$trans = imagecolorsforindex($im, $trans_color);
107				$new_trans_color = imagecolorallocate($thumbim, $trans['red'], $trans['blue'], $trans['green']);
108				imagefill($thumbim, 0, 0, $new_trans_color);
109				imagecolortransparent($thumbim, $new_trans_color);
110			}
111		}
112
113		if(!isset($resized))
114		{
115			@imagecopyresampled($thumbim, $im, 0, 0, 0, 0, $thumbwidth, $thumbheight, $imgwidth, $imgheight);
116		}
117		else
118		{
119			@imagecopyresized($thumbim, $im, 0, 0, 0, 0, $thumbwidth, $thumbheight, $imgwidth, $imgheight);
120		}
121		@imagedestroy($im);
122		if(!function_exists("imagegif") && $imgtype == 1)
123		{
124			$filename = str_replace(".gif", ".jpg", $filename);
125		}
126		switch($imgtype)
127		{
128			case 1:
129				if(function_exists("imagegif"))
130				{
131					@imagegif($thumbim, $path."/".$filename);
132				}
133				else
134				{
135					@imagejpeg($thumbim, $path."/".$filename);
136				}
137				break;
138			case 2:
139				@imagejpeg($thumbim, $path."/".$filename);
140				break;
141			case 3:
142				@imagepng($thumbim, $path."/".$filename);
143				break;
144		}
145		@my_chmod($path."/".$filename, '0644');
146		@imagedestroy($thumbim);
147		$thumb['code'] = 1;
148		$thumb['filename'] = $filename;
149		return $thumb;
150	}
151	else
152	{
153		return array("code" => 4);
154	}
155}
156
157/**
158 * Attempts to allocate enough memory to generate the thumbnail
159 *
160 * @param integer $width width dimension
161 * @param integer $height height dimension
162 * @param string $type one of the IMAGETYPE_XXX constants indicating the type of the image
163 * @param string $bitdepth the bits area the number of bits for each color
164 * @param string $channels the channels - 3 for RGB pictures and 4 for CMYK pictures
165 * @return bool
166 */
167function check_thumbnail_memory($width, $height, $type, $bitdepth, $channels)
168{
169	if(!function_exists("memory_get_usage"))
170	{
171		return false;
172	}
173
174	$memory_limit = @ini_get("memory_limit");
175	if(!$memory_limit || $memory_limit == -1)
176	{
177		return false;
178	}
179
180	$limit = preg_match("#^([0-9]+)\s?([kmg])b?$#i", trim(my_strtolower($memory_limit)), $matches);
181	$memory_limit = (int)$memory_limit;
182	if($matches[1] && $matches[2])
183	{
184		switch($matches[2])
185		{
186			case "k":
187				$memory_limit = $matches[1] * 1024;
188				break;
189			case "m":
190				$memory_limit = $matches[1] * 1048576;
191				break;
192			case "g":
193				$memory_limit = $matches[1] * 1073741824;
194		}
195	}
196	$current_usage = memory_get_usage();
197	$free_memory = $memory_limit - $current_usage;
198
199	$thumbnail_memory = round(($width * $height * $bitdepth * $channels / 8) * 5);
200	$thumbnail_memory += 2097152;
201
202	if($thumbnail_memory > $free_memory)
203	{
204		if($matches[1] && $matches[2])
205		{
206			switch($matches[2])
207			{
208				case "k":
209					$memory_limit = ceil((($memory_limit+$thumbnail_memory) / 1024))."K";
210					break;
211				case "m":
212					$memory_limit = ceil((($memory_limit+$thumbnail_memory) / 1048576))."M";
213					break;
214				case "g":
215					$memory_limit = ceil((($memory_limit+$thumbnail_memory) / 1073741824))."G";
216			}
217		}
218
219		@ini_set("memory_limit", $memory_limit);
220	}
221
222	return true;
223}
224
225/**
226 * Figures out the correct dimensions to use
227 *
228 * @param integer $width current width dimension
229 * @param integer $height current height dimension
230 * @param integer $maxwidth max width dimension
231 * @param integer $maxheight max height dimension
232 * @return array correct height & width
233 */
234function scale_image($width, $height, $maxwidth, $maxheight)
235{
236	$width = (int)$width;
237	$height = (int)$height;
238
239	if(!$width) $width = $maxwidth;
240	if(!$height) $height = $maxheight;
241
242	$newwidth = $width;
243	$newheight = $height;
244
245	if($width > $maxwidth)
246	{
247		$newwidth = $maxwidth;
248		$newheight = ceil(($height*(($maxwidth*100)/$width))/100);
249		$height = $newheight;
250		$width = $newwidth;
251	}
252	if($height > $maxheight)
253	{
254		$newheight = $maxheight;
255		$newwidth = ceil(($width*(($maxheight*100)/$height))/100);
256	}
257	$ret['width'] = $newwidth;
258	$ret['height'] = $newheight;
259	return $ret;
260}
261