1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: class Meme_generator
15: {
16: public $config;
17:
18: public function __construct()
19: {
20: $this->clear();
21: }
22:
23: 24: 25: 26: 27: 28: 29:
30: public function load_config ($config)
31: {
32: $this->config = $config;
33: }
34: 35: 36: 37:
38: public function set_image ( $image_path )
39: {
40: $this->config['meme_image_path'] = $image_path;
41: }
42:
43: 44: 45: 46:
47: public function set_top_text( $txt )
48: {
49: $this->config['meme_top_text'] = $txt;
50: }
51:
52: 53: 54: 55:
56: public function set_bottom_text( $txt )
57: {
58: $this->config['meme_bottom_text'] = $txt;
59: }
60:
61: 62: 63: 64:
65: public function set_font ( $file )
66: {
67: $this->config['meme_font'] = $file ;
68: }
69:
70: 71: 72: 73:
74: public function set_output_dir( $path )
75: {
76: $this->config['meme_output_dir'] = $path;
77: }
78:
79: 80: 81: 82: 83:
84: public function set_font_ratio( $ratio )
85: {
86: $this->config['meme_font_to_image_ratio'] = $ratio;
87: }
88: 89: 90:
91: public function set_quality( $q )
92: {
93: $this->config['meme_quality'] = $q;
94: }
95:
96: 97: 98: 99: 100:
101: public function set_margins_ratio( $ratio )
102: {
103: $this->config['meme_margins_to_image_ratio'] = $ratio;
104: }
105:
106:
107: 108: 109: 110:
111: public function set_watermark( $path )
112: {
113: $this->config['meme_watermark_file'] = $path;
114: }
115:
116: 117: 118: 119:
120: public function set_watermark_margins( $margins = 10 )
121: {
122: $this->config['meme_watermark_margins'] = $margins;
123: }
124:
125: 126: 127: 128:
129: public function set_watemark_opacity( $opacity = 50)
130: {
131: $this->config['meme_watermark_opacity'] = $opacity;
132: }
133:
134: 135: 136:
137: public function clear()
138: {
139: $this->config['meme_image_path'] = null;
140: $this->config['meme_top_text'] = '';
141: $this->config['meme_bottom_text'] = '';
142: $this->config['meme_watermark_file'] = null;
143: $this->config['meme_font'] = './fonts/DejaVuSansMono-Bold.ttf';
144: $this->config['meme_output_dir'] = './';
145: $this->config['meme_font_to_image_ratio'] = 0.04;
146: $this->config['meme_margins_to_image_ratio'] = 0.02;
147: $this->config['meme_quality'] = 90;
148: $this->config['meme_watermark_margins'] = 10;
149: $this->config['meme_watermark_opacity'] = 50;
150: $this->config['meme_prefix'] = 'meme_';
151: $this->config['debug'] = array();
152: }
153:
154: public function debug()
155: {
156: return $this->config['debug'];
157: }
158:
159: 160: 161: 162:
163: public function generate()
164: {
165: if ( ! isset( $this->config['meme_image_path'] ) || ! strlen( $this->config['meme_image_path'] ) ) {
166: die ( 'Meme_generator Class ERROR : Trying to generate meme without image file specified');
167: }
168: $tmp_sizes = getimagesize( $this->config['meme_image_path'] );
169: $image_width = $tmp_sizes[0];
170: $image_height= $tmp_sizes[1];
171: $this->config['debug'] = array_merge ($this->config['debug'], $this->config);
172: $this->config['debug'] = array_merge ($this->config['debug'], $tmp_sizes );
173:
174: $text1 = preg_replace('/\s\s+/', ' ', $this->config['meme_top_text'] );
175: $text2 = preg_replace('/\s\s+/', ' ', $this->config['meme_bottom_text'] );
176:
177: $font = $this->config['meme_font'];
178: $font_size = round($this->config['meme_font_to_image_ratio'] * $image_width );
179: $margin = round($this->config['meme_margins_to_image_ratio'] * $image_width );
180:
181: $text1_params = $this->get_text_params($text1,$image_width,$margin,$font,$font_size);
182: $text2_params = $this->get_text_params($text2,$image_width,$margin,$font,$font_size);
183:
184: $this->config['debug']['font_size'] = $font_size;
185: $this->config['debug']['margin'] = $margin;
186: $this->config['debug']['text1_params'] = $text1_params;
187: $this->config['debug']['text2_params'] = $text2_params;
188:
189: $im = @imagecreatefromstring(file_get_contents( $this->config['meme_image_path'] ));
190: $white = imagecolorallocate($im, 255, 255, 255);
191: $black = imagecolorallocate($im, 0, 0, 0);
192:
193: if ( isset ( $this->config['meme_watermark_file'] ) && strlen( $this->config['meme_watermark_file'] ) ) {
194:
195:
196: $overlay_gd_image = @imagecreatefromstring(file_get_contents ($this->config['meme_watermark_file'] ) );
197: $overlay_width = imagesx($overlay_gd_image);
198: $overlay_height = imagesy($overlay_gd_image);
199:
200: $merge_result = imagecopymerge(
201: $im,
202: $overlay_gd_image,
203: $image_width - $overlay_width - $this->config['meme_watermark_margins'] ,
204: $image_height - $overlay_height - $this->config['meme_watermark_margins'],
205: 0,
206: 0,
207: $overlay_width,
208: $overlay_height,
209: $this->config['meme_watermark_opacity']
210: );
211: $this->config['debug']['meme_watermark_file'] = $this->config['meme_watermark_file'];
212: $this->config['debug']['meme_watermark_margins'] = $this->config['meme_watermark_margins'];
213: $this->config['debug']['meme_watermark_opacity'] = $this->config['meme_watermark_opacity'];
214: imagedestroy($overlay_gd_image);
215: }
216:
217:
218: imagettftext($im, $font_size, 0,
219: $text1_params['centered_start'],
220: $font_size+$margin,
221: $black, $font, $text1_params['text']
222: );
223: imagettftext($im, $font_size, 0,
224: $text1_params['centered_start']-2,
225: $font_size+$margin-2,
226: $white, $font, $text1_params['text']
227: );
228:
229: imagettftext($im, $font_size, 0,
230: $text2_params['centered_start'] ,
231: $image_height-$text2_params['height']+$font_size+$margin,
232: $black, $font, $text2_params['text']
233: );
234: imagettftext($im, $font_size, 0,
235: $text2_params['centered_start']-2,
236: $image_height-$text2_params['height']+$font_size+$margin-2,
237: $white, $font, $text2_params['text']
238: );
239: $fname = $this->config['debug']['meme_recent_file_name']
240: = $this->config['meme_prefix'] . md5(serialize( $this->config )) .time() . '.jpg';
241: $cache_file_name = $this->config['meme_output_dir'] . $fname;
242: $this->config['debug']['cache_file_name'] = $cache_file_name;
243: imagejpeg($im, $cache_file_name, $this->config['meme_quality']);
244: imagedestroy($im);
245: return $fname;
246: }
247:
248: 249: 250:
251: private function get_text_params($text,$width,$margin,$font,$font_size)
252: {
253: $rv = array();
254: $text_a = explode(' ', $text);
255: $text_new = '';
256: foreach($text_a as $word){
257: $box = imagettfbbox($font_size, 0, $font, $text_new.' '.$word);
258: if($box[2] > $width - $margin*2){
259: $text_new .= "\n".$word;
260: } else {
261: $text_new .= " ".$word;
262: }
263: }
264:
265: $text_new = $this->align_center_img_txt($text_new);
266: $box = imagettfbbox($font_size, 0, $font, $text_new);
267: $rv['text'] = $text_new;
268: $rv['height'] = $box[1] + $font_size + $margin * 2;
269: $rv['centered_start'] = ceil(($width-$box[2]) / 2);
270: return $rv;
271: }
272:
273: 274: 275:
276: private function align_center_img_txt ($text_new)
277: {
278: $text_new = trim($text_new);
279: $text_a_tmp = explode("\n", $text_new);
280: $max_line_length1 = 0;
281: foreach($text_a_tmp as $line){
282: if ( mb_strlen($line) > $max_line_length1) $max_line_length1 = mb_strlen($line);
283: }
284: $text_new = '';
285: foreach($text_a_tmp as $line){
286: $text_new .= $this->mb_str_pad($line, $max_line_length1, ' ', STR_PAD_BOTH) . "\n";
287: }
288: return $text_new;
289: }
290:
291: private function mb_str_pad ($input, $pad_length, $pad_string, $pad_style, $encoding="UTF-8") {
292: return str_pad (
293: $input,
294: strlen($input)-mb_strlen($input,$encoding)+$pad_length, $pad_string, $pad_style
295: );
296: }
297:
298: }
299: