File size: 44,258 Bytes
5b9de19 fb53cde 5b9de19 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Six Labors Split License — check your code for free</title>
<meta name="description" content="This free browser tool flags references to ImageSharp, Drawing, Fonts, and ImageSharp.Web versions covered by the Six Labors Split License and shows the SkiaSharp replacement for each line.">
<style>
:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
.wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
.bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
.note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
</style>
<script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/skiasharp-migration-check"><style data-yj-mfit="1">#out{max-width:100%}#out td,#out th{overflow-wrap:anywhere}#out pre,#out code{white-space:pre-wrap;overflow-wrap:anywhere}@media (max-width:640px){table{display:block;max-width:100%;overflow-x:auto}pre{max-width:100%;overflow-x:auto}code,a{overflow-wrap:anywhere}img,svg,video,canvas,iframe{max-width:100%}textarea,input,select{max-width:100%;box-sizing:border-box}.yj-lgbar{position:static!important;justify-content:flex-end;margin:0 0 10px}#out table:not(:has(tr>:nth-child(4))){display:table;table-layout:fixed;width:100%}#out table:has(tr>:nth-child(4)),#out table:has(tr>:nth-child(4)) tbody,#out table:has(tr>:nth-child(4)) tr,#out table:has(tr>:nth-child(4)) td{display:block;width:auto;overflow:visible}#out table:has(tr>:nth-child(4)) thead{display:none}#out table:has(tr>:nth-child(4)) tr{padding:10px 0;border-bottom:1px solid rgba(128,128,128,.28)}#out table:has(tr>:nth-child(4)) td{border:0;padding:1px 0}#out table:has(tr>:nth-child(4)) td:nth-child(-n+3){display:inline-block;margin-right:10px;font-size:12px;opacity:.78}}</style>
</head>
<body>
<div class="wrap">
<h1>Six Labors Split License — check your code for free</h1>
<p class="lede">Flags SixLabors ImageSharp 3+, Drawing 2+, Fonts 2+ and ImageSharp.Web 3+ references that fall under the Six Labors Split License, with the SkiaSharp (MIT) replacement for each line. Runs entirely in your browser — nothing is uploaded.</p>
<textarea id="src" spellcheck="false"><Project Sdk="Microsoft.NET.Sdk.Web">
<!-- Thumbnail API for the product catalogue, deployed as a Linux container -->
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />
<PackageReference Include="SixLabors.Fonts" Version="2.1.3" />
<PackageReference Include="SixLabors.ImageSharp.Web" Version="3.2.0" />
<PackageReference Include="SixLabors.ImageSharp.Web.Providers.AWS" Version="*" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
</ItemGroup>
</Project></textarea>
<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
<div id="out" aria-live="polite"></div>
<div id="paid"><strong>Free here:</strong> Check one .csproj, Directory.Packages.props, packages.config or .cs file and see every Six Labors line under the Split License with its SkiaSharp replacement.. <strong>In the editor:</strong> Scan every project in the solution at once and export one Markdown migration checklist for the licence review ticket. — that part asks for a licence key.</div>
<p class="note">Same engine as the VS Code extension, byte for byte.</p>
</div>
<script>var ISM_RULES = [
{"id": "ISM001", "sev": "error", "kind": "pkg", "pkg": "^SixLabors\\.ImageSharp$", "line_major": 3, "fix": "SkiaSharp 3.119.4 (MIT)", "tail": true,
"msg": "SixLabors.ImageSharp 3.0.0 and later ships under the Six Labors Split License: a direct reference by a for-profit company with 1M USD or more annual gross revenue needs a commercial licence. Replace with SkiaSharp (MIT): SKBitmap / SKImage."},
{"id": "ISM002", "sev": "error", "kind": "pkg", "pkg": "^SixLabors\\.ImageSharp\\.Drawing$", "line_major": 2, "fix": "SkiaSharp SKCanvas + SKPath",
"msg": "SixLabors.ImageSharp.Drawing 2.0.0 and later ships under the Six Labors Split License. Replace the drawing calls with SkiaSharp SKCanvas, SKPath and SKPaint."},
{"id": "ISM003", "sev": "error", "kind": "pkg", "pkg": "^SixLabors\\.Fonts$", "line_major": 2, "fix": "SkiaSharp SKFont + SkiaSharp.HarfBuzz",
"msg": "SixLabors.Fonts 2.0.0 and later ships under the Six Labors Split License. Replace with SkiaSharp SKTypeface / SKFont, and SkiaSharp.HarfBuzz for text shaping."},
{"id": "ISM004", "sev": "error", "kind": "pkg", "pkg": "^SixLabors\\.ImageSharp\\.Web(\\..+)?$", "line_major": 3, "fix": "resize endpoint on SkiaSharp",
"msg": "SixLabors.ImageSharp.Web 3.0.0 and later (and its cache/provider packages) ships under the Six Labors Split License. SkiaSharp has no drop-in middleware: move resizing into your own endpoint that calls SKBitmap.Resize and SKImage.Encode."},
{"id": "ISM005", "sev": "error", "kind": "float", "pkg": "^SixLabors\\.", "fix": "pin SkiaSharp, drop the float", "tail": true,
"msg": "Floating or open-ended Six Labors version: NuGet resolves it to the newest release, which is under the Six Labors Split License (ImageSharp 4.x, Fonts 3.x today). Pin an exact version or move to SkiaSharp."},
{"id": "ISM006", "sev": "info", "kind": "below", "pkg": "^SixLabors\\.(ImageSharp|ImageSharp\\.Drawing|Fonts|ImageSharp\\.Web(\\..+)?)$", "fix": "pin below the licence line or move to SkiaSharp",
"msg": "This Six Labors version is still Apache-2.0, but the next major is under the Six Labors Split License. An automated dependency update PR can cross that line; pin it (for example a Dependabot ignore rule) or plan the SkiaSharp move."},
{"id": "ISM007", "sev": "error", "kind": "sdc", "pkg": "^System\\.Drawing\\.Common$", "fix": "SkiaSharp + SkiaSharp.NativeAssets.Linux",
"msg": "System.Drawing.Common 6.0.0 and later is supported on Windows only; on Linux and macOS it throws at run time. This project targets a non-Windows framework. Move to SkiaSharp with SkiaSharp.NativeAssets.Linux."},
{"id": "ISM008", "sev": "warning", "kind": "skia_native", "pkg": "^SkiaSharp$", "fix": "add SkiaSharp.NativeAssets.Linux.NoDependencies",
"msg": "SkiaSharp is referenced without SkiaSharp.NativeAssets.Linux or SkiaSharp.NativeAssets.Linux.NoDependencies. In a Linux container the native libSkiaSharp is missing and the first SKBitmap call fails with DllNotFoundException."},
{"id": "ISM009", "sev": "error", "kind": "skia_mismatch", "pkg": "^SkiaSharp\\.NativeAssets\\.", "fix": "same version as SkiaSharp",
"msg": "SkiaSharp native assets version differs from the SkiaSharp package version. SkiaSharp checks the native libSkiaSharp version at load and refuses an incompatible one. Use the same version for both."},
{"id": "ISM010", "sev": "warning", "kind": "code", "re": "^\\s*using\\s+(static\\s+)?SixLabors\\.(ImageSharp|Fonts)[\\w.]*\\s*;", "fix": "using SkiaSharp;",
"msg": "Six Labors namespace import. The SkiaSharp equivalent is `using SkiaSharp;`."},
{"id": "ISM011", "sev": "warning", "kind": "code", "gate": true, "re": "\\bImage\\.(Load|LoadAsync)(\u003c\\w+\u003e)?\\s*\\(", "fix": "SKBitmap.Decode(stream)",
"msg": "ImageSharp Image.Load call. The SkiaSharp equivalent is SKBitmap.Decode(stream) or SKImage.FromEncodedData(data)."},
{"id": "ISM012", "sev": "warning", "kind": "code", "gate": true, "re": "\\.Mutate\\s*\\(", "fix": "SKBitmap.Resize / SKCanvas",
"msg": "ImageSharp Mutate pipeline. In SkiaSharp resize with SKBitmap.Resize(new SKImageInfo(w, h), SKSamplingOptions) and draw on an SKCanvas."},
{"id": "ISM013", "sev": "warning", "kind": "code", "gate": true, "re": "\\.SaveAs(Jpeg|Png|Webp|Gif|Bmp)(Async)?\\s*\\(", "fix": "SKImage.Encode(format, quality)",
"msg": "ImageSharp SaveAs call. In SkiaSharp use SKImage.FromBitmap(bmp).Encode(SKEncodedImageFormat.Jpeg, quality) and write the SKData to the stream."}
]
;</script>
<script>/* SkiaSharp migration check — shared engine (VS Code + web page). */
(function () {
var DOC = (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined') ? require('./rules.json')
: (typeof window !== 'undefined' ? window.ISM_RULES : []);
var RULES = Array.isArray(DOC) ? DOC : (DOC && DOC.rules) || [];
var SPLIT = Date.UTC(2023, 2, 1); // SixLabors.ImageSharp 3.0.0 published on nuget.org
function splitDays(today) {
var m = /(\d{4})-(\d{2})-(\d{2})/.exec(String(today || ''));
if (!m) return null;
var t = Date.UTC(+m[1], +m[2] - 1, +m[3]);
if (isNaN(t) || t < SPLIT) return null;
return Math.round((t - SPLIT) / 86400000);
}
// Blank XML comments char-for-char so offsets (and line numbers) stay put.
function blankComments(s) {
return s.replace(/<!--[\s\S]*?-->/g, function (c) { return c.replace(/[^\n]/g, ' '); });
}
function lineAt(s, i) { return s.slice(0, i).split('\n').length; }
function attr(a, names) {
for (var k = 0; k < names.length; k++) {
var m = new RegExp('\\b' + names[k] + '\\s*=\\s*"([^"]*)"', 'i').exec(a);
if (m) return m[1].trim();
}
return null;
}
function major(v) { var m = /^\s*\[?\s*(\d+)/.exec(v || ''); return m ? +m[1] : null; }
function floating(v) { return /\*/.test(v) || /^[\[(]\s*[^,\])]*,\s*\)$/.test(v); }
function packages(src) {
var out = [], re = /<(PackageReference|PackageVersion|package)\b([^>]*?)(\/>|>([\s\S]*?)<\/\1\s*>)/g, m;
while ((m = re.exec(src))) {
var name = attr(m[2], ['Include', 'Update', 'id']);
if (!name) continue;
var ver = attr(m[2], ['VersionOverride', 'Version', 'version']);
if (!ver && m[4]) { var c = /<(?:VersionOverride|Version)>\s*([^<]+?)\s*<\//.exec(m[4]); if (c) ver = c[1]; }
out.push({ name: name, ver: ver, line: lineAt(src, m.index), text: m[0].replace(/\s+/g, ' ').trim() });
}
return out;
}
function nonWindowsTfm(src) {
var m = /<TargetFrameworks?>\s*([^<]+?)\s*<\/TargetFrameworks?>/i.exec(src);
if (!m) return false;
return m[1].split(';').some(function (t) { t = t.trim(); var n = /^net(\d+)\.\d/.exec(t); return n && +n[1] >= 6 && !/-windows/i.test(t); });
}
function check(text, opts) {
opts = opts || {};
var raw = String(text || '').replace(/\r\n?/g, '\n'), src = blankComments(raw);
var days = splitDays(opts.today), findings = [];
var tail = days !== null ? ' ImageSharp 3.0.0 has been under the Split License for ' + days + ' days as of ' + String(opts.today).slice(0, 10) + '.' : '';
var pk = packages(src), skia = pk.filter(function (p) { return p.name === 'SkiaSharp'; })[0];
function add(r, p, extra) {
findings.push({ check: r.id, sev: r.sev, msg: r.msg + (r.tail ? tail : '') + (extra || ''), line: p.line, fix: r.fix, text: p.text });
}
pk.forEach(function (p) {
var isFloat = p.ver && floating(p.ver), mj = major(p.ver), hitPkg = false;
RULES.forEach(function (r) {
if (!r.pkg || !new RegExp(r.pkg).test(p.name)) return;
if (r.kind === 'float' && isFloat) add(r, p, ' Found: ' + p.name + ' ' + p.ver + '.');
if (r.kind === 'pkg' && !isFloat && mj !== null && mj >= r.line_major) { hitPkg = true; add(r, p, ' Found: ' + p.name + ' ' + p.ver + '.'); }
if (r.kind === 'sdc' && mj !== null && mj >= 6 && nonWindowsTfm(src)) add(r, p);
if (r.kind === 'skia_native' && !pk.some(function (q) { return /^SkiaSharp\.NativeAssets\.Linux/.test(q.name); })) add(r, p);
if (r.kind === 'skia_mismatch' && skia && skia.ver && p.ver && skia.ver !== p.ver) add(r, p, ' SkiaSharp ' + skia.ver + ' vs ' + p.name + ' ' + p.ver + '.');
});
if (!hitPkg && !isFloat && mj !== null) RULES.forEach(function (r) {
if (r.kind !== 'below' || !new RegExp(r.pkg).test(p.name)) return;
var line = RULES.filter(function (x) { return x.kind === 'pkg' && new RegExp(x.pkg).test(p.name); })[0];
if (line && mj < line.line_major) add(r, p, ' Found: ' + p.name + ' ' + p.ver + ' (licence line at ' + line.line_major + '.0.0).');
});
});
// C# source rules, line by line; call-site rules only in files that import Six Labors.
var lines = src.split('\n'), usesSix = /^\s*using\s+(static\s+)?SixLabors\./m.test(src);
lines.forEach(function (l, i) {
var s = l.replace(/\/\/.*$/, '');
RULES.forEach(function (r) {
if (r.kind !== 'code' || (r.gate && !usesSix)) return;
if (new RegExp(r.re).test(s)) findings.push({ check: r.id, sev: r.sev, msg: r.msg, line: i + 1, fix: r.fix, text: l.trim() });
});
});
findings.sort(function (a, b) { return a.line - b.line; });
return { findings: findings, split_days: days };
}
var api = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };
if (typeof module !== 'undefined' && module.exports) module.exports = api;
if (typeof window !== 'undefined') window.ISMENGINE = api;
})();
</script>
<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
'use strict';
function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }
function summaryLine(res) {
const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
}
function toText(res, label) {
const f = (res && res.findings) || [];
const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });
return lines.join('\n');
}
function toHtml(res) {
const f = (res && res.findings) || [];
if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
}
var ISMREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
if (typeof module !== 'undefined' && module.exports) module.exports = ISMREPORT;
else window.ISMREPORT = ISMREPORT;
</script>
<script>
(function(){
var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
today.value=new Date().toISOString().slice(0,10);
function run(){ try { var res=window.ISMENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.ISMREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
go.onclick=run; if (src.value.trim()) run();
})();
</script>
<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://open-vsx.org/extension/readystack/skiasharp-migration-check" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'skiasharp-migration-check',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/team" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind SkiaSharp Migration Check for ImageSharp every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"skiasharp-migration-check",lang:"en",source:"rule_alert"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);document.addEventListener("click",function(ev){var b=ev.target&&ev.target.closest?ev.target.closest("button,input[type=submit]"):null;if(b&&!b.closest("[data-yj],[data-yj-cta],[data-yj-install],[data-yj-alert],.yj-find,.yj-related,#yj-ask,.yjp"))mv(ev);},true);})();</script></section>
<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the full version <span class="yj-price">$29</span></h2><p class="yj-cta-paid" style="margin:.25rem 0 .6rem;color:#1f2a37">Scan every project in the solution at once and export one Markdown migration checklist for the licence review ticket.</p><p class="yj-cta-pay" style="margin:.25rem 0 1rem;color:#5b6b7c;font-size:.94rem">One payment, one licence key for this tool. The key is shown right after payment.</p><p class="yj-cta-anchor" style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">Staying on ImageSharp means a Six Labors commercial licence from 799 USD a year for up to 10 developers.</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_YcaDEvXkb3Zm6D3jJ1CvVhhH5g7TlGbOkPleD3kLj0j" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
<!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script>
<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div><section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-29">Updated 2026-09-29</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-29","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku401044_result_card.jpg" alt="SkiaSharp Migration Check for ImageSharp" loading="lazy" style="max-width:100%;border-radius:6px"></p>
<p>skiasharp migration: 6 findings in one 16-line .csproj. That is what a .NET team at a company with 1M USD or more annual revenue gets back when the project file of a Linux-hosted thumbnail API is checked against the Six Labors Split License.</p>
<h3>What Six Labors changed, and when</h3>
<p>SixLabors.ImageSharp 3.0.0 was published on nuget.org on 2023-03-01. Its licence changed from Apache-2.0 to the Six Labors Split License. The same switch happened at SixLabors.Fonts 2.0.0, SixLabors.ImageSharp.Drawing 2.0.0 and SixLabors.ImageSharp.Web 3.0.0. On 2026-09-29 that is 1308 days.</p>
<p>The Split License keeps Apache-2.0 terms for open source or source-available software, for transitive dependencies, for non-profits and registered charities, and for for-profit companies with less than 1M USD annual gross revenue. A company above that line that installs the package directly needs a commercial licence. Six Labors publishes 799 USD a year for up to 10 developers.</p>
<p>SkiaSharp is MIT licensed.</p>
<h3>The project file</h3>
<pre><code><Project Sdk="Microsoft.NET.Sdk.Web">
<!-- Thumbnail API for the product catalogue, deployed as a Linux container -->
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />
<PackageReference Include="SixLabors.Fonts" Version="2.1.3" />
<PackageReference Include="SixLabors.ImageSharp.Web" Version="3.2.0" />
<PackageReference Include="SixLabors.ImageSharp.Web.Providers.AWS" Version="*" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
</ItemGroup>
</Project></code></pre>
<p>The check returns six findings:</p>
<ul><li>L8 ISM001: SixLabors.ImageSharp 3.1.12 → SkiaSharp 3.119.4</li><li>L9 ISM002: SixLabors.ImageSharp.Drawing 2.1.7 → SKCanvas + SKPath</li><li>L10 ISM003: SixLabors.Fonts 2.1.3 → SKFont + SkiaSharp.HarfBuzz</li><li>L11 ISM004: SixLabors.ImageSharp.Web 3.2.0 → your own resize endpoint on SkiaSharp</li><li>L12 ISM005: SixLabors.ImageSharp.Web.Providers.AWS * → pin, drop the float</li><li>L13 ISM007: System.Drawing.Common 8.0.0 on net8.0 → SkiaSharp + NativeAssets.Linux</li></ul>
<p>Serilog is not flagged. A <code>*</code> version resolves to the newest release, which today is under the Split License. System.Drawing.Common 6+ is Windows-only, so it throws in a Linux container.</p>
<h3>Why a version list is not enough</h3>
<p><code>dotnet list package</code> prints requested and resolved versions. It never prints a licence. An automated update PR from ImageSharp 2.1.x to 3.x changes one number in the diff, and the licence line sits at a different major for each package: 3 for ImageSharp and Web, 2 for Drawing and Fonts.</p>
<h3>The 13 rules</h3>
<p>Four licence-line package rules, one for floating versions, one info rule for Apache-2.0 versions one major below the line, one for System.Drawing.Common on non-Windows targets, two for SkiaSharp native assets (missing or mismatched), and four C# rules: <code>using SixLabors.ImageSharp</code>, <code>Image.Load</code>, <code>.Mutate</code> and <code>.SaveAsJpeg</code>, each with its SkiaSharp call.</p>
<h3>Try it on your own file</h3>
<p>The free web page and the VS Code extension use the same engine. Paste one .csproj, Directory.Packages.props, packages.config or .cs file and every Split License line comes back with its SkiaSharp fix; the SkiaSharp version of the project above returns 0 findings. A licence key adds a whole-solution scan and one Markdown migration checklist for the licence review ticket.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku401044_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku401044_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does SkiaSharp Migration Check do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads .csproj, Directory.Packages.props, packages.config and .cs files and flags every Six Labors reference under the Six Labors Split License: ImageSharp 3.0.0+, ImageSharp.Drawing 2.0.0+, Fonts 2.0.0+, ImageSharp.Web 3.0.0+ and floating versions. Each finding names the SkiaSharp (MIT) replacement. It runs 13 rules, including System.Drawing.Common on Linux targets and missing SkiaSharp native assets.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is this for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">.NET developers and tech leads at for-profit companies with 1M USD or more annual gross revenue that reference ImageSharp directly, for example a thumbnail API or a PDF renderer running in a Linux container. Under the Six Labors Split License that direct reference needs a commercial licence, so these teams either pay Six Labors or move image code to SkiaSharp.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just run dotnet list package or ask a chatbot?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">dotnet list package prints requested and resolved versions, never the licence, and an automated dependency update from ImageSharp 2.1.x to 3.x changes only a version number in the diff. The licence line sits at different majors per package: ImageSharp 3, Drawing 2, Fonts 2, Web 3. The check knows each line and names the SkiaSharp replacement for every package and call.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs a licence key?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Checking one file is free and complete: open a project file or .cs file in VS Code, or paste it on the web page, and every Split License line appears with its SkiaSharp fix. A licence key, one payment, adds scanning every project in the solution at once and exporting one Markdown migration checklist for the licence review ticket.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does staying on ImageSharp cost?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Six Labors publishes commercial licence tiers of 799 USD a year for up to 10 developers, 1299 USD a year for 11 to 20 developers and 4999 USD a year for unlimited developers, or 80, 130 and 520 USD a month. SkiaSharp is MIT licensed, so moving the image code removes that recurring cost for companies above the revenue line.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does SkiaSharp Migration Check do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads .csproj, Directory.Packages.props, packages.config and .cs files and flags every Six Labors reference under the Six Labors Split License: ImageSharp 3.0.0+, ImageSharp.Drawing 2.0.0+, Fonts 2.0.0+, ImageSharp.Web 3.0.0+ and floating versions. Each finding names the SkiaSharp (MIT) replacement. It runs 13 rules, including System.Drawing.Common on Linux targets and missing SkiaSharp native assets."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": ".NET developers and tech leads at for-profit companies with 1M USD or more annual gross revenue that reference ImageSharp directly, for example a thumbnail API or a PDF renderer running in a Linux container. Under the Six Labors Split License that direct reference needs a commercial licence, so these teams either pay Six Labors or move image code to SkiaSharp."}}, {"@type": "Question", "name": "Why not just run dotnet list package or ask a chatbot?", "acceptedAnswer": {"@type": "Answer", "text": "dotnet list package prints requested and resolved versions, never the licence, and an automated dependency update from ImageSharp 2.1.x to 3.x changes only a version number in the diff. The licence line sits at different majors per package: ImageSharp 3, Drawing 2, Fonts 2, Web 3. The check knows each line and names the SkiaSharp replacement for every package and call."}}, {"@type": "Question", "name": "What is free and what needs a licence key?", "acceptedAnswer": {"@type": "Answer", "text": "Checking one file is free and complete: open a project file or .cs file in VS Code, or paste it on the web page, and every Split License line appears with its SkiaSharp fix. A licence key, one payment, adds scanning every project in the solution at once and exporting one Markdown migration checklist for the licence review ticket."}}, {"@type": "Question", "name": "What does staying on ImageSharp cost?", "acceptedAnswer": {"@type": "Answer", "text": "Six Labors publishes commercial licence tiers of 799 USD a year for up to 10 developers, 1299 USD a year for 11 to 20 developers and 4999 USD a year for unlimited developers, or 80, 130 and 520 USD a month. SkiaSharp is MIT licensed, so moving the image code removes that recurring cost for companies above the revenue line."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:401044,slug:"skiasharp-migration-check",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/dotnet-eol-support-gate"><span class="yj-rel-t">.NET EOL & CRA Support Window Gate</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ai-model-license-lint"><span class="yj-rel-t">AI Model License Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/almalinux-migration-lint"><span class="yj-rel-t">AlmaLinux Migration Lint — CentOS 7/8</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/brave-search-api-migration-check"><span class="yj-rel-t">Brave Search API Migration Check — Google Custom Search & Bing</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cinc-migration-check"><span class="yj-rel-t">Cinc Migration Check: Chef Infra licence gate lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/conda-channel-license-lint"><span class="yj-rel-t">Conda License Lint: Anaconda defaults channel</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body>
</html>
|