{"id":280,"date":"2016-08-31T23:34:42","date_gmt":"2016-09-01T03:34:42","guid":{"rendered":"http:\/\/halnesbitt.com\/blog\/?p=280"},"modified":"2016-09-01T00:28:11","modified_gmt":"2016-09-01T04:28:11","slug":"halthumb-a-quick-and-dirty-image-resizer-script-for-php-or-asp-net","status":"publish","type":"post","link":"https:\/\/halnesbitt.com\/blog\/2016\/08\/31\/halthumb-a-quick-and-dirty-image-resizer-script-for-php-or-asp-net\/","title":{"rendered":"HalThumb &#8211; A Quick and Dirty Image Resizer Script for PHP or ASP.NET"},"content":{"rendered":"<!--more-->\r\n\r\n<p>As a web developer, you are going to have to display images at different sizes. When I was young and stupid, I used to make different versions of the same photo in Photoshop and locate them all on the server using different paths. As I got older, I got lazier, so I just started resizing them as needed via CSS (or inline style via javascript). This of course led to distortion, which is when I discovered <a target=\"_blank\" href=\"https:\/\/www.binarymoon.co.uk\/projects\/timthumb\/\">TimThumb<\/a>, which made my life infinitely easier, as I could resize images on the fly using PHP. A brilliant script, but it had a few <a target=\"_blank\" href=\"https:\/\/www.binarymoon.co.uk\/2014\/09\/timthumb-end-life\/\">security issues<\/a>, and it also started getting a little too robust, which affected speed, so I decided to just create my own, with just the bare minimum for resizing, scaling and cropping. Use it for thumbnail generation, or to make your images just fit exactly.<\/p>\r\n\r\n<p>You can see it in action below:<\/p>\r\n\r\n<div class=\"field_holder\">\r\n<label>Width:<\/label>\r\n<input class=\"try\" id=\"tw\" type=\"text\" value=\"600\" \/>\r\n<\/div>\r\n<div class=\"field_holder\">\r\n<label>Height:<\/label>\r\n<input class=\"try\" id=\"th\" type=\"text\" value=\"400\" \/>\r\n<\/div>\r\n<div class=\"field_holder\">\r\n<label>Crop:<\/label>\r\n<select class=\"try\" id=\"tc\" style=\"display: block;\">\r\n<option value=\"portfolio\">portfolio<\/option>\r\n<option value=\"full\">full<\/option>\r\n<option value=\"\">none<\/option>\r\n<\/select>\r\n<\/div>\r\n\r\n<br style=\"clear:both;\" \/>\r\n\r\n<img decoding=\"async\" id=\"test_img\" src=\"\/scripts\/halthumb.php?src=\/images\/projects\/home-business-card.jpg&#038;w=600&#038;h=400&#038;crop=portfolio\" \/>\r\n\r\n<script type=\"text\/javascript\">\r\njQuery(document).ready(function() {\r\n\tjQuery(\".field_holder\").css({\"width\":\"30%\", \"padding\":\"10px\", \"float\":\"left\"});\r\n\tjQuery(\".field_holder input, .field_holder select\").change(function() {\r\n\t\tvar tw = jQuery(\"#tw\").val();\r\n\t\tvar th = jQuery(\"#th\").val();\r\n\t\tvar tc = jQuery(\"#tc\").val();\r\n\t\tif(isNaN(tw) || isNaN(th) || tw == \"\" || th == \"\") {\r\n\t\t\talert('Please enter a number for both width and height.');\r\n\t\t} else {\r\n\t\t\tvar new_src = \"\/scripts\/halthumb.php?src=\/images\/projects\/home-business-card.jpg&w=\" + tw + \"&h=\" + th + \"&crop=\" + tc;\r\n\t\t\tjQuery(\"#test_img\").attr(\"src\", new_src);\r\n\t\t\tjQuery(\"#generated_src\").html('&lt;img src=\"' + new_src.replace('\/scripts\/','') + '\" \/&gt;');\r\n\t\t}\r\n\t});\r\n});\r\n<\/script>\r\n\r\n<br style=\"clear:both;\" \/><br \/>\r\n\r\n<pre>\r\n<code id=\"generated_src\">\r\n&lt;img src=\"halthumb.php?src=\/images\/projects\/home-business-card.jpg&w=600&h=400&crop=portfolio\" \/&gt;\r\n<\/code>\r\n<\/pre>\r\n\r\n<p>Just set the script in your img src attribute, as above. The parameters to pass are:<\/p>\r\n<ul>\r\n<li>src = the local path to the image on your server<\/li>\r\n<li>w = the width, in pixels<\/li>\r\n<li>h = the height, in pixels<\/li>\r\n<li>crop (optional) = the type of crop. Use &#8216;portfolio&#8217; to crop and scale dynamically and exactly fit your w\/h. Use &#8216;full&#8217; to simply output the original image (will override the passed sizes). If nothing is passed, the image will just scale proportionately.<\/li>\r\n<\/ul>\r\n\r\n<p>You can copy the PHP or ASP.NET code below, or download both scripts as a <a href=\"\/blog\/wp-content\/uploads\/2016\/08\/halthumb.zip\">zip<\/a>.<\/p>\r\n\r\n<p>Here&#8217;s the PHP code:<\/p>\r\n\r\n<pre>\r\n<code>\r\n&lt;?php \r\n\r\n\/******************************************************************************\r\n-- HalThumb - a quick and dirty thumbnail script\r\n-- Parameters:\r\n-- src = the path to the image\r\n-- w = width of thumb, in pixels\r\n-- h = height of thumb, in pixels\r\n-- crop = type of crop. Options are portfolio or full\r\n-- http:\/\/www.halnesbitt.com\r\n******************************************************************************\/\r\n\r\n\t\/\/determine the path and parts\r\n\t$src = $_GET['src'];\r\n\t$path_parts = pathinfo($src);\r\n\t$ext = $path_parts['extension'];\r\n\t$file_name = $path_parts['filename'] . \".\" . $ext;\r\n\t$local_path = $_SERVER['DOCUMENT_ROOT'] . $src;\r\n\r\n\t\/\/set defaults\r\n\t$MAX_WIDTH = 100;\r\n\t$MAX_HEIGHT = 100;\r\n\t$MAX_WIDTH_LIMIT = 1200;\r\n\t$MAX_HEIGHT_LIMIT = 1200;\r\n\r\n\t\/\/get parameters from querystring\r\n\t$MAX_WIDTH = grabParam('w');\r\n\t$MAX_HEIGHT = grabParam('h');\r\n\t$CROP_TYPE = grabParam('crop');\r\n\r\n\r\n\t\/\/setting limits so people can't just blow up thumbnails\r\n\tif ($MAX_WIDTH > $MAX_WIDTH_LIMIT) {\r\n\t\t$MAX_WIDTH = $MAX_WIDTH_LIMIT;\r\n\t}\r\n\tif ($MAX_HEIGHT > $MAX_HEIGHT_LIMIT) {\r\n\t\t$MAX_HEIGHT = $MAX_HEIGHT_LIMIT;\r\n\t}\r\n\r\n\t\/\/get the photo into data form\r\n\tswitch ($ext) {\r\n\t\tcase \"jpg\":\r\n\t\t\t$mime_type = \"image\/jpeg\";\r\n         \t\t$photo = imagecreatefromjpeg($local_path);\r\n         \t\tbreak;\r\n\r\n\t\tcase \"png\":\r\n\t\t\t$mime_type = \"image\/png\";\r\n         \t\t$photo = imagecreatefrompng($local_path);\r\n         \t\tbreak;\r\n\r\n\t\tcase \"gif\":\r\n\t\t\t$mime_type = \"image\/gif\";\r\n         \t\t$photo = imagecreatefromgif($local_path);\r\n         \t\tbreak;\r\n\t}\r\n\r\n\t\/\/getting dimensions of real photo\r\n\t$old_width = imagesx($photo);\r\n\t$old_height = imagesy($photo);\r\n\r\n\t\/\/set measurements for the crop and scale\r\n\tswitch ($CROP_TYPE) {\r\n\r\n\t\tcase \"portfolio\":\r\n\t\t\t\/\/crops and resizes based on passed sizes - 600 x 400\r\n\t\t\t$thumb_width = $MAX_WIDTH;\r\n\t\t\t$thumb_height = $MAX_HEIGHT;\r\n\r\n\t\t\t$original_aspect = $old_width \/ $old_height;\r\n\t\t\t$thumb_aspect = $thumb_width \/ $thumb_height;\r\n\r\n\t\t\tif($original_aspect >= $thumb_aspect) {   \r\n\t\t\t\t\/\/ If image is wider than thumbnail (in aspect ratio sense)   \r\n\t\t\t\t$new_height = $thumb_height;   \r\n\t\t\t\t$new_width = $old_width \/ ($old_height \/ $thumb_height);\r\n\t\t\t} else {   \r\n\t\t\t\t\/\/ If the thumbnail is wider than the image   \r\n\t\t\t\t$new_width = $thumb_width;   \r\n\t\t\t\t$new_height = $old_height \/ ($old_width \/ $thumb_width);\r\n\t\t\t}\r\n\r\n\t\t\t$src_x = ($new_width - $thumb_width) \/ 2;\r\n\t\t\t$src_y = ($new_height - $thumb_height) \/ 2;\r\n\t\t\tbreak;\r\n\t\t\r\n\t\tcase \"full\":\r\n\t\t\t\/\/show the full image at its full, original size\r\n\t\t\t$new_width = $old_width;\r\n\t\t\t$new_height = $old_height;\r\n\t\t\t$thumb_width = $old_width;\r\n\t\t\t$thumb_height = $old_height;\r\n\t\t\t$src_x = 0;\r\n\t\t\t$src_y = 0;\r\n\t\t\tbreak;\r\n\r\n\t\tdefault:\r\n\t\t\t\/\/true scaled\r\n\t\t\t$scale = min($MAX_WIDTH\/$old_width, $MAX_HEIGHT\/$old_height);\r\n\t\t\t$new_width = floor($scale*$old_width);\r\n\t\t\t$new_height = floor($scale*$old_height);\r\n\t\t\t$thumb_width = $new_width;\r\n\t\t\t$thumb_height = $new_height;\r\n\t\t\t$src_x = 0;\r\n\t\t\t$src_y = 0;\r\n\t\t\tbreak;\r\n\r\n\t}\r\n\r\n\r\n\t\/\/create the new photo and assign the data\r\n\t$tmp_img = imagecreatetruecolor($thumb_width, $thumb_height);\r\n\r\n\t\/\/handle transparency\r\n\tswitch ($ext) {\r\n\t\tcase \"png\":\r\n\t\t\/\/ integer representation of the color black (rgb: 0,0,0)\r\n\t\t$background = imagecolorallocate($tmp_img, 0, 0, 0);\r\n\t\t\/\/ removing the black from the placeholder\r\n\t\timagecolortransparent($tmp_img, $background);\r\n\r\n\t\t\/\/ turning off alpha blending (to ensure alpha channel information is preserved, rather than removed (blending with the rest of the image in the form of black))\r\n\t\timagealphablending($tmp_img, false);\r\n\r\n\t\t\/\/ turning on alpha channel information saving (to ensure the full range of transparency is preserved)\r\n\t\timagesavealpha($tmp_img, true);\r\n\t\tbreak;\r\n\r\n\tcase \"gif\":\r\n\t\t\/\/ integer representation of the color black (rgb: 0,0,0)\r\n\t\t$background = imagecolorallocate($tmp_img, 0, 0, 0);\r\n\t\t\/\/ removing the black from the placeholder\r\n\t\timagecolortransparent($tmp_img, $background);\r\n\t\tbreak;\r\n\t}\r\n\r\n\t\/\/do it, doug\r\n\timagecopyresampled($tmp_img, $photo, 0, 0, $src_x, $src_y, $new_width, $new_height, $old_width, $old_height);\r\n \t$photo = $tmp_img;        \r\n \r\n\t\/\/set all of the headers\r\n\theader(\"Cache-Control: private, max-age=10800, pre-check=10800\");\r\n\theader(\"Pragma: private\");\r\n\theader(\"Expires: \" . date(DATE_RFC822,strtotime(\" 2 day\")));\r\n\r\n\t\/\/commenting out size - was fucking up and making the browser hang, for some reason\r\n\t\/\/header(\"Content-length: $size\");\r\n\theader(\"Content-type: $mime_type\");\r\n\theader(\"Content-Disposition: inline; filename=$file_name\");\r\n\r\n\t\/\/output based on type\r\n\tswitch ($ext) {\r\n\t\tcase \"png\":\r\n\t\t\timagepng($photo);\r\n         \t\tbreak;\r\n\r\n\t\tcase \"gif\":\r\n\t\t\timagegif($photo);\r\n         \t\tbreak;\r\n\r\n\t\tdefault:\r\n\t\t\timagejpeg($photo);\r\n\t\t\tbreak;\r\n\t\t\r\n\t}\r\n\r\n\t\/\/clean up\r\n\tif(is_resource($photo)) {\r\n\t\timagedestroy($photo);\r\n\t}\r\n\tif(is_resource($tmp_img)) {\r\n\t\timagedestroy($tmp_img);\r\n\t}\r\n\r\n\texit();\r\n\r\n\r\n\t\/\/misc helper functions\r\n\tfunction grabParam($x) {\r\n\t\tif(isset($_GET[$x]) && $_GET[$x] != \"\") {\r\n\t\t\treturn $_GET[$x];\r\n\t\t}\r\n\t}\r\n\r\n?&gt;\r\n<\/code>\r\n<\/pre>\r\n\r\n<p>And here&#8217;s the ASP.NET (VB) version (note: I wrote these two scripts at different times, and on different projects, so they don&#8217;t match exactly, but the basic functionality is the same):<\/p>\r\n\r\n<pre>\r\n<code>\r\n&lt;%@ Page Language=\"VB\" Debug=\"False\" %&gt;\r\n&lt;%@ Import Namespace=\"System.IO\" %&gt;\r\n&lt;%@ Import Namespace=\"System.Drawing\" %&gt;\r\n&lt;%@ Import Namespace=\"System.Drawing.Imaging\" %&gt;\r\n&lt;%@ Import Namespace=\"System.Drawing.Graphics\" %&gt;\r\n&lt;%@ Import Namespace=\"System.Drawing.Drawing2D\" %&gt;\r\n&lt;script language=\"VB\" runat=\"server\"&gt;\r\nSub Page_Load(sender as Object, e as EventArgs)\r\n\r\n'------------------------------------------------------------------------------------\r\n'-- HalThumb - a quick and dirty thumbnail script\r\n'-- Parameters:\r\n'-- src = the path to the image\r\n'-- w = width of thumb, in pixels\r\n'-- h = height of thumb, in pixels\r\n'-- crop = type of crop. Options are portfolio or full\r\n'-- can also do custom crop by passing x_size, y_size - see below for full info\r\n'-- http:\/\/www.halnesbitt.com\r\n'------------------------------------------------------------------------------------\r\n\r\n\t'----get the image path\r\n\tDim imageUrl As String = Request.QueryString(\"src\")\r\n\tIf imageUrl = \"\" Then\r\n\t\tResponse.Write(\"no image\")\r\n\t\tExit Sub\r\n\tEnd If\r\n\r\n\tTry\r\n\r\n\t\t'----set default vars\r\n\t\tDim default_thumb_height As Integer = 100\r\n\t\tDim default_thumb_width As Integer = 180\r\n\t\tDim default_thumb_height_max As Integer = 1200\r\n\t\tDim default_thumb_width_max As Integer = 1200\r\n\t\tDim default_crop_type As String = \"scaled\"\r\n\t\t\r\n\t\t'----get the sizes\r\n\t\tDim thumbHeight, thumbWidth as Integer\r\n\t\tIf Request.QueryString(\"h\") = \"\" Then\r\n\t\t\tthumbHeight = default_thumb_height\r\n\t\tElse\r\n\t\t\tthumbHeight = Request.QueryString(\"h\")\r\n\t\tEnd If\r\n\r\n\t\tIf Request.QueryString(\"w\") = \"\"  Then\r\n\t\t\tthumbWidth = default_thumb_width\r\n\t\tElse\r\n\t\t\tthumbWidth = Request.QueryString(\"w\")\r\n\t\tEnd If\r\n\r\n\t\t'----set max values for the thumbnail\r\n\t\tIf thumbHeight &gt; default_thumb_height_max Then\r\n\t\t\tthumbHeight = default_thumb_height_max\r\n\t\tEnd If\r\n\t\r\n\t\tIf thumbWidth &gt; default_thumb_width_max Then\r\n\t\t\tthumbWidth = default_thumb_width_max\r\n\t\tEnd If\r\n\r\n\r\n    \t\t'----set all the image vars\r\n\t\tDim imageName, fileName As String\r\n\t\tDim fullSizeImg As System.Drawing.Image\r\n\t\tDim fullPath As String\r\n\t\tDim bmImg As Drawing.Bitmap\r\n\t\tDim outputImage As System.Drawing.Image\r\n\t\tDim MS As New MemoryStream '----Note: PNGS require outputting to an intermediate memory stream, rather than just directly to the OutputStream\r\n\r\n\t\t'----get the orginal image\r\n\t\tfullPath = Server.MapPath(imageUrl)\r\n\t\tfullSizeImg = System.Drawing.Image.FromFile(fullPath)\r\n\r\n        \tDim originalWidth As Integer = fullSizeImg.Width \r\n        \tDim originalHeight As Integer = fullSizeImg.Height\r\n\t\tDim cropType As String = Request.QueryString(\"crop\")\r\n\t\tIf cropType = \"\" Then\r\n\t\t\tcropType = default_crop_type\r\n\t\tEnd If\r\n\r\n\t\tDim original_aspect As Integer\r\n\t\tDim thumb_aspect As Integer\r\n\t\tDim width_ratio As Decimal\r\n\t\tDim height_ratio As Decimal\r\n\t\tDim scale As Decimal\r\n\t\tDim preview_scale As Decimal\r\n\t\tDim crop_x As Integer = 0\r\n\t\tDim crop_y As Integer = 0\r\n\t\tDim crop_w As Integer = 0\r\n\t\tDim crop_h As Integer = 0\r\n\r\n\t\t'----define ratios\r\n\t\toriginal_aspect = originalWidth \/ originalHeight\r\n\t\tthumb_aspect = thumbWidth \/ thumbHeight\r\n\t\twidth_ratio = thumbWidth \/ originalWidth\r\n\t\theight_ratio = thumbHeight \/ originalHeight\r\n\r\n\t\t'----------------------------------------------------------\r\n\t\t'----Portfolio - this is the main one, so use it mostly for crop and scale\r\n\t\t'----------------------------------------------------------\r\n\t\tIf cropType = \"portfolio\" Then\r\n\r\n\t\t\tIf thumbWidth &gt; thumbHeight Then\r\n\t\t\t\t'----landscape thimb\r\n\t\t\t\tcrop_w = originalWidth\r\n\t\t\t\tcrop_h = (thumbHeight \/ thumbWidth) * originalWidth\r\n\t\t\tElseIf thumbWidth &lt; thumbHeight Then\r\n\t\t\t\t'----portrait thumb\r\n\t\t\t\tcrop_w = (thumbWidth \/ thumbHeight) * originalHeight\r\n\t\t\t\tcrop_h = originalHeight\r\n\t\t\tElse\r\n\t\t\t\t'----square - treat it like landscape - it will get picked up by the cleanup below\r\n\t\t\t\tcrop_w = originalWidth\r\n\t\t\t\tcrop_h = (thumbHeight \/ thumbWidth) * originalWidth\r\n\t\t\tEnd If\r\n\r\n\t\t\t'----if the thumbnail size changes the orientation (from landscape to not landscape) then flip it\r\n\t\t\tIf crop_h  &gt; originalHeight Then\r\n\t\t\t\tcrop_h = originalHeight\r\n\t\t\t\tcrop_w = (thumbWidth \/ thumbHeight) * originalHeight\r\n\t\t\tEnd If\r\n\t\r\n\t\t\t'----or from portrait original to not portrait, then flip it\r\n\t\t\tIf crop_w  &gt; originalWidth Then\r\n\t\t\t\tcrop_h = (thumbHeight \/ thumbWidth) * originalWidth\r\n\t\t\t\tcrop_w = originalWidth\r\n\t\t\tEnd If\r\n\r\n\t\t\tcrop_x = (originalWidth - crop_w) \/ 2\r\n\t\t\tcrop_y = (originalHeight - crop_h) \/ 2\r\n\r\n\t\t'----------------------------------------------------------\r\n\t\t'----Scaled - keeps same proportions\r\n\t\t'----------------------------------------------------------\r\n\r\n\t\tElse\r\n\t\t\tscale = Math.Min((thumbWidth\/originalWidth), (thumbHeight\/originalHeight))\r\n\t\t\tcrop_x = 0\r\n\t\t\tcrop_y = 0\r\n\t\t\tcrop_w = originalWidth\r\n\t\t\tcrop_h = originalHeight\r\n\t\t\tthumbWidth = Math.Floor(scale * originalWidth)\r\n\t\t\tthumbHeight = Math.Floor(scale * originalHeight)\r\n\r\n\t\tEnd If\r\n\r\n\t\t'----------------------------------------------------------\r\n\t\t'----Custom crop - grab extra parameters\r\n\t\t'----------------------------------------------------------\r\n\r\n\t\tIf Request.QueryString(\"x\") &lt;&gt; \"\" AND Request.QueryString(\"y\") &lt;&gt; \"\" Then\r\n\t\t\tIf Request.QueryString(\"x_size\") &lt;&gt; \"\" AND Request.QueryString(\"y_size\") &lt;&gt; \"\" Then\r\n\r\n\t\t\t\t'----meant to be passed from a tool using a crop tool, such as Jcrop\r\n\t\t\t\t'----takes into account what the \"preview image\" size was and scales\r\n\t\t\t\tDim default_preview_width As Integer = 650\r\n\t\t\t\tDim default_preview_height As Integer = 650\r\n\r\n\t\t\t\t'----override the default view, if used in a different module\r\n\t\t\t\tIf Request.QueryString(\"default_preview_width\") &lt;&gt; \"\" Then\r\n\t\t\t\t\tdefault_preview_width = Request.QueryString(\"default_preview_width\")\r\n\t\t\t\tEnd If\r\n\r\n\t\t\t\tIf Request.QueryString(\"default_preview_height\") &lt;&gt; \"\" Then\r\n\t\t\t\t\tdefault_preview_height = Request.QueryString(\"default_preview_height\")\r\n\t\t\t\tEnd If\r\n\r\n\r\n\t\t\t\tpreview_scale = Math.Min((default_preview_width\/originalWidth), (default_preview_height\/originalHeight))\r\n\t\t\t\tcrop_x = Request.QueryString(\"x\") \/ preview_scale\r\n\t\t\t\tcrop_y = Request.QueryString(\"y\") \/ preview_scale\r\n\t\t\t\tcrop_w = Request.QueryString(\"x_size\") \/ preview_scale\r\n\t\t\t\tcrop_h = Request.QueryString(\"y_size\") \/ preview_scale\r\n\t\t\t\tthumbWidth = Request.QueryString(\"w\")\r\n\t\t\t\tthumbHeight = Request.QueryString(\"h\")\r\n\r\n\t\t\tEnd If\r\n\r\n\t\tEnd If\r\n\r\n\r\n\t\t'----Generate the thumbnails\r\n\t\tIf cropType &lt;&gt; \"full\" Then\r\n\r\n\t\t\tDim dummyCallBack as System.Drawing.Image.GetThumbNailImageAbort\r\n\t\t\tdummyCallBack = New System.Drawing.Image.GetThumbnailImageAbort(AddressOf ThumbnailCallback)\r\n\r\n       \t\t\t'----create a bitmap window for cropping\r\n        \t\tbmImg = New Drawing.Bitmap(thumbWidth, thumbHeight) \r\n        \t\tbmImg.SetResolution(72, 72)\r\n         \r\n        \t\t'----create a new graphics object from our image and set properties\r\n\t\t\tDim grImg As Drawing.Graphics = Drawing.Graphics.FromImage(bmImg)\r\n\t\t\tgrImg.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic\r\n\t\t\tgrImg.SmoothingMode = Drawing2D.SmoothingMode.HighQuality\r\n\t\t\tgrImg.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality\r\n\t\t\tgrImg.CompositingQuality = Drawing2D.CompositingQuality.HighQuality\r\n\t\t\t'----grImg.Clear(Color.Orange) '----add background color, for debug\r\n\r\n \t\t\t'----set the rectangles and apply\r\n\t\t\tDim src_rect As New Rectangle(crop_x, crop_y, crop_w, crop_h) '----part of the original image that should be copied\r\n       \t\t\tDim dst_rect As New Rectangle(0, 0, bmImg.Width, bmImg.Height) '----where to draw the src in the new bitmap\r\n\t\t\tgrImg.DrawImage(fullSizeImg, dst_rect, src_rect, GraphicsUnit.Pixel)\r\n\r\n\t\t\t'----assign the thumbnail to the output image\r\n\t\t\toutputImage = bmImg\r\n\r\n\t\t\t'----Clean up \/ Dispose...\r\n\t\t\tgrImg.Dispose()\r\n\r\n\t\tElse\r\n\r\n\t\t\t'----assign the fullsize image to the output image\r\n\t\t\toutputImage = fullSizeImg\r\n\t\tEnd If\r\n\r\n\t\t'----set headers\r\n     \t\timageName = imageUrl.Substring(imageUrl.LastIndexOf(\"\/\"))\r\n\t\tfileName = imageUrl.Substring(1,Len(imageName)-5) & \"_thumb.png\"\r\n\t\tIf cropType = \"full\" Then\r\n     \t\t\tfileName = imageUrl.Substring(1,Len(imageName)-5) & \".png\"\r\n\t\tEnd If\r\n\t\tResponse.ContentType = \"image\/png\"\r\n     \t\tResponse.AddHeader(\"Content-Disposition\", \"inline;filename=\" + fileName)\r\n\t\tResponse.AddHeader(\"Etag\",\"\"\"\" & imageUrl.Substring(1,Len(imageName)-5) & \"\"\"\")\r\n\t\tResponse.AddHeader(\"Last-Modified\", File.GetLastWriteTime(fullPath).ToString(\"ddd, dd MMM yyyy HH:mm:ss\"))\r\n\t\tResponse.Cache.SetCacheability(HttpCacheability.Public)\r\n\t\tResponse.Cache.SetMaxAge(new TimeSpan(1, 0, 0))\r\n\r\n    \t\t'----output the image\r\n     \t\toutputImage.Save(MS, ImageFormat.png)\r\n     \t\tMS.WriteTo(Response.OutputStream) \r\n\r\n    \t\t'----Clean up \/ Dispose...\r\n    \t\tMS.Dispose()\r\n    \t\tfullSizeImg.Dispose()\r\n    \t\toutputImage.Dispose()\r\n\r\n\t\tIf Not bmImg Is Nothing Then\r\n\t\t\tbmImg.Dispose()\r\n\t\tEnd If\r\n\r\n\tCatch ex As Exception\r\n\t\tResponse.Write(ex.ToString())\r\n\tEnd Try\r\n\r\nEnd Sub\r\n\r\nFunction ThumbnailCallback() as Boolean\r\n\tReturn False\r\nEnd Function\r\n&lt;\/script&gt;\r\n\r\n<\/code>\r\n<\/pre>\r\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,1],"tags":[],"class_list":["post-280","post","type-post","status-publish","format-standard","hentry","category-computer-stuff","category-show-all"],"_links":{"self":[{"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/posts\/280","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/comments?post=280"}],"version-history":[{"count":42,"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/posts\/280\/revisions"}],"predecessor-version":[{"id":354,"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/posts\/280\/revisions\/354"}],"wp:attachment":[{"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/media?parent=280"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/categories?post=280"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/halnesbitt.com\/blog\/wp-json\/wp\/v2\/tags?post=280"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}