CINXE.COM
January 2008 – paint.net blog
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="profile" href="http://gmpg.org/xfn/11"> <link rel="pingback" href="https://blog.getpaint.net/xmlrpc.php"> <title>January 2008 – paint.net blog</title> <meta name='robots' content='max-image-preview:large' /> <!-- Async WordPress.com Remote Login --> <script id="wpcom_remote_login_js"> var wpcom_remote_login_extra_auth = ''; function wpcom_remote_login_remove_dom_node_id( element_id ) { var dom_node = document.getElementById( element_id ); if ( dom_node ) { dom_node.parentNode.removeChild( dom_node ); } } function wpcom_remote_login_remove_dom_node_classes( class_name ) { var dom_nodes = document.querySelectorAll( '.' + class_name ); for ( var i = 0; i < dom_nodes.length; i++ ) { dom_nodes[ i ].parentNode.removeChild( dom_nodes[ i ] ); } } function wpcom_remote_login_final_cleanup() { wpcom_remote_login_remove_dom_node_classes( "wpcom_remote_login_msg" ); wpcom_remote_login_remove_dom_node_id( "wpcom_remote_login_key" ); wpcom_remote_login_remove_dom_node_id( "wpcom_remote_login_validate" ); wpcom_remote_login_remove_dom_node_id( "wpcom_remote_login_js" ); wpcom_remote_login_remove_dom_node_id( "wpcom_request_access_iframe" ); wpcom_remote_login_remove_dom_node_id( "wpcom_request_access_styles" ); } // Watch for messages back from the remote login window.addEventListener( "message", function( e ) { if ( e.origin === "https://r-login.wordpress.com" ) { var data = {}; try { data = JSON.parse( e.data ); } catch( e ) { wpcom_remote_login_final_cleanup(); return; } if ( data.msg === 'LOGIN' ) { // Clean up the login check iframe wpcom_remote_login_remove_dom_node_id( "wpcom_remote_login_key" ); var id_regex = new RegExp( /^[0-9]+$/ ); var token_regex = new RegExp( /^.*|.*|.*$/ ); if ( token_regex.test( data.token ) && id_regex.test( data.wpcomid ) ) { // We have everything we need to ask for a login var script = document.createElement( "script" ); script.setAttribute( "id", "wpcom_remote_login_validate" ); script.src = '/remote-login.php?wpcom_remote_login=validate' + '&wpcomid=' + data.wpcomid + '&token=' + encodeURIComponent( data.token ) + '&host=' + window.location.protocol + '//' + window.location.hostname + '&postid=245' + '&is_singular='; document.body.appendChild( script ); } return; } // Safari ITP, not logged in, so redirect if ( data.msg === 'LOGIN-REDIRECT' ) { window.location = 'https://wordpress.com/log-in?redirect_to=' + window.location.href; return; } // Safari ITP, storage access failed, remove the request if ( data.msg === 'LOGIN-REMOVE' ) { var css_zap = 'html { -webkit-transition: margin-top 1s; transition: margin-top 1s; } /* 9001 */ html { margin-top: 0 !important; } * html body { margin-top: 0 !important; } @media screen and ( max-width: 782px ) { html { margin-top: 0 !important; } * html body { margin-top: 0 !important; } }'; var style_zap = document.createElement( 'style' ); style_zap.type = 'text/css'; style_zap.appendChild( document.createTextNode( css_zap ) ); document.body.appendChild( style_zap ); var e = document.getElementById( 'wpcom_request_access_iframe' ); e.parentNode.removeChild( e ); document.cookie = 'wordpress_com_login_access=denied; path=/; max-age=31536000'; return; } // Safari ITP if ( data.msg === 'REQUEST_ACCESS' ) { console.log( 'request access: safari' ); // Check ITP iframe enable/disable knob if ( wpcom_remote_login_extra_auth !== 'safari_itp_iframe' ) { return; } // If we are in a "private window" there is no ITP. var private_window = false; try { var opendb = window.openDatabase( null, null, null, null ); } catch( e ) { private_window = true; } if ( private_window ) { console.log( 'private window' ); return; } var iframe = document.createElement( 'iframe' ); iframe.id = 'wpcom_request_access_iframe'; iframe.setAttribute( 'scrolling', 'no' ); iframe.setAttribute( 'sandbox', 'allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-top-navigation-by-user-activation' ); iframe.src = 'https://r-login.wordpress.com/remote-login.php?wpcom_remote_login=request_access&origin=' + encodeURIComponent( data.origin ) + '&wpcomid=' + encodeURIComponent( data.wpcomid ); var css = 'html { -webkit-transition: margin-top 1s; transition: margin-top 1s; } /* 9001 */ html { margin-top: 46px !important; } * html body { margin-top: 46px !important; } @media screen and ( max-width: 660px ) { html { margin-top: 71px !important; } * html body { margin-top: 71px !important; } #wpcom_request_access_iframe { display: block; height: 71px !important; } } #wpcom_request_access_iframe { border: 0px; height: 46px; position: fixed; top: 0; left: 0; width: 100%; min-width: 100%; z-index: 99999; background: #23282d; } '; var style = document.createElement( 'style' ); style.type = 'text/css'; style.id = 'wpcom_request_access_styles'; style.appendChild( document.createTextNode( css ) ); document.body.appendChild( style ); document.body.appendChild( iframe ); } if ( data.msg === 'DONE' ) { wpcom_remote_login_final_cleanup(); } } }, false ); // Inject the remote login iframe after the page has had a chance to load // more critical resources window.addEventListener( "DOMContentLoaded", function( e ) { var iframe = document.createElement( "iframe" ); iframe.style.display = "none"; iframe.setAttribute( "scrolling", "no" ); iframe.setAttribute( "id", "wpcom_remote_login_key" ); iframe.src = "https://r-login.wordpress.com/remote-login.php" + "?wpcom_remote_login=key" + "&origin=aHR0cHM6Ly9ibG9nLmdldHBhaW50Lm5ldA%3D%3D" + "&wpcomid=12948295" + "&time=1733126498"; document.body.appendChild( iframe ); }, false ); </script> <link rel='dns-prefetch' href='//s1.wp.com' /> <link rel='dns-prefetch' href='//s2.wp.com' /> <link rel='dns-prefetch' href='//s0.wp.com' /> <link rel='dns-prefetch' href='//fonts-api.wp.com' /> <link rel='dns-prefetch' href='//s.pubmine.com' /> <link rel='dns-prefetch' href='//x.bidswitch.net' /> <link rel='dns-prefetch' href='//static.criteo.net' /> <link rel='dns-prefetch' href='//ib.adnxs.com' /> <link rel='dns-prefetch' href='//aax.amazon-adsystem.com' /> <link rel='dns-prefetch' href='//bidder.criteo.com' /> <link rel='dns-prefetch' href='//cas.criteo.com' /> <link rel='dns-prefetch' href='//gum.criteo.com' /> <link rel='dns-prefetch' href='//ads.pubmatic.com' /> <link rel='dns-prefetch' href='//gads.pubmatic.com' /> <link rel='dns-prefetch' href='//tpc.googlesyndication.com' /> <link rel='dns-prefetch' href='//ad.doubleclick.net' /> <link rel='dns-prefetch' href='//googleads.g.doubleclick.net' /> <link rel='dns-prefetch' href='//www.googletagservices.com' /> <link rel='dns-prefetch' href='//cdn.switchadhub.com' /> <link rel='dns-prefetch' href='//delivery.g.switchadhub.com' /> <link rel='dns-prefetch' href='//delivery.swid.switchadhub.com' /> <link rel='dns-prefetch' href='//a.teads.tv' /> <link rel='dns-prefetch' href='//prebid.media.net' /> <link rel='dns-prefetch' href='//adserver-us.adtech.advertising.com' /> <link rel='dns-prefetch' href='//fastlane.rubiconproject.com' /> <link rel='dns-prefetch' href='//prebid-server.rubiconproject.com' /> <link rel='dns-prefetch' href='//hb-api.omnitagjs.com' /> <link rel='dns-prefetch' href='//mtrx.go.sonobi.com' /> <link rel='dns-prefetch' href='//apex.go.sonobi.com' /> <link rel='dns-prefetch' href='//u.openx.net' /> <link rel="alternate" type="application/rss+xml" title="paint.net blog » Feed" href="https://blog.getpaint.net/feed/" /> <link rel="alternate" type="application/rss+xml" title="paint.net blog » Comments Feed" href="https://blog.getpaint.net/comments/feed/" /> <script type="text/javascript"> /* <![CDATA[ */ function addLoadEvent(func) { var oldonload = window.onload; if (typeof window.onload != 'function') { window.onload = func; } else { window.onload = function () { oldonload(); func(); } } } /* ]]> */ </script> <script type="text/javascript"> /* <![CDATA[ */ window._wpemojiSettings = {"baseUrl":"https:\/\/s0.wp.com\/wp-content\/mu-plugins\/wpcom-smileys\/twemoji\/2\/72x72\/","ext":".png","svgUrl":"https:\/\/s0.wp.com\/wp-content\/mu-plugins\/wpcom-smileys\/twemoji\/2\/svg\/","svgExt":".svg","source":{"concatemoji":"https:\/\/s2.wp.com\/wp-includes\/js\/wp-emoji-release.min.js?m=1719498190i&ver=6.8-alpha-59438"}}; /*! This file is auto-generated */ !function(i,n){var o,s,e;function c(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(o,JSON.stringify(t))}catch(e){}}function p(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data),r=(e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0),new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data));return t.every(function(e,t){return e===r[t]})}function u(e,t,n){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\uddfa\ud83c\uddf3","\ud83c\uddfa\u200b\ud83c\uddf3")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!n(e,"\ud83d\udc26\u200d\u2b1b","\ud83d\udc26\u200b\u2b1b")}return!1}function f(e,t,n){var r="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):i.createElement("canvas"),a=r.getContext("2d",{willReadFrequently:!0}),o=(a.textBaseline="top",a.font="600 32px Arial",{});return e.forEach(function(e){o[e]=t(a,e,n)}),o}function t(e){var t=i.createElement("script");t.src=e,t.defer=!0,i.head.appendChild(t)}"undefined"!=typeof Promise&&(o="wpEmojiSettingsSupports",s=["flag","emoji"],n.supports={everything:!0,everythingExceptFlag:!0},e=new Promise(function(e){i.addEventListener("DOMContentLoaded",e,{once:!0})}),new Promise(function(t){var n=function(){try{var e=JSON.parse(sessionStorage.getItem(o));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(s),u.toString(),p.toString()].join(",")+"));",r=new Blob([e],{type:"text/javascript"}),a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=function(e){c(n=e.data),a.terminate(),t(n)})}catch(e){}c(n=f(s,u,p))}t(n)}).then(function(e){for(var t in e)n.supports[t]=e[t],n.supports.everything=n.supports.everything&&n.supports[t],"flag"!==t&&(n.supports.everythingExceptFlag=n.supports.everythingExceptFlag&&n.supports[t]);n.supports.everythingExceptFlag=n.supports.everythingExceptFlag&&!n.supports.flag,n.DOMReady=!1,n.readyCallback=function(){n.DOMReady=!0}}).then(function(){return e}).then(function(){var e;n.supports.everything||(n.readyCallback(),(e=n.source||{}).concatemoji?t(e.concatemoji):e.wpemoji&&e.twemoji&&(t(e.twemoji),t(e.wpemoji)))}))}((window,document),window._wpemojiSettings); /* ]]> */ </script> <link crossorigin='anonymous' rel='stylesheet' id='all-css-0-1' href='https://s0.wp.com/_static/??/wp-content/blog-plugins/wordads/global.css,/wp-content/mu-plugins/widgets/eu-cookie-law/templates/style.css?m=1642463000j&cssminify=yes' type='text/css' media='all' /> <style id='wp-emoji-styles-inline-css'> img.wp-smiley, img.emoji { display: inline !important; border: none !important; box-shadow: none !important; height: 1em !important; width: 1em !important; margin: 0 0.07em !important; vertical-align: -0.1em !important; background: none !important; padding: 0 !important; } </style> <link crossorigin='anonymous' rel='stylesheet' id='all-css-2-1' href='https://s2.wp.com/_static/??-eJydzEEOwiAQheELCWNrFV0YzwKUkKkIZGbQcPtWN+5cuHx5+X54VeVLlpAFamoRM0Ns23SB4vZQgOdw0UbvwTVMM7hU/F0ldGSpA0tPQXvmHfwMfRTDEqTaN7e9NFGRcP43QVYwR/7y2+M6mMN4NNP5NC4rOVVP3w==&cssminify=yes' type='text/css' media='all' /> <style id='wp-block-library-inline-css'> .has-text-align-justify { text-align:justify; } .has-text-align-justify{text-align:justify;} </style> <link crossorigin='anonymous' rel='stylesheet' id='all-css-4-1' href='https://s2.wp.com/_static/??-eJzTLy/QzcxLzilNSS3WzyrWz01NyUxMzUnNTc0rQeEU5CRWphbp5qSmJyZX6uVm5uklFxfr6OPTDpRD5sM02efaGpoZmFkYGRuZGmQBAHPvL0Y=&cssminify=yes' type='text/css' media='all' /> <style id='jetpack-sharing-buttons-style-inline-css'> .jetpack-sharing-buttons__services-list{display:flex;flex-direction:row;flex-wrap:wrap;gap:0;list-style-type:none;margin:5px;padding:0}.jetpack-sharing-buttons__services-list.has-small-icon-size{font-size:12px}.jetpack-sharing-buttons__services-list.has-normal-icon-size{font-size:16px}.jetpack-sharing-buttons__services-list.has-large-icon-size{font-size:24px}.jetpack-sharing-buttons__services-list.has-huge-icon-size{font-size:36px}@media print{.jetpack-sharing-buttons__services-list{display:none!important}}.editor-styles-wrapper .wp-block-jetpack-sharing-buttons{gap:0;padding-inline-start:0}ul.jetpack-sharing-buttons__services-list.has-background{padding:1.25em 2.375em} </style> <link crossorigin='anonymous' rel='stylesheet' id='all-css-6-1' href='https://s2.wp.com/wp-content/plugins/coblocks/2.18.1-simple-rev.4/dist/coblocks-style.css?m=1681832297i&cssminify=yes' type='text/css' media='all' /> <style id='classic-theme-styles-inline-css'> /*! This file is auto-generated */ .wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none} </style> <link crossorigin='anonymous' rel='stylesheet' id='all-css-8-1' href='https://s1.wp.com/_static/??/wp-content/mu-plugins/core-compat/wp-mediaelement.css,/wp-content/mu-plugins/wpcom-bbpress-premium-themes.css?m=1432920480j&cssminify=yes' type='text/css' media='all' /> <style id='global-styles-inline-css'> :root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--font-family--albert-sans: 'Albert Sans', sans-serif;--wp--preset--font-family--alegreya: Alegreya, serif;--wp--preset--font-family--arvo: Arvo, serif;--wp--preset--font-family--bodoni-moda: 'Bodoni Moda', serif;--wp--preset--font-family--bricolage-grotesque: 'Bricolage Grotesque', sans-serif;--wp--preset--font-family--cabin: Cabin, sans-serif;--wp--preset--font-family--chivo: Chivo, sans-serif;--wp--preset--font-family--commissioner: Commissioner, sans-serif;--wp--preset--font-family--cormorant: Cormorant, serif;--wp--preset--font-family--courier-prime: 'Courier Prime', monospace;--wp--preset--font-family--crimson-pro: 'Crimson Pro', serif;--wp--preset--font-family--dm-mono: 'DM Mono', monospace;--wp--preset--font-family--dm-sans: 'DM Sans', sans-serif;--wp--preset--font-family--dm-serif-display: 'DM Serif Display', serif;--wp--preset--font-family--domine: Domine, serif;--wp--preset--font-family--eb-garamond: 'EB Garamond', serif;--wp--preset--font-family--epilogue: Epilogue, sans-serif;--wp--preset--font-family--fahkwang: Fahkwang, sans-serif;--wp--preset--font-family--figtree: Figtree, sans-serif;--wp--preset--font-family--fira-sans: 'Fira Sans', sans-serif;--wp--preset--font-family--fjalla-one: 'Fjalla One', sans-serif;--wp--preset--font-family--fraunces: Fraunces, serif;--wp--preset--font-family--gabarito: Gabarito, system-ui;--wp--preset--font-family--ibm-plex-mono: 'IBM Plex Mono', monospace;--wp--preset--font-family--ibm-plex-sans: 'IBM Plex Sans', sans-serif;--wp--preset--font-family--ibarra-real-nova: 'Ibarra Real Nova', serif;--wp--preset--font-family--instrument-serif: 'Instrument Serif', serif;--wp--preset--font-family--inter: Inter, sans-serif;--wp--preset--font-family--josefin-sans: 'Josefin Sans', sans-serif;--wp--preset--font-family--jost: Jost, sans-serif;--wp--preset--font-family--libre-baskerville: 'Libre Baskerville', serif;--wp--preset--font-family--libre-franklin: 'Libre Franklin', sans-serif;--wp--preset--font-family--literata: Literata, serif;--wp--preset--font-family--lora: Lora, serif;--wp--preset--font-family--merriweather: Merriweather, serif;--wp--preset--font-family--montserrat: Montserrat, sans-serif;--wp--preset--font-family--newsreader: Newsreader, serif;--wp--preset--font-family--noto-sans-mono: 'Noto Sans Mono', sans-serif;--wp--preset--font-family--nunito: Nunito, sans-serif;--wp--preset--font-family--open-sans: 'Open Sans', sans-serif;--wp--preset--font-family--overpass: Overpass, sans-serif;--wp--preset--font-family--pt-serif: 'PT Serif', serif;--wp--preset--font-family--petrona: Petrona, serif;--wp--preset--font-family--piazzolla: Piazzolla, serif;--wp--preset--font-family--playfair-display: 'Playfair Display', serif;--wp--preset--font-family--plus-jakarta-sans: 'Plus Jakarta Sans', sans-serif;--wp--preset--font-family--poppins: Poppins, sans-serif;--wp--preset--font-family--raleway: Raleway, sans-serif;--wp--preset--font-family--roboto: Roboto, sans-serif;--wp--preset--font-family--roboto-slab: 'Roboto Slab', serif;--wp--preset--font-family--rubik: Rubik, sans-serif;--wp--preset--font-family--rufina: Rufina, serif;--wp--preset--font-family--sora: Sora, sans-serif;--wp--preset--font-family--source-sans-3: 'Source Sans 3', sans-serif;--wp--preset--font-family--source-serif-4: 'Source Serif 4', serif;--wp--preset--font-family--space-mono: 'Space Mono', monospace;--wp--preset--font-family--syne: Syne, sans-serif;--wp--preset--font-family--texturina: Texturina, serif;--wp--preset--font-family--urbanist: Urbanist, sans-serif;--wp--preset--font-family--work-sans: 'Work Sans', sans-serif;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}.has-albert-sans-font-family{font-family: var(--wp--preset--font-family--albert-sans) !important;}.has-alegreya-font-family{font-family: var(--wp--preset--font-family--alegreya) !important;}.has-arvo-font-family{font-family: var(--wp--preset--font-family--arvo) !important;}.has-bodoni-moda-font-family{font-family: var(--wp--preset--font-family--bodoni-moda) !important;}.has-bricolage-grotesque-font-family{font-family: var(--wp--preset--font-family--bricolage-grotesque) !important;}.has-cabin-font-family{font-family: var(--wp--preset--font-family--cabin) !important;}.has-chivo-font-family{font-family: var(--wp--preset--font-family--chivo) !important;}.has-commissioner-font-family{font-family: var(--wp--preset--font-family--commissioner) !important;}.has-cormorant-font-family{font-family: var(--wp--preset--font-family--cormorant) !important;}.has-courier-prime-font-family{font-family: var(--wp--preset--font-family--courier-prime) !important;}.has-crimson-pro-font-family{font-family: var(--wp--preset--font-family--crimson-pro) !important;}.has-dm-mono-font-family{font-family: var(--wp--preset--font-family--dm-mono) !important;}.has-dm-sans-font-family{font-family: var(--wp--preset--font-family--dm-sans) !important;}.has-dm-serif-display-font-family{font-family: var(--wp--preset--font-family--dm-serif-display) !important;}.has-domine-font-family{font-family: var(--wp--preset--font-family--domine) !important;}.has-eb-garamond-font-family{font-family: var(--wp--preset--font-family--eb-garamond) !important;}.has-epilogue-font-family{font-family: var(--wp--preset--font-family--epilogue) !important;}.has-fahkwang-font-family{font-family: var(--wp--preset--font-family--fahkwang) !important;}.has-figtree-font-family{font-family: var(--wp--preset--font-family--figtree) !important;}.has-fira-sans-font-family{font-family: var(--wp--preset--font-family--fira-sans) !important;}.has-fjalla-one-font-family{font-family: var(--wp--preset--font-family--fjalla-one) !important;}.has-fraunces-font-family{font-family: var(--wp--preset--font-family--fraunces) !important;}.has-gabarito-font-family{font-family: var(--wp--preset--font-family--gabarito) !important;}.has-ibm-plex-mono-font-family{font-family: var(--wp--preset--font-family--ibm-plex-mono) !important;}.has-ibm-plex-sans-font-family{font-family: var(--wp--preset--font-family--ibm-plex-sans) !important;}.has-ibarra-real-nova-font-family{font-family: var(--wp--preset--font-family--ibarra-real-nova) !important;}.has-instrument-serif-font-family{font-family: var(--wp--preset--font-family--instrument-serif) !important;}.has-inter-font-family{font-family: var(--wp--preset--font-family--inter) !important;}.has-josefin-sans-font-family{font-family: var(--wp--preset--font-family--josefin-sans) !important;}.has-jost-font-family{font-family: var(--wp--preset--font-family--jost) !important;}.has-libre-baskerville-font-family{font-family: var(--wp--preset--font-family--libre-baskerville) !important;}.has-libre-franklin-font-family{font-family: var(--wp--preset--font-family--libre-franklin) !important;}.has-literata-font-family{font-family: var(--wp--preset--font-family--literata) !important;}.has-lora-font-family{font-family: var(--wp--preset--font-family--lora) !important;}.has-merriweather-font-family{font-family: var(--wp--preset--font-family--merriweather) !important;}.has-montserrat-font-family{font-family: var(--wp--preset--font-family--montserrat) !important;}.has-newsreader-font-family{font-family: var(--wp--preset--font-family--newsreader) !important;}.has-noto-sans-mono-font-family{font-family: var(--wp--preset--font-family--noto-sans-mono) !important;}.has-nunito-font-family{font-family: var(--wp--preset--font-family--nunito) !important;}.has-open-sans-font-family{font-family: var(--wp--preset--font-family--open-sans) !important;}.has-overpass-font-family{font-family: var(--wp--preset--font-family--overpass) !important;}.has-pt-serif-font-family{font-family: var(--wp--preset--font-family--pt-serif) !important;}.has-petrona-font-family{font-family: var(--wp--preset--font-family--petrona) !important;}.has-piazzolla-font-family{font-family: var(--wp--preset--font-family--piazzolla) !important;}.has-playfair-display-font-family{font-family: var(--wp--preset--font-family--playfair-display) !important;}.has-plus-jakarta-sans-font-family{font-family: var(--wp--preset--font-family--plus-jakarta-sans) !important;}.has-poppins-font-family{font-family: var(--wp--preset--font-family--poppins) !important;}.has-raleway-font-family{font-family: var(--wp--preset--font-family--raleway) !important;}.has-roboto-font-family{font-family: var(--wp--preset--font-family--roboto) !important;}.has-roboto-slab-font-family{font-family: var(--wp--preset--font-family--roboto-slab) !important;}.has-rubik-font-family{font-family: var(--wp--preset--font-family--rubik) !important;}.has-rufina-font-family{font-family: var(--wp--preset--font-family--rufina) !important;}.has-sora-font-family{font-family: var(--wp--preset--font-family--sora) !important;}.has-source-sans-3-font-family{font-family: var(--wp--preset--font-family--source-sans-3) !important;}.has-source-serif-4-font-family{font-family: var(--wp--preset--font-family--source-serif-4) !important;}.has-space-mono-font-family{font-family: var(--wp--preset--font-family--space-mono) !important;}.has-syne-font-family{font-family: var(--wp--preset--font-family--syne) !important;}.has-texturina-font-family{font-family: var(--wp--preset--font-family--texturina) !important;}.has-urbanist-font-family{font-family: var(--wp--preset--font-family--urbanist) !important;}.has-work-sans-font-family{font-family: var(--wp--preset--font-family--work-sans) !important;} :where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;} :root :where(.wp-block-pullquote){font-size: 1.5em;line-height: 1.6;} :where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;} </style> <link rel='stylesheet' id='sela-fonts-css' href='https://fonts-api.wp.com/css?family=Source+Sans+Pro%3A300%2C300italic%2C400%2C400italic%2C600%7CDroid+Serif%3A400%2C400italic%7COswald%3A300%2C400&subset=latin%2Clatin-ext' media='all' /> <link crossorigin='anonymous' rel='stylesheet' id='all-css-12-1' href='https://s1.wp.com/_static/??-eJyFjssOAiEMRX9IbND4Whg/xTBNRUYohEIm/r2McYHR6O7e5JzbwpQURi7EBUJVyVfrWGCkkgzeXh2kMpwdI1hiyq4J8j0uUWQB3Wa5UiCBVAcQ8gak3D39peZTT1JNCWP44LtPMw0+2hYtNKqrvyRLUfmIprjIb0VdvHF5Vk/hqLf7jdar9WE3PgDfam4x&cssminify=yes' type='text/css' media='all' /> <style id='sela-style-inline-css'> .site-branding { background-image: url(https://blog.getpaint.net/wp-content/uploads/2019/02/blog-header-2019-1.png); } </style> <link crossorigin='anonymous' rel='stylesheet' id='print-css-13-1' href='https://s1.wp.com/wp-content/mu-plugins/global-print/global-print.css?m=1465851035i&cssminify=yes' type='text/css' media='print' /> <style id='jetpack-global-styles-frontend-style-inline-css'> :root { --font-headings: unset; --font-base: unset; --font-headings-default: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; --font-base-default: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;} </style> <link crossorigin='anonymous' rel='stylesheet' id='all-css-16-1' href='https://s2.wp.com/wp-content/themes/h4/global.css?m=1420737423i&cssminify=yes' type='text/css' media='all' /> <script type="text/javascript" id="wpcom-actionbar-placeholder-js-extra"> /* <![CDATA[ */ var actionbardata = {"siteID":"12948295","postID":"0","siteURL":"https:\/\/blog.getpaint.net","xhrURL":"https:\/\/blog.getpaint.net\/wp-admin\/admin-ajax.php","nonce":"3c40ff70a7","isLoggedIn":"","statusMessage":"","subsEmailDefault":"instantly","proxyScriptUrl":"https:\/\/s0.wp.com\/wp-content\/js\/wpcom-proxy-request.js?ver=20211021","i18n":{"followedText":"New posts from this site will now appear in your <a href=\"https:\/\/wordpress.com\/read\">Reader<\/a>","foldBar":"Collapse this bar","unfoldBar":"Expand this bar"}}; /* ]]> */ </script> <script type="text/javascript" id="jetpack-mu-wpcom-settings-js-before"> /* <![CDATA[ */ var JETPACK_MU_WPCOM_SETTINGS = {"assetsUrl":"https:\/\/s1.wp.com\/wp-content\/mu-plugins\/jetpack-mu-wpcom-plugin\/sun\/vendor\/automattic\/jetpack-mu-wpcom\/src\/build\/"}; /* ]]> */ </script> <script crossorigin='anonymous' type='text/javascript' src='https://s1.wp.com/_static/??-eJyFjcsOwiAQRX/I6dSa+lgYvwWBEAgMOAPW/n3bqIk7V2dxT87FqYDOVC1VDIIcKxTOr7kLssN186RjM1a2MTya5fmDLnn6K0HyjlW1v/L37R6zgxKb8yQ4ZTbKCOioRN4hnQo+hw1AmcCZwmvilq7709CPh/54voQFmNpFWg=='></script> <script type="text/javascript" id="rlt-proxy-js-after"> /* <![CDATA[ */ rltInitialize( {"token":null,"iframeOrigins":["https:\/\/widgets.wp.com"]} ); /* ]]> */ </script> <link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://rickbrewster.wordpress.com/xmlrpc.php?rsd" /> <meta name="generator" content="WordPress.com" /> <!-- Jetpack Open Graph Tags --> <meta property="og:type" content="website" /> <meta property="og:title" content="January 2008 – paint.net blog" /> <meta property="og:site_name" content="paint.net blog" /> <meta property="og:image" content="https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=200" /> <meta property="og:image:width" content="200" /> <meta property="og:image:height" content="200" /> <meta property="og:image:alt" content="" /> <meta property="og:locale" content="en_US" /> <!-- End Jetpack Open Graph Tags --> <link rel='openid.server' href='https://blog.getpaint.net/?openidserver=1' /> <link rel='openid.delegate' href='https://blog.getpaint.net/' /> <link rel="search" type="application/opensearchdescription+xml" href="https://blog.getpaint.net/osd.xml" title="paint.net blog" /> <link rel="search" type="application/opensearchdescription+xml" href="https://s1.wp.com/opensearch.xml" title="WordPress.com" /> <meta name="theme-color" content="#f0f0f0" /> <style type="text/css">.recentcomments a{display:inline !important;padding:0 !important;margin:0 !important;}</style> <style type="text/css"> .recentcomments a { display: inline !important; padding: 0 !important; margin: 0 !important; } table.recentcommentsavatartop img.avatar, table.recentcommentsavatarend img.avatar { border: 0px; margin: 0; } table.recentcommentsavatartop a, table.recentcommentsavatarend a { border: 0px !important; background-color: transparent !important; } td.recentcommentsavatarend, td.recentcommentsavatartop { padding: 0px 0px 1px 0px; margin: 0px; } td.recentcommentstextend { border: none !important; padding: 0px 0px 2px 10px; } .rtl td.recentcommentstextend { padding: 0px 10px 2px 0px; } td.recentcommentstexttop { border: none; padding: 0px 0px 0px 10px; } .rtl td.recentcommentstexttop { padding: 0px 10px 0px 0px; } </style> <meta name="application-name" content="paint.net blog" /><meta name="msapplication-window" content="width=device-width;height=device-height" /><meta name="description" content="9 posts published by Rick Brewster during January 2008" /> <style type="text/css" id="custom-background-css"> body.custom-background { background-color: #f0f0f0; } </style> <script type="text/javascript"> /* <![CDATA[ */ var wa_smart = { 'network_id': 3905, 'site_id': 474853, 'page_id': 1572546, 'blog_id': 12948295, 'post_id': null, 'theme': 'pub/sela', 'target': 'wp_blog_id=12948295;language=en', '_': { 'title': 'Advertisement', 'privacy_settings': 'Privacy Settings' }, 'top': { 'enabled': false, 'adflow_enabled': true, 'format_id': 135099 }, 'inline': { 'enabled': false, 'adflow_enabled': true, 'format_id': 110354, 'max_slots': 20, 'max_blaze_slots': 20 }, 'belowpost': { 'enabled': false, 'adflow_enabled': true, 'format_id': 134071 }, 'bottom_sticky': { 'enabled': false, 'adflow_enabled': true, 'format_id': 117571 }, 'sidebar': { 'enabled': false, 'adflow_enabled': true, 'format_id': 134686 }, 'sidebar_sticky_right': { 'enabled': false, 'adflow_enabled': true, 'format_id': 135281 }, 'gutenberg_rectangle': { 'enabled': false, 'adflow_enabled': true, 'format_id': 134788 }, 'gutenberg_leaderboard': { 'enabled': false, 'adflow_enabled': true, 'format_id': 135073 }, 'gutenberg_mobile_leaderboard': { 'enabled': false, 'adflow_enabled': true, 'format_id': 135098 }, 'gutenberg_skyscraper': { 'enabled': false, 'adflow_enabled': true, 'format_id': 135088 } }; wa_smart.cmd = []; /* ]]> */ </script> <script type="text/javascript"> function __ATA_CC() {var v = document.cookie.match('(^|;) ?personalized-ads-consent=([^;]*)(;|$)');return v ? 1 : 0;} var __ATA_PP = { 'pt': 3, 'ht': 0, 'tn': 'sela', 'uloggedin': 0, 'amp': false, 'consent': __ATA_CC(), 'gdpr_applies': false, 'ad': { 'label': { 'text': 'Advertisements' }, 'reportAd': { 'text': 'Report this ad' } }, 'disabled_slot_formats': [], 'siteid': 8982, 'blogid': 12948295 }; var __ATA = __ATA || {}; __ATA.cmd = __ATA.cmd || []; __ATA.criteo = __ATA.criteo || {}; __ATA.criteo.cmd = __ATA.criteo.cmd || []; </script> <script type="text/javascript"> (function(){var g=Date.now||function(){return+new Date};function h(a,b){a:{for(var c=a.length,d="string"==typeof a?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a)){b=e;break a}b=-1}return 0>b?null:"string"==typeof a?a.charAt(b):a[b]};function k(a,b,c){c=null!=c?"="+encodeURIComponent(String(c)):"";if(b+=c){c=a.indexOf("#");0>c&&(c=a.length);var d=a.indexOf("?");if(0>d||d>c){d=c;var e=""}else e=a.substring(d+1,c);a=[a.substr(0,d),e,a.substr(c)];c=a[1];a[1]=b?c?c+"&"+b:b:c;a=a[0]+(a[1]?"?"+a[1]:"")+a[2]}return a};var l=0;function m(a,b){var c=document.createElement("script");c.src=a;c.onload=function(){b&&b(void 0)};c.onerror=function(){b&&b("error")};a=document.getElementsByTagName("head");var d;a&&0!==a.length?d=a[0]:d=document.documentElement;d.appendChild(c)}function n(a){var b=void 0===b?document.cookie:b;return(b=h(b.split("; "),function(c){return-1!=c.indexOf(a+"=")}))?b.split("=")[1]:""}function p(a){return"string"==typeof a&&0<a.length} function r(a,b,c){b=void 0===b?"":b;c=void 0===c?".":c;var d=[];Object.keys(a).forEach(function(e){var f=a[e],q=typeof f;"object"==q&&null!=f||"function"==q?d.push(r(f,b+e+c)):null!==f&&void 0!==f&&(e=encodeURIComponent(b+e),d.push(e+"="+encodeURIComponent(f)))});return d.filter(p).join("&")}function t(a,b){a||((window.__ATA||{}).config=b.c,m(b.url))}var u=Math.floor(1E13*Math.random()),v=window.__ATA||{};window.__ATA=v;window.__ATA.cmd=v.cmd||[];v.rid=u;v.createdAt=g();var w=window.__ATA||{},x="s.pubmine.com"; w&&w.serverDomain&&(x=w.serverDomain);var y="//"+x+"/conf",z=window.top===window,A=window.__ATA_PP&&window.__ATA_PP.gdpr_applies,B="boolean"===typeof A?Number(A):null,C=window.__ATA_PP||null,D=z?document.referrer?document.referrer:null:null,E=z?window.location.href:document.referrer?document.referrer:null,F,G=n("__ATA_tuuid");F=G?G:null;var H=window.innerWidth+"x"+window.innerHeight,I=n("usprivacy"),J=r({gdpr:B,pp:C,rid:u,src:D,ref:E,tuuid:F,vp:H,us_privacy:I?I:null},"","."); (function(a){var b=void 0===b?"cb":b;l++;var c="callback__"+g().toString(36)+"_"+l.toString(36);a=k(a,b,c);window[c]=function(d){t(void 0,d)};m(a,function(d){d&&t(d)})})(y+"?"+J);}).call(this); </script> <script> var sas_fallback = sas_fallback || []; sas_fallback.push( { tag: "<div id="atatags-26942-{{unique_id}}"></div><script>__ATA.cmd.push(function() {__ATA.initDynamicSlot({id: \'atatags-26942-{{unique_id}}\',location: 120,formFactor: \'001\',label: {text: \'Advertisements\',},creative: {reportAd: {text: \'Report this ad\',},privacySettings: {text: \'Privacy\',}}});});</script>", type: 'belowpost' }, { tag: "<div id="atatags-26942-{{unique_id}}"></div><script>__ATA.cmd.push(function() {__ATA.initDynamicSlot({id: \'atatags-26942-{{unique_id}}\',location: 310,formFactor: \'001\',label: {text: \'Advertisements\',},creative: {reportAd: {text: \'Report this ad\',},privacySettings: {text: \'Privacy\',}}});});</script>", type: 'inline' }, { tag: "<div id="atatags-26942-{{unique_id}}"></div><script>__ATA.cmd.push(function() {__ATA.initDynamicSlot({id: \'atatags-26942-{{unique_id}}\',location: 140,formFactor: \'003\',label: {text: \'Advertisements\',},creative: {reportAd: {text: \'Report this ad\',},privacySettings: {text: \'Privacy\',}}});});</script>", type: 'sidebar' }, { tag: "<div id="atatags-26942-{{unique_id}}"></div><script>__ATA.cmd.push(function() {__ATA.initDynamicSlot({id: \'atatags-26942-{{unique_id}}\',location: 110,formFactor: \'002\',label: {text: \'Advertisements\',},creative: {reportAd: {text: \'Report this ad\',},privacySettings: {text: \'Privacy\',}}});});</script>", type: 'top' } ); </script> <script type="text/javascript"> window.doNotSellCallback = function() { var linkElements = [ 'a[href="https://wordpress.com/?ref=footer_blog"]', 'a[href="https://wordpress.com/?ref=footer_website"]', 'a[href="https://wordpress.com/?ref=vertical_footer"]', 'a[href^="https://wordpress.com/?ref=footer_segment_"]', ].join(','); var dnsLink = document.createElement( 'a' ); dnsLink.href = 'https://wordpress.com/advertising-program-optout/'; dnsLink.classList.add( 'do-not-sell-link' ); dnsLink.rel = 'nofollow'; dnsLink.style.marginLeft = '0.5em'; dnsLink.textContent = 'Do Not Sell or Share My Personal Information'; var creditLinks = document.querySelectorAll( linkElements ); if ( 0 === creditLinks.length ) { return false; } Array.prototype.forEach.call( creditLinks, function( el ) { el.insertAdjacentElement( 'afterend', dnsLink ); }); return true; }; </script> <style type="text/css" id="custom-colors-css"> .nav-menu > li > a:after { color: rgba(0, 0, 0, 0.3); } .main-navigation a, .social-links ul a:before { color: #FFFFFF;} .menu-toggle, .menu-toggle:hover, .menu-toggle:focus { color: #FFFFFF;} .main-navigation.toggled ul ul, .main-navigation.toggled ul ul a { color: #FFFFFF;} .site-info a { color: #FFFFFF;} .main-navigation li.current_page_ancestor > a, .main-navigation li.current-menu-ancestor > a { color: #FFFFFF;} .main-navigation a:hover, .main-navigation ul > :hover > a, .main-navigation ul > .focus > a { color: #FFFFFF;} .main-navigation li.current_page_item > a, .main-navigation li.current-menu-item > a { color: #FFFFFF;} .main-navigation li.current_page_item > a .sub-menu li a, .main-navigation li.current-menu-item > a .sub-menu li a, .main-navigation ul ul li.current_page_item > a, .main-navigation ul ul li.current-menu-item > a { color: #4F4F4F;} body { background-color: #f0f0f0;} .main-navigation, button { background-color: #267aaa;} .main-navigation .nav-menu > li > a:after, .main-navigation .menu > li > a:after { color: #5CACDA;} a, .entry-title a:hover, .comment-meta a, .jetpack-testimonial .entry-title { color: #2374A3;} .widget_flickr #flickr_badge_uber_wrapper td a:last-child, .widget-area .milestone-countdown .difference { color: #2374A3;} .main-navigation ul ul a:hover, .main-navigation ul ul > li.focus > a { color: #2374A3;} input[type="button"], input[type="reset"], input[type="submit"], #infinite-handle span { background-color: #2374A3;} input[type="text"]:focus, input[type="email"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="url"]:focus, textarea:focus { border-color: #2374A3;} .social-links ul a:before, .footer-widget-area button { background-color: #7FBCE0;} .site-info a:hover { color: #7FBCE0;} .footer-widget-area a:hover { color: #21719F;} </style> <link rel="icon" href="https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=32" sizes="32x32" /> <link rel="icon" href="https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=192" sizes="192x192" /> <link rel="apple-touch-icon" href="https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=180" /> <meta name="msapplication-TileImage" content="https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=256" /> <script type="text/javascript"> window.google_analytics_uacct = "UA-52447-2"; </script> <script type="text/javascript"> var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-52447-2']); _gaq.push(['_gat._anonymizeIp']); _gaq.push(['_setDomainName', 'none']); _gaq.push(['_setAllowLinker', true]); _gaq.push(['_initData']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga); })(); </script> </head> <body class="archive date custom-background customizer-styles-applied not-multi-author display-header-text jetpack-reblog-enabled"> <div id="page" class="hfeed site"> <header id="masthead" class="site-header" role="banner"> <a class="skip-link screen-reader-text" href="#content" title="Skip to content">Skip to content</a> <div class="site-branding"> <a href="https://blog.getpaint.net/" class="site-logo-link" rel="home" itemprop="url"></a> <h1 class="site-title"><a href="https://blog.getpaint.net/" title="paint.net blog" rel="home">paint.net blog</a></h1> </div><!-- .site-branding --> <nav id="site-navigation" class="main-navigation" role="navigation"> <button class="menu-toggle" aria-controls="menu" aria-expanded="false">Menu</button> <div class="menu"><ul> <li ><a href="https://blog.getpaint.net/">Home</a></li><li class="page_item page-item-336"><a href="https://blog.getpaint.net/about-2/">About</a></li> </ul></div> </nav><!-- #site-navigation --> </header><!-- #masthead --> <div id="content" class="site-content"> <section id="primary" class="content-area"> <main id="main" class="site-main" role="main"> <header class="page-header"> <h1 class="page-title">Month: <span>January 2008</span></h1> </header><!-- .page-header --> <article id="post-245" class="post-245 post type-post status-publish format-standard hentry category-uncategorized without-featured-image"> <header class="entry-header "> <h1 class="entry-title"><a href=" https://blog.getpaint.net/2008/01/28/paintnet-is-going-to-get-8-bit-and-24-bit-png-support/" rel="bookmark">Paint.NET is going to get 8-bit and 24-bit PNG support</a></h1> </header><!-- .entry-header --> <div class="entry-body"> <div class="entry-meta"> <span class="date"><a href="https://blog.getpaint.net/2008/01/28/paintnet-is-going-to-get-8-bit-and-24-bit-png-support/" title="Permalink to Paint.NET is going to get 8-bit and 24-bit PNG support" rel="bookmark"><time class="entry-date published" datetime="2008-01-28T23:32:41-08:00">2008-01-28</time></a></span><span class="comments-link"><a href="https://blog.getpaint.net/2008/01/28/paintnet-is-going-to-get-8-bit-and-24-bit-png-support/#comments">8 Comments</a></span> </div><!-- .entry-meta --> <div class="entry-content"> <p>"It’s about time!!!" <em>— Many users who keep pestering me for this</em></p> <p>I just finished about 90% of the code for adding 8-bit and 24-bit support to Paint.NET’s PNG codec. Most of the work wasn’t even in the PNG codec itself, but rather in adding IndirectUI support for FileType plugins. Once that was done, the extra PNG code just tripped and fell into place. I just really didn’t want to write another WinForms widget complete with obnoxious layout and data binding.</p> <p><em>(dang, I was trying to add a screenshot, but Windows Live Writer refuses to cooperate, oh well — I’ll save it for later I guess?)</em></p> <p>To be honest, it’s that laborious and error-prone WinForms code that was preventing me from adding this support over the last 2 years. After you write it once you realize that you just don’t want to write <em>and debug it</em> ever again. With IndirectUI I only have to write the layout and data binding once, and then I can re-use it for every other file type configuration UI I make going forward.</p> <p>I also plan to redo the configuration UI for the GIF, TGA, and DDS file types so that they use a few simple lines of IndirectUI instead of mountains of WinForms code. Who knows, maybe expanded BMP support will make it into the next release as well. Why not? I wish everything was as easy to implement as with IndirectUI.</p> <p>Also, while implementing this I found out that <a href="http://blogs.msdn.com/mattavis/archive/2004/08/23/219200.aspx" target="_blank">the SOAP formatter for .NET serialization has essentially been deprecated</a>. It doesn’t support serialization of types that have generic type parameters, and will not be updated … lame! So I have moved the persistence for file type settings over to the BinaryFormatter. This means that the next Paint.NET update will forget any settings you’ve had for file types. For instance, if you had JPEG set to a quality of 75 or something (default is 90), that will be reset in the next update.</p> <div id="atatags-26942-674d696235f0e"></div> <script> __ATA.cmd.push(function() { __ATA.initDynamicSlot({ id: 'atatags-26942-674d696235f0e', location: 120, formFactor: '001', label: { text: 'Advertisements', }, creative: { reportAd: { text: 'Report this ad', }, privacySettings: { text: 'Privacy', } } }); }); </script> </div><!-- .entry-content --> </div><!-- .entry-body --> </article><!-- #post-## --> <article id="post-244" class="post-244 post type-post status-publish format-standard hentry category-uncategorized without-featured-image"> <header class="entry-header "> <h1 class="entry-title"><a href=" https://blog.getpaint.net/2008/01/25/heterogeneous-catch-clauses-for-cps-exception-handling/" rel="bookmark">Heterogeneous Catch Clauses for CPS Exception Handling</a></h1> </header><!-- .entry-header --> <div class="entry-body"> <div class="entry-meta"> <span class="date"><a href="https://blog.getpaint.net/2008/01/25/heterogeneous-catch-clauses-for-cps-exception-handling/" title="Permalink to Heterogeneous Catch Clauses for CPS Exception Handling" rel="bookmark"><time class="entry-date published" datetime="2008-01-25T14:01:59-08:00">2008-01-25</time></a></span><span class="comments-link"><a href="https://blog.getpaint.net/2008/01/25/heterogeneous-catch-clauses-for-cps-exception-handling/#comments">4 Comments</a></span> </div><!-- .entry-meta --> <div class="entry-content"> <p>Well, that title is certainly a brain-full and won’t win me any search engine rankings for popular query terms.</p> <p>Anyway, Nidonocu had an important question he posted on <a href="https://blog.getpaint.net/2008/01/22/more-on-continuation-passing-style-generatetest-and-the-do-class" target="_blank">my previous post about the "Do" class</a>:</p> <blockquote> <p>This looks like this could be quite a useful class but I was wondering how this might work when it comes to wanting to catch specific exceptions rather than just the base Exception type? </p> <p>I know from using FxCop that using ‘catch (Exception)’ is something Paint.net rather a lot and while I’m sure you sleep at night doing that, its something I’m trying to avoid in my own app. 😉 <strong>Are there any simple ways this code could be tweaked to not use Exception?</strong></p> </blockquote> <p>The issue is that the various TryCatch() helper methods only take a single delegate for the catch clause, and they always take the base Exception type. In essence, the burden of exception type filtering has been placed on that single delegate, forcing you to do something like:</p> <blockquote> <p><font face="courier new">Do.TryCatch( <br />    () => DoSomething(), <br />    (ex) => <br />    { <br />        if (ex is InvalidOperationException) { … } <br />        else if (ex is SystemException) { … } <br />        else if (ex is FileNotFoundException) { … } <br />        etc.</font><font face="courier new"> <br />    });</font></p> </blockquote> <p>Even then, you can’t use "throw" to propagate the exception correctly. This may also encourage lazy exception handling that only covers the generic "oh no something happened" situation. We’re trying to simplify the code, darnit! You see, I knew about this problem, but I didn’t have a solution for it yet. The type of syntax that I <em>wanted</em> was this:</p> <blockquote> <p><font face="courier new">Do.TryCatch( <br />    () => DoSomething(), <br />    (InvalidOperationException ex) => { … } <br />    (SystemException ex) => { … } <br />    (FileNotFoundException ex) => { … });</font></p> </blockquote> <p>This would be very nice and intuitive, and fairly succinct. You would expect the function signature for Do.TryCatch() to look like the following at this point:</p> <blockquote> <p><font face="courier new">void TryCatch( <br />    Procedure tryFn, <br />    params Procedure<Exception>[] catchFns);</font></p> </blockquote> <p>But you run into a huge problem here. The C# compiler will try to convert each of the lambda expressions into Procedure<Exception> but will be unable to do so — it will convert the first one to Procedure<InvalidOperationException>, etc. and then spit out errors because it can’t convert it. <em>(Actually, it will simply see that the lambda cannot be paired up with Procedure<Exception>, so that last sentence is a weird, technically incorrect simplification.)</em> This is unintuitive at first, but makes perfect sense after thinking about it for a few minutes.</p> <p>Even if two types, T1 and T2, have an inheritance relationship of T2:T1 (that is, T2 derives from T1), this does not create a relationship between Procedure<T1> and Procedure<T2>. For us, this means that even though InvalidOperationException derives from Exception and is thus substitutable for a parameter that is declared as taking an Exception, it is <em>not</em> the case that Procedure<InvalidOperationException> is substitutable for Procedure<Exception>. They are two distinct types in the .NET runtime. We are doing exception filtering, which is a different problem than just covariance or contravariance (I can never keep those two terms straight, I’m not sure which one applies here).</p> <p>I was, however, able to set things up to my liking … almost. Here’s the syntax I was finally able to achieve:</p> <blockquote> <p><font face="courier new">Do.TryCatch( <br />    () => DoSomething(), <br />    CatchClause.From((InvalidOperationException ex) => CatchResult.Throw), <br />    CatchClause.From((SystemException ex) => CatchResult.Handled), <br />    CatchClause.From((FileNotFoundException ex) => { MessageBox.Show("Couldn’t find file!"); return CatchResult.Handled; }));</font></p> </blockquote> <p>We are no longer passing a list of delegates to TryCatch(). Instead, we have a CatchClause class (aka <a href="http://en.wikipedia.org/wiki/Functor" target="_blank">functor</a>) that implements a CanHandle() function to allow for filtering, and then a Handle() method that returns CatchResult.Handled to finish the catch clause, or CatchResult.Throw to re-throw the exception. </p> <p>So, in order to effectively force a type relationship between the delegates (which cannot have "inheritance relationships"), we have to wrap them inside instances of class objects which <em>do</em> have that type relationship we want. In our case, we provide this relationship with a base class called CatchClause, which then has a derived CatchClause<TEx> class, where TEx has a constraint forcing it to derive from Exception. Then, we use CatchClause<InvalidOperationException>, CatchClause<SystemException>, etc. All of these are substitutable for the base CatchClause class, which lets our magic work. Finally, a static helper method in the base CatchClause class makes our TryCatch() usage easier to read and write. Unfortunately we cannot use an implicit type-conversion operator because those cannot take generic type parameters, and the type inference system isn’t quite psychic enough to enable it to work anyway.</p> <p>Here’s the code, which I hereby release into the public domain:</p> <blockquote> <p><font face="courier new">public enum CatchResult <br />{ <br />    Handled, <br />    Throw <br />}</font></p> <p><font face="courier new">public abstract class CatchClause <br />{ <br />    public abstract bool CanHandle(Exception ex); <br />    public abstract CatchResult Handle(Exception ex); </font></p> <p><font face="courier new">    public static CatchClause From<TEx>(Function<CatchResult, TEx> catchFunction) <br />        where TEx : Exception <br />    { <br />        return new DelegateToCatchClause<TEx>(catchFunction); <br />    } <br />}</font></p> <p><font face="courier new">public abstract class CatchClause<TEx> <br />    : CatchClause <br />      where TEx : Exception <br />{ <br />    public override bool CanHandle(Exception ex) <br />    { <br />        return typeof(TEx).IsAssignableFrom(ex.GetType()); <br />    } </font></p> <p><font face="courier new">    public abstract CatchResult HandleT(TEx ex); </font></p> <p><font face="courier new">    public override sealed CatchResult Handle(Exception ex) <br />    { <br />        return HandleT((TEx)ex); <br />    } <br />}</font></p> <p><font face="courier new">public class DelegateToCatchClause<TEx> <br />    : CatchCla<br /> use<TEx> <br />      where TEx: Exception <br />{ <br />    private Function<CatchResult, TEx> catchFunction; </font></p> <p><font face="courier new">    public override CatchResult HandleT(TEx ex) <br />    { <br />        return this.catchFunction(ex); <br />    } </font></p> <p><font face="courier new">    public DelegateToCatchClause(Function<CatchResult, TEx> catchFunction) <br />    { <br />        this.catchFunction = catchFunction; <br />    } <br />}</font></p> <p><font face="courier new">public static void TryCatch( <br />    Procedure actionProcedure, <br />    params CatchClause[] catchClauses) <br />{ <br />    TryCatch(actionProcedure, (IEnumerable<CatchClause>)catchClauses); <br />}</font></p> <p><font face="courier new">public static void TryCatch( <br />    Procedure actionProcedure, <br />    IEnumerable<CatchClause> catchClauses) <br />{ <br />    try <br />    { <br />        actionProcedure(); <br />    } </font></p> <p><font face="courier new">    catch (Exception ex) <br />    { <br />        foreach (CatchClause catchClause in catchClauses) <br />        { <br />            if (catchClause.CanHandle(ex)) <br />            { <br />                CatchResult catchResult = catchClause.Handle(ex); </font></p> <p><font face="courier new">                if (catchResult == CatchResult.Handled) <br />                    break; <br />                else if (catchResult == CatchResult.Throw) <br />                    throw; <br />                else <br />                    throw new InvalidEnumArgumentException("catchResult", (int)catchResult, typeof(CatchResult)); <br />            } <br />       } </p> <p>       throw; // no one handled it, so rethrow <br />    } <br />}</font></p> </blockquote> <div id="atatags-370373-674d696239260"> <script type="text/javascript"> __ATA.cmd.push(function() { __ATA.initVideoSlot('atatags-370373-674d696239260', { sectionId: '370373', format: 'inread' }); }); </script> </div> </div><!-- .entry-content --> </div><!-- .entry-body --> </article><!-- #post-## --> <article id="post-243" class="post-243 post type-post status-publish format-standard hentry category-uncategorized without-featured-image"> <header class="entry-header "> <h1 class="entry-title"><a href=" https://blog.getpaint.net/2008/01/23/use-paintnet-to-photoshop-it/" rel="bookmark">"Use Paint.NET to Photoshop it"</a></h1> </header><!-- .entry-header --> <div class="entry-body"> <div class="entry-meta"> <span class="date"><a href="https://blog.getpaint.net/2008/01/23/use-paintnet-to-photoshop-it/" title="Permalink to "Use Paint.NET to Photoshop it"" rel="bookmark"><time class="entry-date published" datetime="2008-01-23T11:19:06-08:00">2008-01-23</time></a></span><span class="comments-link"><a href="https://blog.getpaint.net/2008/01/23/use-paintnet-to-photoshop-it/#comments">24 Comments</a></span> </div><!-- .entry-meta --> <div class="entry-content"> <p>I guess "Photoshop" really is turning into a generic verb, something that Adobe is undoubtedly unhappy about. I found this on a Q&A website, paraphrased for readability:</p> <blockquote> <p>Question: <em>"My friend has pictures of her eyes, a different color that really stick out. It’s grey and her eyes are bright blue or neon green. Please tell me how to do that." </em>(Note: I believe they are asking how to take a picture of someone’s face and apply a grayscale effect to only the eyes.)</p> <p>Answer 1: "Oh yeah, I’ve seen that but I don’t know how to do that either … let’s read what everyone else has to say, I want to know too…"</p> <p>Answer 2: <em><strong>"use paint.net to photoshop it"</strong></em></p> </blockquote> <p>I won’t link to it so as to preserve their anonymity, but it’s easy enough to find by doing a search for the title of this blog post (including the quotation marks).</p> <p>Anyway, I just thought that was curious enough to share … 🙂</p> </div><!-- .entry-content --> </div><!-- .entry-body --> </article><!-- #post-## --> <article id="post-242" class="post-242 post type-post status-publish format-standard hentry category-uncategorized without-featured-image"> <header class="entry-header "> <h1 class="entry-title"><a href=" https://blog.getpaint.net/2008/01/22/more-on-continuation-passing-style-generatetest-and-the-do-class/" rel="bookmark">More on C# Continuation-Passing Style: The Full "Do" class</a></h1> </header><!-- .entry-header --> <div class="entry-body"> <div class="entry-meta"> <span class="date"><a href="https://blog.getpaint.net/2008/01/22/more-on-continuation-passing-style-generatetest-and-the-do-class/" title="Permalink to More on C# Continuation-Passing Style: The Full "Do" class" rel="bookmark"><time class="entry-date published" datetime="2008-01-22T11:00:10-08:00">2008-01-22</time></a></span><span class="comments-link"><a href="https://blog.getpaint.net/2008/01/22/more-on-continuation-passing-style-generatetest-and-the-do-class/#comments">8 Comments</a></span> </div><!-- .entry-meta --> <div class="entry-content"> <p>Continuing on from yesterday’s post about <a href="https://blog.getpaint.net/2008/01/21/continuation-passing-style-simplifies-your-exception-handling-code/" target="_blank">simplifying exception handling code</a> by using lambdas and <em><a href="http://en.wikipedia.org/wiki/Continuation_passing_style" target="_blank">continuation-passing style</a></em>, I’d like to show off some other examples. Another common pattern in code is to generate a value, test it against some condition, and then have an if/else block to execute two other blocks of code dependent on that test. </p> <p>So, let’s introduce the TryIgnore() and GenerateTest() helper functions with an example (see below for the <em>trivial </em>implementation). I want to generate a full file path for a log file, delete it if it exists, and then enable logging into that file for the later Windows Installer stuff that will be happening. However, if any of that fails I do not want an exception to be propagated because it isn’t critical to the success of what I’m doing.</p> <p>Here’s the old code: <em>(I’m omitting the code that initializes the tempPath, dwMsiLogMode, and dwMsiLogAttributes values. Assume that tempPath is just "%TEMP%", and the others aren’t really important for this discussion)</em></p> <blockquote> <p><font face="courier new">const string logFileName = "PdnMsiInstall.log"; <br /></font><font face="courier new"> <br />try <br />{ <br />    string logFilePath = Path.Combine(tempPath, logFileName); </p> <p>    if (File.Exists(logFilePath)) <br />    { <br />        File.Delete(logFilePath); <br />    } <br />} </font></p> <p><font face="courier new">catch (Exception) <br />{ <br />    // Ignore error <br />} </font></p> <p><font face="courier new">try <br />{ <br />    NativeMethods.MsiEnableLogW( <br />        dwMsiLogMode, <br />        logFilePath, <br />        dwMsiLogAttributes); <br />} </font></p> <p><font face="courier new">catch (Exception) <br />{ <br />    // Ignore error <br />}</font></p> </blockquote> <p>And the new code, which makes use of the TryIgnore() and GenerateTest() helper methods:</p> <blockquote> <p><font face="courier new">const string logFileName = "PdnMsiInstall.log"; </font></p> <p><font face="courier new">Do.TryIgnore(() => <br />    Do.GenerateTest(() => <br />        Path.Combine(tempPath, logFileName), <br />        s => File.Exists(s), <br />        s => File.Delete(s), <br />        s => { /* no-op */ })); </font></p> <p><font face="courier new">Do.TryIgnore(() => NativeMethods.MsiEnableLogW(dwMsiLogMode, logFilePath, dwMsiLogAttributes));</font></p> </blockquote> <p>There’s room to make the code even <em>more</em> succinct by inlining the value of logFileName into the Path.Combine() call, and to have an overload of GenerateTest() that doesn’t take an "ifFalse" delegate. Honestly though, I prefer to have my constants sitting in named values. It makes things easier when you’re sitting in the debugger and scratching your head and/or chin.</p> <p>Here is the full code for my current "Do" class. I hereby release this into the public domain, so do whatever you want with it. There are obviously many other helper functions that could be added, but what I have her is sufficient to get things started. I’ll let you add others as you need them. And remember, my definition of <em>Function </em>has the type parameters in the reverse order that .NET 3.5’s <em>Func</em> delegate has them.</p> <blockquote> <p><font face="Courier New">public delegate R Function<R>(); <br />public delegate R Function<R, TArg>(TArg arg); <br />public delegate void Procedure(); <br />public delegate void Procedure<TArg>(TArg arg);</font> </p> <p><font face="courier new">public static class Do <br />{ <br />    public static void GenerateTest<T>( <br />        Function<T> generate, <br />        Function<bool, T> test, <br />        Procedure<T> ifTrue, <br />        Procedure<T> ifFalse) <br />    { <br />        T value = generate(); <br />        (test(value) ? ifTrue : ifFalse)(value); <br />    } </font></p> <p><font face="courier new">    public static bool TryBool(Procedure actionProcedure) <br />    { <br />        try <br />        { <br />            actionProcedure(); <br />            return true; <br />        } </font></p> <p><font face="courier new">        catch (Exception) <br />        { <br />            return false; <br />        } <br />    } </font></p> <p><font face="courier new">    public static Exception TryEx(Procedure actionProcedure) <br />    { <br />        try <br />        { <br />            actionProcedure(); <br />            return null; <br />        } </font></p> <p><font face="courier new">        catch (Exception ex) <br />        { <br />            return ex; <br />        } <br />    } </font></p> <p><font face="courier new">    public static void TryIgnore(Procedure actionProcedure) <br />    { <br />        try <br />        { <br />            actionProcedure(); <br />        } </font></p> <p><font face="courier new">        catch (Exception) <br />        { <br />            // Ignore <br />        } <br />    } </font></p> <p><font face="courier new">    public static void TryCatch( <br />        Procedure actionProcedure, <br />        Procedure<Exception> catchClause) <br />    { <br />        try <br />        { <br />            actionProcedure();<br /> <br />        } </font></p> <p><font face="courier new">        catch (Exception ex) <br />        { <br />            catchClause(ex); <br />        } <br />    } </font></p> <p><font face="courier new">    public static T TryCatch<T>( <br />        Function<T> actionFunction, <br />        Function<T, Exception> catchClause) <br />    { <br />        T returnVal; </font></p> <p><font face="courier new">        try <br />        { <br />            returnVal = actionFunction(); <br />        } </font></p> <p><font face="courier new">        catch (Exception ex) <br />        { <br />            returnVal = catchClause(ex); <br />        } </font></p> <p><font face="courier new">        return returnVal; <br />    } </font></p> <p><font face="courier new">    public static void TryCatchFinally( <br />        Procedure actionProcedure, <br />        Procedure<Exception> catchClause, <br />        Procedure finallyClause) <br />    { <br />        try <br />        { <br />            actionProcedure(); <br />        } </font></p> <p><font face="courier new">        catch (Exception ex) <br />        { <br />            catchClause(ex); <br />        } </font></p> <p><font face="courier new">        finally <br />        { <br />            finallyClause(); <br />        } <br />    } </font></p> <p><font face="courier new">    public static T TryCatchFinally<T>( <br />        Function<T> actionFunction, <br />        Function<T, Exception> catchClause, <br />        Procedure finallyClause) <br />    { <br />        T returnVal; </font></p> <p><font face="courier new">        try <br />        { <br />            returnVal = actionFunction(); <br />        } </font></p> <p><font face="courier new">        catch (Exception ex) <br />        { <br />            returnVal = catchClause(ex); <br />        } </font></p> <p><font face="courier new">        finally <br />        { <br />            finallyClause(); <br />        } </font></p> <p><font face="courier new">        return returnVal; <br />    } </font></p> <p><font face="courier new">    public static void TryFinally( <br />        Procedure actionProcedure, <br />        Procedure finallyClause) <br />    { <br />        try <br />        { <br />            actionProcedure(); <br />        } </font></p> <p><font face="courier new">        finally <br />        { <br />            finallyClause(); <br />        } <br />    } <br />}</font></p> </blockquote> </div><!-- .entry-content --> </div><!-- .entry-body --> </article><!-- #post-## --> <article id="post-241" class="post-241 post type-post status-publish format-standard hentry category-uncategorized without-featured-image"> <header class="entry-header "> <h1 class="entry-title"><a href=" https://blog.getpaint.net/2008/01/21/continuation-passing-style-simplifies-your-exception-handling-code/" rel="bookmark">Continuation-Passing Style Simplifies Your C# Exception Handling Code</a></h1> </header><!-- .entry-header --> <div class="entry-body"> <div class="entry-meta"> <span class="date"><a href="https://blog.getpaint.net/2008/01/21/continuation-passing-style-simplifies-your-exception-handling-code/" title="Permalink to Continuation-Passing Style Simplifies Your C# Exception Handling Code" rel="bookmark"><time class="entry-date published" datetime="2008-01-21T15:41:04-08:00">2008-01-21</time></a></span><span class="comments-link"><a href="https://blog.getpaint.net/2008/01/21/continuation-passing-style-simplifies-your-exception-handling-code/#comments">7 Comments</a></span> </div><!-- .entry-meta --> <div class="entry-content"> <p>Many lines of code in C# and other imperative languages are seemingly wasted by dealing with overhead such as exception handling and the like. How many times have you written the following type of code?</p> <blockquote> <p>string[] fileNames;</p> <p>try <br />{ <br />    fileNames = Directory.GetFiles(…); <br />} </p> <p>catch (Exception) <br />{ <br />    // There was an error, like the directory isn’t there. <br />    // This isn’t an error for us, so just use a 0-length array <br />    // to simplify our later code <br />    fileNames = new string[0]; <br />} </p> <p>foreach (string fileName in fileNames) <br />{ <br />    … do some processing on this file … <br />}</p> </blockquote> <p>The basic pattern is, "try to obtain a value by calling this function, but if there’s an error then use a default value." It’s a lot of code, and it gets tiring and unreadable or unmanageable after awhile. This pattern, which is called the <em></em><a href="http://enfranchisedmind.com/blog/2007/07/10/the-hole-in-the-middle-pattern/" target="_blank">hole in the middle pattern</a>, crops up all the time in imperative programming. The <em>structure</em> of this block of code is consistent, but there’s that little part in the middle that’s always changing. Most of the time we just trudge through the code because we want to get our stuff done, clock out, then go home and drink beer.</p> <p>C# 3.0 adds a nice feature called <em><a href="http://en.wikipedia.org/wiki/Lambda_expressions" target="_blank">lambda expressions</a></em>, which is mostly syntactic sugar for anonymous delegates. Using them along with <a href="http://en.wikipedia.org/wiki/Continuation_passing_style" target="_blank">continuation-passing style</a> we can write some helper functions that make this type of code much easier to deal with, and more expressive and succinct. In Paint.NET I’m adding a static class called "Do" that will help out with my code:</p> <p><em>(Please note that Paint.NET’s "Function" delegate has the type parameters reversed from .NET 3.5’s "Func" delegate. "Func" delcares them in the traditional functional or mathematical ordering, where "F x -> y" is equivalent to "y F(x)". So, my code uses the "y-x" order. I added "Function" before .NET 3.5 added "Func", so let’s not get on my case about the ordering … 🙂 )</em></p> <blockquote> <p>public static class Do <br />{ <br />    public static T TryCatch<T>(Function<T> actionFunction, Function<T, Exception> catchClause) <br />    { <br />        T returnVal; </p> <p>        try <br />        { <br />            returnVal = actionFunction(); <br />        } </p> <p>        catch (Exception ex) <br />        { <br />            returnVal = catchClause(ex); <br />        } </p> <p>        return returnVal; <br />    } <br />}</p> </blockquote> <p><em>(Quick digression: You’ll note that I do <u>not</u> assign to returnVal at the beginning of the function. This is a pattern I use quite often, because the C# compiler always does analysis to ensure a variable is assigned to before being used. This lets me make sure I always assign a meaningful value, and don’t miss the assignment in any of my branches or clauses. If I were to immediately assign "null", for instance, but then I forgot to assign a meaningful value to it in some if/else branch, then that error would go undetected.)</em></p> <p>Once we have this utility function, the first code snippet simplifies to the following:</p> <blockquote> <p>foreach (string fileName in Do.TryCatch(() => Directory.GetFiles(…), ex => new string[0])) <br />{ <br />    … do some processing on this file … <br />}</p> </blockquote> <p>Voila 🙂 I’m actually using this code in the setup wizard, as it needs to get a list of files in a directory and then delete them. If the directory doesn’t exist then there’s really nothing to do, but it also isn’t an error, and having the try/catch around the call wreaks havoc on the simplicity of the code. This lets me express that much more succinctly.</p> <p>There are other patterns you can use, such as passing lambdas for the finally clause, or passing lambdas for various exception types, or even returning the exception for more imperative style processing.</p> </div><!-- .entry-content --> </div><!-- .entry-body --> </article><!-- #post-## --> <article id="post-240" class="post-240 post type-post status-publish format-standard hentry category-uncategorized without-featured-image"> <header class="entry-header "> <h1 class="entry-title"><a href=" https://blog.getpaint.net/2008/01/16/how-not-to-start-a-business-partnership/" rel="bookmark">How NOT to start a business "partnership"</a></h1> </header><!-- .entry-header --> <div class="entry-body"> <div class="entry-meta"> <span class="date"><a href="https://blog.getpaint.net/2008/01/16/how-not-to-start-a-business-partnership/" title="Permalink to How NOT to start a business "partnership"" rel="bookmark"><time class="entry-date published" datetime="2008-01-16T00:34:56-08:00">2008-01-16</time></a></span><span class="comments-link"><a href="https://blog.getpaint.net/2008/01/16/how-not-to-start-a-business-partnership/#comments">6 Comments</a></span> </div><!-- .entry-meta --> <div class="entry-content"> <p>Remember how I said I keep trying to write a blog post about bundleware, but I always get annoyed and it turns into rambling junk? (I mentioned this briefly in <a href="https://blog.getpaint.net/2008/01/15/how-much-is-paintnet-worth/" target="_blank">my previous blog post</a>)</p> <p>Well, I just received this email from <a href="http://yazzle.net" target="_blank">Yazzle.net</a> or something.</p> <blockquote> <p>Dear <strong>Getpaint</strong>, <em>[sic]</em></p> <p>I represent <a href="http://www.yazzle.net/" target="_blank">Yazzle.net</a>. My company is looking for new business partners to bundle our free bonus software. We want to pay you up to $0.80 for every download you bundle our bonus software with. We pay several of our partners over a thousand dollars a day. We offer products relevant to your site demographics. We believe that you can dramatically increase your revenue and simultaneously improve the experience of the visitors to your website.</p> <p>Please give me a call at <em>(phone number removed)</em> to discuss or contact me at <em>(removed) </em>on aol instant messenger</p> <p>Regards, <br />Joseph Ghartey <br />*Business Development <br />Yazzle.net <br /><em>(contact details removed)</em></p> </blockquote> <p>So apparently they’ll pay me "up to" $400,000 per month*. Err, tempting? But honestly, would I really want to do business with someone who thinks my name is "Getpaint?" Anyone who says they’ll pay "up to" a certain amount is probably just using that figure as a bait, and the real payout is probably 10% of that.** Although even $40,000/month is a nice figure.</p> <p>When you download Paint.NET, you want and you get Paint.NET. I don’t think it’s appropriate to bundle Sudoku and ringtones, that’s just ridiculous to be honest. <strong>Plus, I refuse to do business with </strong><a href="http://www.google.com/search?hl=en&q=yazzle" target="_blank"><strong>spyware/adware providers</strong></a><strong>. </strong>I have more respect for weed dealers*** (well, as long as they’re like Nancy Botwin from <a href="http://www.sho.com/site/weeds/home.do" target="_blank">Weeds on Showtime</a>, anyway). If I ever bundle anything with Paint.NET it’ll have to be something that’s actually relevant and useful in the context of Paint.NET type stuff.</p> <p><em>* Calculated from a rough average/estimate of 500,000 Paint.NET downloads per month. <br /></em><em>** I have no facts to back this up, just good ol’ fashioned cynicism. I’d never heard of Yazzle.net before they e-mailed me. <br />*** This is not a pro-drug endorsement, I’m just trying to make a point. At least a weed dealer is providing something that the customer actually wants. Spyware/adware is usually snuck on to the user’s system without their honest consent.</em></p> </div><!-- .entry-content --> </div><!-- .entry-body --> </article><!-- #post-## --> <article id="post-237" class="post-237 post type-post status-publish format-standard hentry category-update-news without-featured-image"> <header class="entry-header "> <h1 class="entry-title"><a href=" https://blog.getpaint.net/2008/01/12/paintnet-v322-is-now-available/" rel="bookmark">Paint.NET v3.22 is now available</a></h1> </header><!-- .entry-header --> <div class="entry-body"> <div class="entry-meta"> <span class="date"><a href="https://blog.getpaint.net/2008/01/12/paintnet-v322-is-now-available/" title="Permalink to Paint.NET v3.22 is now available" rel="bookmark"><time class="entry-date published" datetime="2008-01-12T20:22:48-08:00">2008-01-12</time></a></span><span class="comments-link"><a href="https://blog.getpaint.net/2008/01/12/paintnet-v322-is-now-available/#comments">12 Comments</a></span> </div><!-- .entry-meta --> <div class="entry-content"> <p>It’s that time again: a new version of Paint.NET! This release fixes a few minor bugs and adds a new, much-needed Reduce Noise effect. You can download it from the website at <a href="http://www.getpaint.net">http://www.getpaint.net</a>, or use the built-in updater by clicking on <em>Help -> Check for Updates</em> within the application. </p> <p>Changes: </p> <ul> <li><strong>New</strong>: “Reduce Noise” effect. </li> <li>Changed: Ctrl+W will now close Paint.NET if zero images are open. </li> <li><strong>Fixed</strong>: In Windows XP, when launching web content, sometimes Internet Explorer was used instead of the user’s chosen default browser. </li> <li><strong>Fixed</strong>: The Unfocus effect was not handling alpha values properly. </li> <li><strong>Fixed</strong>: The Brightness / Contrast adjustment was only displaying its text in English. </li> <li><strong>Fixed</strong>: The /auto parameter for the installer now correctly allows for an automated installation. This was inadvertently broken in 3.20. </li> </ul> <p>Enjoy!</p> </div><!-- .entry-content --> </div><!-- .entry-body --> </article><!-- #post-## --> <article id="post-236" class="post-236 post type-post status-publish format-standard hentry category-update-news without-featured-image"> <header class="entry-header "> <h1 class="entry-title"><a href=" https://blog.getpaint.net/2008/01/04/paintnet-v322-beta-2-is-now-available/" rel="bookmark">Paint.NET v3.22 Beta 2 is now available</a></h1> </header><!-- .entry-header --> <div class="entry-body"> <div class="entry-meta"> <span class="date"><a href="https://blog.getpaint.net/2008/01/04/paintnet-v322-beta-2-is-now-available/" title="Permalink to Paint.NET v3.22 Beta 2 is now available" rel="bookmark"><time class="entry-date published" datetime="2008-01-04T16:57:32-08:00">2008-01-04</time></a></span><span class="comments-link"><a href="https://blog.getpaint.net/2008/01/04/paintnet-v322-beta-2-is-now-available/#comments">8 Comments</a></span> </div><!-- .entry-meta --> <div class="entry-content"> <p>There weren’t many changes for this update, but they’re all in the <em>installer</em> so I felt it was very important to get wider testing before trusting the code enough for a final release. Anyway, as usual you can get the update from the website at <a href="http://www.getpaint.net/">http://www.getpaint.net/</a> or you can use the built-in updater from the Help -> Check for Updates menu item. You will need to make sure that “Also check for Beta releases” is enabled, by clicking on the “Options” button after clicking the “Check for Updates” menu item. </p> <p>Changes since Beta 1: </p> <ul> <li><strong>Fixed:</strong> Some uncommon installer bugs </li> <li><strong>Fixed:</strong> Very poor performance during installation or updating, sometimes causing the removal of the previous version to take 20 minutes </li> </ul> <p>Enjoy!</p> </div><!-- .entry-content --> </div><!-- .entry-body --> </article><!-- #post-## --> <article id="post-231" class="post-231 post type-post status-publish format-standard hentry category-uncategorized without-featured-image"> <header class="entry-header "> <h1 class="entry-title"><a href=" https://blog.getpaint.net/2008/01/03/refactoring-a-mountain-late-binding-for-paintnet-v40/" rel="bookmark">Refactoring A Mountain: Late-Binding for Paint.NET v4.0</a></h1> </header><!-- .entry-header --> <div class="entry-body"> <div class="entry-meta"> <span class="date"><a href="https://blog.getpaint.net/2008/01/03/refactoring-a-mountain-late-binding-for-paintnet-v40/" title="Permalink to Refactoring A Mountain: Late-Binding for Paint.NET v4.0" rel="bookmark"><time class="entry-date published" datetime="2008-01-03T17:31:23-08:00">2008-01-03</time></a></span><span class="comments-link"><a href="https://blog.getpaint.net/2008/01/03/refactoring-a-mountain-late-binding-for-paintnet-v40/#comments">13 Comments</a></span> </div><!-- .entry-meta --> <div class="entry-content"> <p>Like I stated earlier, <a href="https://blog.getpaint.net/2007/12/19/paintnet%e2%80%99s-plans-for-2008/">I’ve finally started work on Paint.NET v4.0</a> (yay!). To that end, I’ll be focusing most of my development time throughout 2008 on this effort. There will still be Paint.NET releases in the meantime, as there is plenty of life left in the 3.xx architecture. There are a lot of small features that Paint.NET lacks and needs to catch up on that are feasible even without the changes I am slowly architecting into the 4.0 branch. I’m also hoping and planning to integrate some of the more popular or useful community plugins (with permission of course!). </p> <p>A major change in the Paint.NET architecture for version 4.0 is the introduction of a pervasive late-binding and inversion-of-control mechanism. At a glance it looks like a localized version of COM: “give me an object that implements this interface, btw I don’t care what concrete class actually implements it” (actually, in COM you quite often do specify which implementation you want, but bear with me). </p> <p>It isn’t anything revolutionary, but refactoring it into a code base that weighs in at 150,000 lines of code is a lot of work. It’s being very educational to me to go through and see all the poor code choices that have been made over the last 4 years. If only I had been psychic back then, I would have known the right way to do things! 🙂 </p> <p>Consider a line of code to load an image resource: </p> <p><span style="font-family:Courier New;font-size:9pt;">. string labelText = PdnResources.GetString(“SomeDialog.SomeControl.Text”);</span> </p> <p><strong>PdnResources</strong> is a static class that contains all the logic for retrieving the string resource from the appropriate language file. However, having this as a static class is a <strong>very very bad thing, </strong>and this pattern is repeated for many other classes that need to be accessible throughout the application. Any piece of code can load resources, even if it shouldn’t be able to. For example, there is code in the <strong>Layer</strong> and <strong>Document</strong> classes to load the default name for a layer, and this is not appropriate for code that is in the <em>data layer</em> of the application. This text should be supplied by whoever is creating the objects, or hooked in at the UI layer somehow instead. </p> <p>To that end, this code will be moved out of a static class and into a public interface and a concrete, private implementation. A bindings provider (or <em>scope</em>) will serve as the mechanism for accessing it. </p> <p style="margin-left:36pt;"><span style="font-family:Courier New;font-size:9pt;">public interface IResourcesService { … }</p> <p>internal sealed class ResourcesService : IResourcesService { … }</p> <p>bindings.RegisterService<IResourcesService, ResourcesService>();</p> <p>string labelText = bindings.GetService<IResourcesService>().GetString(<br /> “SomeDialog.SomeControl.Text”);<br /> </span></p> <p>At first glance, this may not appear to buy much, and is more code that is less expressive. But it allows me several things, including the freedom to <em>move</em> the resource loader, or to <em>hide</em> it from pieces of code (such as plugins, or from the data layer). I can do more granular <em>versioning </em>so that if plugins do need access I can at least continue to change it with more freedom (just introduce a “IResourcesServiceV2” or whatever). I can implement things like pseudo-localization by way of chaining together two implementations of IResourcesService. Logging and fault injection can be made easier, as they can also be implemented as a chained implementation. By “chained implementation” I mean that the normal implementation stays as-is, but a second implementation is registered so that it passes-through method calls while also performing some other service, such as logging or transformation. The primary implementation can then be kept clean and simple. </p> <p>The “bindings” object would never be available globally or statically. Any object that needs to use it must take it via its constructor. This is proving to be a lot of work to enforce, but I believe it will be worth it. It makes it easier to analyze things like layering and dependency flow if code can’t just magically go and grab resources from static locations, and is instead forced to go through an object that is supplied by its creator/owner. For example, if I don’t want the data layer to be able to load resources, then I simply remove the IResourcesService from its bindings object. The only way to access the concrete class at that point would be via reflection, which is easy enough to detect and combat against. </p> <p>I plan on extending this pattern to all of the static classes in the SystemLayer assembly as well. Instead of just bluntly calling into the <strong>PaintDotNet.SystemLayer.FileSystem</strong> static class, for instance, you would ask for the <strong>IFileSystemService</strong> via your local bindings provider object. The SystemLayer DLL would then have a static class with one function that would be responsible for registering all of the bindings. </p> <p>This may even make things easier for Miguel de Icaza and his <a href="http://tirania.org/blog/archive/2007/Dec-21.html">Mono port, Paint-Mono</a>, although it’s too early to tell for certain. Done properly, there could be a PaintDotNet.SystemLayer.NetFxWin32.dll and a PaintDotNet.SystemLayer.MonoLinux.dll, and a simple configuration or command-line switch of some sort would choose which one to use at startup. I’ve paid attention to his blog posts and other documentation and it has brought to light some areas that still need to be separated into the SystemLayer DLL. </p> <p>And while this could be a boon for Miguel, it’s also good for me and isn’t something I’m necessarily doing to directly help out his porting efforts. What if the differences between the XP and Vista code paths grew so great that I needed two different versions of the SystemLayer DLL? Or, what about a Mac OS version?* Moving to a late binding system and avoiding static classes will make things much, much cleaner. Who knows, maybe I can stuff Windows Forms itself behind an abstraction layer and decouple Paint.NET from it. That’s actually one of the things that the new IndirectUI system in v3.20 has allowed me to practice with: I could port the thing over to WPF or even to a console window, and the effects/plugin code wouldn’t know the slightest difference. </p> <p><em>* This should not be taken as an announcement of a plan to release a Mac OS version.</em></p> </div><!-- .entry-content --> </div><!-- .entry-body --> </article><!-- #post-## --> </main><!-- #main --> </section><!-- #primary --> <div id="secondary" class="widget-area sidebar-widget-area" role="complementary"> <aside id="block-5" class="widget widget_block widget_search"><form role="search" method="get" action="https://blog.getpaint.net/" class="wp-block-search__button-outside wp-block-search__text-button wp-block-search" ><label class="wp-block-search__label" for="wp-block-search__input-1" >Search</label><div class="wp-block-search__inside-wrapper " ><input class="wp-block-search__input" id="wp-block-search__input-1" placeholder="" value="" type="search" name="s" required /><button aria-label="Search" class="wp-block-search__button wp-element-button" type="submit" >Search</button></div></form></aside><aside id="twitter_timeline-3" class="widget widget_twitter_timeline"><h3 class="widget-title">Follow me on Twitter</h3><a class="twitter-timeline" data-width="220" data-height="200" data-theme="light" data-border-color="#f0f0f1" data-lang="EN" data-partner="jetpack" href="https://twitter.com/rickbrewPDN" href="https://twitter.com/rickbrewPDN">My Tweets</a></aside><aside id="block-4" class="widget widget_block widget_archive"><ul class="wp-block-archives-list wp-block-archives"> <li><a href='https://blog.getpaint.net/2024/12/'>December 2024</a></li> <li><a href='https://blog.getpaint.net/2024/11/'>November 2024</a></li> <li><a href='https://blog.getpaint.net/2024/10/'>October 2024</a></li> <li><a href='https://blog.getpaint.net/2024/09/'>September 2024</a></li> <li><a href='https://blog.getpaint.net/2024/08/'>August 2024</a></li> <li><a href='https://blog.getpaint.net/2024/03/'>March 2024</a></li> <li><a href='https://blog.getpaint.net/2023/12/'>December 2023</a></li> <li><a href='https://blog.getpaint.net/2023/10/'>October 2023</a></li> <li><a href='https://blog.getpaint.net/2023/08/'>August 2023</a></li> <li><a href='https://blog.getpaint.net/2023/07/'>July 2023</a></li> <li><a href='https://blog.getpaint.net/2023/06/'>June 2023</a></li> <li><a href='https://blog.getpaint.net/2023/05/'>May 2023</a></li> <li><a href='https://blog.getpaint.net/2023/03/'>March 2023</a></li> <li><a href='https://blog.getpaint.net/2023/02/'>February 2023</a></li> <li><a href='https://blog.getpaint.net/2023/01/'>January 2023</a></li> <li><a href='https://blog.getpaint.net/2022/12/'>December 2022</a></li> <li><a href='https://blog.getpaint.net/2022/11/'>November 2022</a></li> <li><a href='https://blog.getpaint.net/2022/08/'>August 2022</a></li> <li><a href='https://blog.getpaint.net/2022/05/'>May 2022</a></li> <li><a href='https://blog.getpaint.net/2022/03/'>March 2022</a></li> <li><a href='https://blog.getpaint.net/2022/02/'>February 2022</a></li> <li><a href='https://blog.getpaint.net/2022/01/'>January 2022</a></li> <li><a href='https://blog.getpaint.net/2021/12/'>December 2021</a></li> <li><a href='https://blog.getpaint.net/2021/11/'>November 2021</a></li> <li><a href='https://blog.getpaint.net/2021/10/'>October 2021</a></li> <li><a href='https://blog.getpaint.net/2021/09/'>September 2021</a></li> <li><a href='https://blog.getpaint.net/2021/08/'>August 2021</a></li> <li><a href='https://blog.getpaint.net/2021/07/'>July 2021</a></li> <li><a href='https://blog.getpaint.net/2021/04/'>April 2021</a></li> <li><a href='https://blog.getpaint.net/2021/01/'>January 2021</a></li> <li><a href='https://blog.getpaint.net/2020/10/'>October 2020</a></li> <li><a href='https://blog.getpaint.net/2020/09/'>September 2020</a></li> <li><a href='https://blog.getpaint.net/2020/08/'>August 2020</a></li> <li><a href='https://blog.getpaint.net/2020/07/'>July 2020</a></li> <li><a href='https://blog.getpaint.net/2020/05/'>May 2020</a></li> <li><a href='https://blog.getpaint.net/2020/04/'>April 2020</a></li> <li><a href='https://blog.getpaint.net/2020/02/'>February 2020</a></li> <li><a href='https://blog.getpaint.net/2020/01/'>January 2020</a></li> <li><a href='https://blog.getpaint.net/2019/12/'>December 2019</a></li> <li><a href='https://blog.getpaint.net/2019/11/'>November 2019</a></li> <li><a href='https://blog.getpaint.net/2019/10/'>October 2019</a></li> <li><a href='https://blog.getpaint.net/2019/09/'>September 2019</a></li> <li><a href='https://blog.getpaint.net/2019/08/'>August 2019</a></li> <li><a href='https://blog.getpaint.net/2019/07/'>July 2019</a></li> <li><a href='https://blog.getpaint.net/2019/06/'>June 2019</a></li> <li><a href='https://blog.getpaint.net/2019/05/'>May 2019</a></li> <li><a href='https://blog.getpaint.net/2019/03/'>March 2019</a></li> <li><a href='https://blog.getpaint.net/2018/12/'>December 2018</a></li> <li><a href='https://blog.getpaint.net/2018/11/'>November 2018</a></li> <li><a href='https://blog.getpaint.net/2018/10/'>October 2018</a></li> <li><a href='https://blog.getpaint.net/2018/09/'>September 2018</a></li> <li><a href='https://blog.getpaint.net/2018/08/'>August 2018</a></li> <li><a href='https://blog.getpaint.net/2018/04/'>April 2018</a></li> <li><a href='https://blog.getpaint.net/2018/01/'>January 2018</a></li> <li><a href='https://blog.getpaint.net/2017/12/'>December 2017</a></li> <li><a href='https://blog.getpaint.net/2017/10/'>October 2017</a></li> <li><a href='https://blog.getpaint.net/2017/09/'>September 2017</a></li> <li><a href='https://blog.getpaint.net/2017/08/'>August 2017</a></li> <li><a href='https://blog.getpaint.net/2017/07/'>July 2017</a></li> <li><a href='https://blog.getpaint.net/2017/06/'>June 2017</a></li> <li><a href='https://blog.getpaint.net/2017/04/'>April 2017</a></li> <li><a href='https://blog.getpaint.net/2016/12/'>December 2016</a></li> <li><a href='https://blog.getpaint.net/2016/09/'>September 2016</a></li> <li><a href='https://blog.getpaint.net/2016/07/'>July 2016</a></li> <li><a href='https://blog.getpaint.net/2016/06/'>June 2016</a></li> <li><a href='https://blog.getpaint.net/2016/01/'>January 2016</a></li> <li><a href='https://blog.getpaint.net/2015/12/'>December 2015</a></li> <li><a href='https://blog.getpaint.net/2015/08/'>August 2015</a></li> <li><a href='https://blog.getpaint.net/2015/07/'>July 2015</a></li> <li><a href='https://blog.getpaint.net/2014/12/'>December 2014</a></li> <li><a href='https://blog.getpaint.net/2014/11/'>November 2014</a></li> <li><a href='https://blog.getpaint.net/2014/07/'>July 2014</a></li> <li><a href='https://blog.getpaint.net/2014/06/'>June 2014</a></li> <li><a href='https://blog.getpaint.net/2014/04/'>April 2014</a></li> <li><a href='https://blog.getpaint.net/2014/02/'>February 2014</a></li> <li><a href='https://blog.getpaint.net/2014/01/'>January 2014</a></li> <li><a href='https://blog.getpaint.net/2013/12/'>December 2013</a></li> <li><a href='https://blog.getpaint.net/2013/11/'>November 2013</a></li> <li><a href='https://blog.getpaint.net/2013/10/'>October 2013</a></li> <li><a href='https://blog.getpaint.net/2013/08/'>August 2013</a></li> <li><a href='https://blog.getpaint.net/2013/03/'>March 2013</a></li> <li><a href='https://blog.getpaint.net/2012/10/'>October 2012</a></li> <li><a href='https://blog.getpaint.net/2012/09/'>September 2012</a></li> <li><a href='https://blog.getpaint.net/2012/05/'>May 2012</a></li> <li><a href='https://blog.getpaint.net/2012/04/'>April 2012</a></li> <li><a href='https://blog.getpaint.net/2012/03/'>March 2012</a></li> <li><a href='https://blog.getpaint.net/2011/12/'>December 2011</a></li> <li><a href='https://blog.getpaint.net/2011/10/'>October 2011</a></li> <li><a href='https://blog.getpaint.net/2011/09/'>September 2011</a></li> <li><a href='https://blog.getpaint.net/2011/07/'>July 2011</a></li> <li><a href='https://blog.getpaint.net/2011/06/'>June 2011</a></li> <li><a href='https://blog.getpaint.net/2011/05/'>May 2011</a></li> <li><a href='https://blog.getpaint.net/2011/04/'>April 2011</a></li> <li><a href='https://blog.getpaint.net/2011/03/'>March 2011</a></li> <li><a href='https://blog.getpaint.net/2011/02/'>February 2011</a></li> <li><a href='https://blog.getpaint.net/2010/12/'>December 2010</a></li> <li><a href='https://blog.getpaint.net/2010/11/'>November 2010</a></li> <li><a href='https://blog.getpaint.net/2010/10/'>October 2010</a></li> <li><a href='https://blog.getpaint.net/2010/08/'>August 2010</a></li> <li><a href='https://blog.getpaint.net/2010/07/'>July 2010</a></li> <li><a href='https://blog.getpaint.net/2010/06/'>June 2010</a></li> <li><a href='https://blog.getpaint.net/2010/04/'>April 2010</a></li> <li><a href='https://blog.getpaint.net/2010/03/'>March 2010</a></li> <li><a href='https://blog.getpaint.net/2010/02/'>February 2010</a></li> <li><a href='https://blog.getpaint.net/2010/01/'>January 2010</a></li> <li><a href='https://blog.getpaint.net/2009/12/'>December 2009</a></li> <li><a href='https://blog.getpaint.net/2009/11/'>November 2009</a></li> <li><a href='https://blog.getpaint.net/2009/10/'>October 2009</a></li> <li><a href='https://blog.getpaint.net/2009/09/'>September 2009</a></li> <li><a href='https://blog.getpaint.net/2009/08/'>August 2009</a></li> <li><a href='https://blog.getpaint.net/2009/06/'>June 2009</a></li> <li><a href='https://blog.getpaint.net/2009/05/'>May 2009</a></li> <li><a href='https://blog.getpaint.net/2009/04/'>April 2009</a></li> <li><a href='https://blog.getpaint.net/2009/03/'>March 2009</a></li> <li><a href='https://blog.getpaint.net/2009/02/'>February 2009</a></li> <li><a href='https://blog.getpaint.net/2009/01/'>January 2009</a></li> <li><a href='https://blog.getpaint.net/2008/12/'>December 2008</a></li> <li><a href='https://blog.getpaint.net/2008/11/'>November 2008</a></li> <li><a href='https://blog.getpaint.net/2008/10/'>October 2008</a></li> <li><a href='https://blog.getpaint.net/2008/09/'>September 2008</a></li> <li><a href='https://blog.getpaint.net/2008/08/'>August 2008</a></li> <li><a href='https://blog.getpaint.net/2008/07/'>July 2008</a></li> <li><a href='https://blog.getpaint.net/2008/06/'>June 2008</a></li> <li><a href='https://blog.getpaint.net/2008/05/'>May 2008</a></li> <li><a href='https://blog.getpaint.net/2008/04/'>April 2008</a></li> <li><a href='https://blog.getpaint.net/2008/03/'>March 2008</a></li> <li><a href='https://blog.getpaint.net/2008/02/'>February 2008</a></li> <li><a href='https://blog.getpaint.net/2008/01/' aria-current="page">January 2008</a></li> <li><a href='https://blog.getpaint.net/2007/12/'>December 2007</a></li> <li><a href='https://blog.getpaint.net/2007/11/'>November 2007</a></li> <li><a href='https://blog.getpaint.net/2007/10/'>October 2007</a></li> <li><a href='https://blog.getpaint.net/2007/09/'>September 2007</a></li> <li><a href='https://blog.getpaint.net/2007/08/'>August 2007</a></li> <li><a href='https://blog.getpaint.net/2007/07/'>July 2007</a></li> <li><a href='https://blog.getpaint.net/2007/06/'>June 2007</a></li> <li><a href='https://blog.getpaint.net/2007/05/'>May 2007</a></li> </ul></aside> <div id="atatags-286348-674d69624468f"></div> <script> __ATA.cmd.push(function() { __ATA.initDynamicSlot({ id: 'atatags-286348-674d69624468f', location: 140, formFactor: '003', label: { text: 'Advertisements', }, creative: { reportAd: { text: 'Report this ad', }, privacySettings: { text: 'Privacy', } } }); }); </script> </div><!-- #secondary --> </div><!-- #content --> <footer id="colophon" class="site-footer"> <div class="site-info" role="contentinfo"> <a href="https://wordpress.com/?ref=footer_website" rel="nofollow">Create a free website or blog at WordPress.com.</a> </div><!-- .site-info --> </footer><!-- #colophon --> </div><!-- #page --> <!-- --> <script type="text/javascript" src="//0.gravatar.com/js/hovercards/hovercards.min.js?ver=202449b213a1cbb4e3271ca470eb7790af362ac2e18ce468f8945952c7bd3456d2132e" id="grofiles-cards-js"></script> <script type="text/javascript" id="wpgroho-js-extra"> /* <![CDATA[ */ var WPGroHo = {"my_hash":""}; /* ]]> */ </script> <script crossorigin='anonymous' type='text/javascript' src='https://s2.wp.com/wp-content/mu-plugins/gravatar-hovercards/wpgroho.js?m=1610363240i'></script> <script> // Initialize and attach hovercards to all gravatars ( function() { function init() { if ( typeof Gravatar === 'undefined' ) { return; } if ( typeof Gravatar.init !== 'function' ) { return; } Gravatar.profile_cb = function ( hash, id ) { WPGroHo.syncProfileData( hash, id ); }; Gravatar.my_hash = WPGroHo.my_hash; Gravatar.init( 'body', '#wp-admin-bar-my-account', { i18n: { 'Edit your profile': 'Edit your profile', 'View profile': 'View profile', 'Sorry, we are unable to load this Gravatar profile.': 'Sorry, we are unable to load this Gravatar profile.', 'Profile not found.': 'Profile not found.', 'Too Many Requests.': 'Too Many Requests.', 'Internal Server Error.': 'Internal Server Error.', }, } ); } if ( document.readyState !== 'loading' ) { init(); } else { document.addEventListener( 'DOMContentLoaded', init ); } } )(); </script> <div style="display:none"> </div> <script type="text/javascript"> ( function() { function init() { document.body.addEventListener( 'is.post-load', function() { if ( typeof __ATA.insertInlineAds === 'function' ) { __ATA.insertInlineAds(); } } ); } if ( document.readyState !== 'loading' ) { init(); } else { document.addEventListener( 'DOMContentLoaded', init ); } } )(); </script> <!-- CCPA [start] --> <script type="text/javascript"> ( function () { var setupPrivacy = function() { // Minimal Mozilla Cookie library // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework var cookieLib = window.cookieLib = {getItem:function(e){return e&&decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*"+encodeURIComponent(e).replace(/[\-\.\+\*]/g,"\\$&")+"\\s*\\=\\s*([^;]*).*$)|^.*$"),"$1"))||null},setItem:function(e,o,n,t,r,i){if(!e||/^(?:expires|max\-age|path|domain|secure)$/i.test(e))return!1;var c="";if(n)switch(n.constructor){case Number:c=n===1/0?"; expires=Fri, 31 Dec 9999 23:59:59 GMT":"; max-age="+n;break;case String:c="; expires="+n;break;case Date:c="; expires="+n.toUTCString()}return"rootDomain"!==r&&".rootDomain"!==r||(r=(".rootDomain"===r?".":"")+document.location.hostname.split(".").slice(-2).join(".")),document.cookie=encodeURIComponent(e)+"="+encodeURIComponent(o)+c+(r?"; domain="+r:"")+(t?"; path="+t:"")+(i?"; secure":""),!0}}; // Implement IAB USP API. window.__uspapi = function( command, version, callback ) { // Validate callback. if ( typeof callback !== 'function' ) { return; } // Validate the given command. if ( command !== 'getUSPData' || version !== 1 ) { callback( null, false ); return; } // Check for GPC. If set, override any stored cookie. if ( navigator.globalPrivacyControl ) { callback( { version: 1, uspString: '1YYN' }, true ); return; } // Check for cookie. var consent = cookieLib.getItem( 'usprivacy' ); // Invalid cookie. if ( null === consent ) { callback( null, false ); return; } // Everything checks out. Fire the provided callback with the consent data. callback( { version: 1, uspString: consent }, true ); }; // Initialization. document.addEventListener( 'DOMContentLoaded', function() { // Internal functions. var setDefaultOptInCookie = function() { var value = '1YNN'; var domain = '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname; cookieLib.setItem( 'usprivacy', value, 365 * 24 * 60 * 60, '/', domain ); }; var setDefaultOptOutCookie = function() { var value = '1YYN'; var domain = '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname; cookieLib.setItem( 'usprivacy', value, 24 * 60 * 60, '/', domain ); }; var setDefaultNotApplicableCookie = function() { var value = '1---'; var domain = '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname; cookieLib.setItem( 'usprivacy', value, 24 * 60 * 60, '/', domain ); }; var setCcpaAppliesCookie = function( applies ) { var domain = '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname; cookieLib.setItem( 'ccpa_applies', applies, 24 * 60 * 60, '/', domain ); } var maybeCallDoNotSellCallback = function() { if ( 'function' === typeof window.doNotSellCallback ) { return window.doNotSellCallback(); } return false; } // Look for usprivacy cookie first. var usprivacyCookie = cookieLib.getItem( 'usprivacy' ); // Found a usprivacy cookie. if ( null !== usprivacyCookie ) { // If the cookie indicates that CCPA does not apply, then bail. if ( '1---' === usprivacyCookie ) { return; } // CCPA applies, so call our callback to add Do Not Sell link to the page. maybeCallDoNotSellCallback(); // We're all done, no more processing needed. return; } // We don't have a usprivacy cookie, so check to see if we have a CCPA applies cookie. var ccpaCookie = cookieLib.getItem( 'ccpa_applies' ); // No CCPA applies cookie found, so we'll need to geolocate if this visitor is from California. // This needs to happen client side because we do not have region geo data in our $SERVER headers, // only country data -- therefore we can't vary cache on the region. if ( null === ccpaCookie ) { var request = new XMLHttpRequest(); request.open( 'GET', 'https://public-api.wordpress.com/geo/', true ); request.onreadystatechange = function () { if ( 4 === this.readyState ) { if ( 200 === this.status ) { // Got a geo response. Parse out the region data. var data = JSON.parse( this.response ); var region = data.region ? data.region.toLowerCase() : ''; var ccpa_applies = ['california', 'colorado', 'connecticut', 'delaware', 'indiana', 'iowa', 'montana', 'new jersey', 'oregon', 'tennessee', 'texas', 'utah', 'virginia'].indexOf( region ) > -1; // Set CCPA applies cookie. This keeps us from having to make a geo request too frequently. setCcpaAppliesCookie( ccpa_applies ); // Check if CCPA applies to set the proper usprivacy cookie. if ( ccpa_applies ) { if ( maybeCallDoNotSellCallback() ) { // Do Not Sell link added, so set default opt-in. setDefaultOptInCookie(); } else { // Failed showing Do Not Sell link as required, so default to opt-OUT just to be safe. setDefaultOptOutCookie(); } } else { // CCPA does not apply. setDefaultNotApplicableCookie(); } } else { // Could not geo, so let's assume for now that CCPA applies to be safe. setCcpaAppliesCookie( true ); if ( maybeCallDoNotSellCallback() ) { // Do Not Sell link added, so set default opt-in. setDefaultOptInCookie(); } else { // Failed showing Do Not Sell link as required, so default to opt-OUT just to be safe. setDefaultOptOutCookie(); } } } }; // Send the geo request. request.send(); } else { // We found a CCPA applies cookie. if ( ccpaCookie === 'true' ) { if ( maybeCallDoNotSellCallback() ) { // Do Not Sell link added, so set default opt-in. setDefaultOptInCookie(); } else { // Failed showing Do Not Sell link as required, so default to opt-OUT just to be safe. setDefaultOptOutCookie(); } } else { // CCPA does not apply. setDefaultNotApplicableCookie(); } } } ); }; // Kickoff initialization. if ( window.defQueue && defQueue.isLOHP && defQueue.isLOHP === 2020 ) { defQueue.items.push( setupPrivacy ); } else { setupPrivacy(); } } )(); </script> <!-- CCPA [end] --> <div class="widget widget_eu_cookie_law_widget"> <div class="hide-on-button ads-active" data-hide-timeout="30" data-consent-expiration="180" id="eu-cookie-law" style="display: none" > <form method="post"> <input type="submit" value="Close and accept" class="accept" /> Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use. <br /> To find out more, including how to control cookies, see here: <a href="https://automattic.com/cookies/" rel="nofollow"> Cookie Policy </a> </form> </div> </div> <div id="actionbar" style="display: none;" class="actnbr-pub-sela actnbr-has-follow"> <ul> <li class="actnbr-btn actnbr-hidden"> <a class="actnbr-action actnbr-actn-follow " href=""> <svg class="gridicon" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path clip-rule="evenodd" d="m4 4.5h12v6.5h1.5v-6.5-1.5h-1.5-12-1.5v1.5 10.5c0 1.1046.89543 2 2 2h7v-1.5h-7c-.27614 0-.5-.2239-.5-.5zm10.5 2h-9v1.5h9zm-5 3h-4v1.5h4zm3.5 1.5h-1v1h1zm-1-1.5h-1.5v1.5 1 1.5h1.5 1 1.5v-1.5-1-1.5h-1.5zm-2.5 2.5h-4v1.5h4zm6.5 1.25h1.5v2.25h2.25v1.5h-2.25v2.25h-1.5v-2.25h-2.25v-1.5h2.25z" fill-rule="evenodd"></path></svg> <span>Subscribe</span> </a> <a class="actnbr-action actnbr-actn-following no-display" href=""> <svg class="gridicon" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M16 4.5H4V15C4 15.2761 4.22386 15.5 4.5 15.5H11.5V17H4.5C3.39543 17 2.5 16.1046 2.5 15V4.5V3H4H16H17.5V4.5V12.5H16V4.5ZM5.5 6.5H14.5V8H5.5V6.5ZM5.5 9.5H9.5V11H5.5V9.5ZM12 11H13V12H12V11ZM10.5 9.5H12H13H14.5V11V12V13.5H13H12H10.5V12V11V9.5ZM5.5 12H9.5V13.5H5.5V12Z" fill="#008A20"></path><path class="following-icon-tick" d="M13.5 16L15.5 18L19 14.5" stroke="#008A20" stroke-width="1.5"></path></svg> <span>Subscribed</span> </a> <div class="actnbr-popover tip tip-top-left actnbr-notice" id="follow-bubble"> <div class="tip-arrow"></div> <div class="tip-inner actnbr-follow-bubble"> <ul> <li class="actnbr-sitename"> <a href="https://blog.getpaint.net"> <img loading='lazy' alt='' src='https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=50' srcset='https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=50 1x, https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=75 1.5x, https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=100 2x, https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=150 3x, https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=200 4x' class='avatar avatar-50' height='50' width='50' /> paint.net blog </a> </li> <div class="actnbr-message no-display"></div> <form method="post" action="https://subscribe.wordpress.com" accept-charset="utf-8" style="display: none;"> <div class="actnbr-follow-count">Join 456 other subscribers</div> <div> <input type="email" name="email" placeholder="Enter your email address" class="actnbr-email-field" aria-label="Enter your email address" /> </div> <input type="hidden" name="action" value="subscribe" /> <input type="hidden" name="blog_id" value="12948295" /> <input type="hidden" name="source" value="https://blog.getpaint.net/2008/01/" /> <input type="hidden" name="sub-type" value="actionbar-follow" /> <input type="hidden" id="_wpnonce" name="_wpnonce" value="1722b188b4" /> <div class="actnbr-button-wrap"> <button type="submit" value="Sign me up"> Sign me up </button> </div> </form> <li class="actnbr-login-nudge"> <div> Already have a WordPress.com account? <a href="https://wordpress.com/log-in?redirect_to=https%3A%2F%2Fr-login.wordpress.com%2Fremote-login.php%3Faction%3Dlink%26back%3Dhttps%253A%252F%252Fblog.getpaint.net%252F2008%252F01%252F28%252Fpaintnet-is-going-to-get-8-bit-and-24-bit-png-support%252F">Log in now.</a> </div> </li> </ul> </div> </div> </li> <li class="actnbr-ellipsis actnbr-hidden"> <svg class="gridicon gridicons-ellipsis" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M7 12c0 1.104-.896 2-2 2s-2-.896-2-2 .896-2 2-2 2 .896 2 2zm12-2c-1.104 0-2 .896-2 2s.896 2 2 2 2-.896 2-2-.896-2-2-2zm-7 0c-1.104 0-2 .896-2 2s.896 2 2 2 2-.896 2-2-.896-2-2-2z"/></g></svg> <div class="actnbr-popover tip tip-top-left actnbr-more"> <div class="tip-arrow"></div> <div class="tip-inner"> <ul> <li class="actnbr-sitename"> <a href="https://blog.getpaint.net"> <img loading='lazy' alt='' src='https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=50' srcset='https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=50 1x, https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=75 1.5x, https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=100 2x, https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=150 3x, https://blog.getpaint.net/wp-content/uploads/2019/02/paintdotnet.256.png?w=200 4x' class='avatar avatar-50' height='50' width='50' /> paint.net blog </a> </li> <li class="actnbr-folded-customize"> <a href="https://rickbrewster.wordpress.com/wp-admin/customize.php?url=https%3A%2F%2Frickbrewster.wordpress.com%2F2008%2F01%2F"> <svg class="gridicon gridicons-customize" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M2 6c0-1.505.78-3.08 2-4 0 .845.69 2 2 2 1.657 0 3 1.343 3 3 0 .386-.08.752-.212 1.09.74.594 1.476 1.19 2.19 1.81L8.9 11.98c-.62-.716-1.214-1.454-1.807-2.192C6.753 9.92 6.387 10 6 10c-2.21 0-4-1.79-4-4zm12.152 6.848l1.34-1.34c.607.304 1.283.492 2.008.492 2.485 0 4.5-2.015 4.5-4.5 0-.725-.188-1.4-.493-2.007L18 9l-2-2 3.507-3.507C18.9 3.188 18.225 3 17.5 3 15.015 3 13 5.015 13 7.5c0 .725.188 1.4.493 2.007L3 20l2 2 6.848-6.848c1.885 1.928 3.874 3.753 5.977 5.45l1.425 1.148 1.5-1.5-1.15-1.425c-1.695-2.103-3.52-4.092-5.448-5.977z"/></g></svg> <span>Customize</span> </a> </li> <li class="actnbr-folded-follow"> <a class="actnbr-action actnbr-actn-follow " href=""> <svg class="gridicon" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path clip-rule="evenodd" d="m4 4.5h12v6.5h1.5v-6.5-1.5h-1.5-12-1.5v1.5 10.5c0 1.1046.89543 2 2 2h7v-1.5h-7c-.27614 0-.5-.2239-.5-.5zm10.5 2h-9v1.5h9zm-5 3h-4v1.5h4zm3.5 1.5h-1v1h1zm-1-1.5h-1.5v1.5 1 1.5h1.5 1 1.5v-1.5-1-1.5h-1.5zm-2.5 2.5h-4v1.5h4zm6.5 1.25h1.5v2.25h2.25v1.5h-2.25v2.25h-1.5v-2.25h-2.25v-1.5h2.25z" fill-rule="evenodd"></path></svg> <span>Subscribe</span> </a> <a class="actnbr-action actnbr-actn-following no-display" href=""> <svg class="gridicon" height="20" width="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M16 4.5H4V15C4 15.2761 4.22386 15.5 4.5 15.5H11.5V17H4.5C3.39543 17 2.5 16.1046 2.5 15V4.5V3H4H16H17.5V4.5V12.5H16V4.5ZM5.5 6.5H14.5V8H5.5V6.5ZM5.5 9.5H9.5V11H5.5V9.5ZM12 11H13V12H12V11ZM10.5 9.5H12H13H14.5V11V12V13.5H13H12H10.5V12V11V9.5ZM5.5 12H9.5V13.5H5.5V12Z" fill="#008A20"></path><path class="following-icon-tick" d="M13.5 16L15.5 18L19 14.5" stroke="#008A20" stroke-width="1.5"></path></svg> <span>Subscribed</span> </a> </li> <li class="actnbr-signup"><a href="https://wordpress.com/start/">Sign up</a></li> <li class="actnbr-login"><a href="https://wordpress.com/log-in?redirect_to=https%3A%2F%2Fr-login.wordpress.com%2Fremote-login.php%3Faction%3Dlink%26back%3Dhttps%253A%252F%252Fblog.getpaint.net%252F2008%252F01%252F28%252Fpaintnet-is-going-to-get-8-bit-and-24-bit-png-support%252F">Log in</a></li> <li class="flb-report"> <a href="https://wordpress.com/abuse/?report_url=https://blog.getpaint.net" target="_blank" rel="noopener noreferrer"> Report this content </a> </li> <li class="actnbr-reader"> <a href="https://wordpress.com/read/feeds/92711"> View site in Reader </a> </li> <li class="actnbr-subs"> <a href="https://subscribe.wordpress.com/">Manage subscriptions</a> </li> <li class="actnbr-fold"><a href="">Collapse this bar</a></li> </ul> </div> </div> </li> </ul> </div> <script> window.addEventListener( "load", function( event ) { var link = document.createElement( "link" ); link.href = "https://s0.wp.com/wp-content/mu-plugins/actionbar/actionbar.css?v=20241015"; link.type = "text/css"; link.rel = "stylesheet"; document.head.appendChild( link ); var script = document.createElement( "script" ); script.src = "https://s0.wp.com/wp-content/mu-plugins/actionbar/actionbar.js?v=20231122"; script.defer = true; document.body.appendChild( script ); } ); </script> <script crossorigin='anonymous' type='text/javascript' src='https://s1.wp.com/_static/??-eJyNj91KxUAMhF/IGA9VxAvxUSTdpmva7A9N1vXx3QOC0gs5VyGTmW8I9gqhZOfsuBmmMosyNOOD4tBA8lruN7vDP75ZS4SqLUo27OVYaDEISmZsV0gn13Mmtd+ELJHdkNu4ll0YlDo6p6rkfNLPHP/gNDy1zWisdK3L9CmRXEq+wWy7VFDJO6wlNINVvm5JjfnPRxt7pbD/7Ggt47vkgN7FnQ9wSTw6eSDe0uvlebo8Tg/T08v2DVipjbU='></script> <script type="text/javascript"> (function () { var wpcom_reblog = { source: 'toolbar', toggle_reblog_box_flair: function (obj_id, post_id) { // Go to site selector. This will redirect to their blog if they only have one. const postEndpoint = `https://wordpress.com/post`; // Ideally we would use the permalink here, but fortunately this will be replaced with the // post permalink in the editor. const originalURL = `${ document.location.href }?page_id=${ post_id }`; const url = postEndpoint + '?url=' + encodeURIComponent( originalURL ) + '&is_post_share=true' + '&v=5'; const redirect = function () { if ( ! window.open( url, '_blank' ) ) { location.href = url; } }; if ( /Firefox/.test( navigator.userAgent ) ) { setTimeout( redirect, 0 ); } else { redirect(); } }, }; window.wpcom_reblog = wpcom_reblog; })(); </script> <script type="text/javascript"> // <![CDATA[ (function() { try{ if ( window.external &&'msIsSiteMode' in window.external) { if (window.external.msIsSiteMode()) { var jl = document.createElement('script'); jl.type='text/javascript'; jl.async=true; jl.src='/wp-content/plugins/ie-sitemode/custom-jumplist.php'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(jl, s); } } }catch(e){} })(); // ]]> </script><script src="//stats.wp.com/w.js?67" defer></script> <script type="text/javascript"> _tkq = window._tkq || []; _stq = window._stq || []; _tkq.push(['storeContext', {'blog_id':'12948295','blog_tz':'-7','user_lang':'en','blog_lang':'en','user_id':'0'}]); _stq.push(['view', {'blog':'12948295','v':'wpcom','tz':'-7','user_id':'0','subd':'rickbrewster'}]); _stq.push(['extra', {'crypt':'UE5XaGUuOTlwaD85flAmcm1mcmZsaDhkV11YdWtpP0NsWnVkPS9sL0ViLndld3BEMUpSVTRMYl1bdDRQfC9oVjE9K35zLlU9VTRKZGhZLjgtbWxXalEreGI0NnZuTVltP0lmMi5zWyUtYlM3N1JNc0t3X285b2hNSTFwRG1GLCwyZm15dCVERHVHfjRabS1+Q1Q2cyVdPU90T2c3M0hwbkp1b2FrTHxUaXp3b19IbWhnXy5SQ1ImV1VCMy1SJmRQMWguck9zUWt6ckxdak5aTTRxUU9JZ0VEK3QlSmwrQ25keS8lVklTVUJSTC82M25JTnF5YkNdbENqdXR8OCZseFBbNixTXTdveklIdz1WZjJaOFVkS090R0VDP3A/V19aUw=='}]); _stq.push([ 'clickTrackerInit', '12948295', '0' ]); </script> <noscript><img src="https://pixel.wp.com/b.gif?v=noscript" style="height:1px;width:1px;overflow:hidden;position:absolute;bottom:1px;" alt="" /></noscript> <script> ( function() { function getMobileUserAgentInfo() { if ( typeof wpcom_mobile_user_agent_info === 'object' ) { wpcom_mobile_user_agent_info.init(); var mobileStatsQueryString = ''; if ( wpcom_mobile_user_agent_info.matchedPlatformName !== false ) { mobileStatsQueryString += '&x_' + 'mobile_platforms' + '=' + wpcom_mobile_user_agent_info.matchedPlatformName; } if ( wpcom_mobile_user_agent_info.matchedUserAgentName !== false ) { mobileStatsQueryString += '&x_' + 'mobile_devices' + '=' + wpcom_mobile_user_agent_info.matchedUserAgentName; } if ( wpcom_mobile_user_agent_info.isIPad() ) { mobileStatsQueryString += '&x_' + 'ipad_views' + '=' + 'views'; } if ( mobileStatsQueryString != '' ) { new Image().src = document.location.protocol + '//pixel.wp.com/g.gif?v=wpcom-no-pv' + mobileStatsQueryString + '&baba=' + Math.random(); } } } document.addEventListener( 'DOMContentLoaded', getMobileUserAgentInfo ); } )(); </script> </body> </html>