diff --git a/next.config.js b/next.config.js index e6e9176..bcb12c7 100644 --- a/next.config.js +++ b/next.config.js @@ -1,10 +1,11 @@ const remarkMath = require("remark-math"); const rehypeKatex = require("rehype-katex"); const rehypePrism = require("@mapbox/rehype-prism"); +var footnotes = require("remark-footnotes"); const withMDX = require("@next/mdx")({ extension: /\.mdx?$/, options: { - remarkPlugins: [remarkMath], + remarkPlugins: [remarkMath, footnotes], rehypePlugins: [rehypeKatex, rehypePrism], }, }); diff --git a/package-lock.json b/package-lock.json index f9e1425..d213dab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -717,6 +717,14 @@ "unified": "9.2.0", "unist-builder": "2.0.3", "unist-util-visit": "2.0.3" + }, + "dependencies": { + "remark-footnotes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", + "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==", + "dev": true + } } }, "@mdx-js/react": { @@ -887,8 +895,7 @@ "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", - "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", - "dev": true + "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" }, "@webassemblyjs/ast": { "version": "1.9.0", @@ -1816,20 +1823,17 @@ "character-entities": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "dev": true + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==" }, "character-entities-legacy": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "dev": true + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" }, "character-reference-invalid": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "dev": true + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==" }, "chokidar": { "version": "3.4.3", @@ -2339,7 +2343,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -3714,14 +3717,12 @@ "is-alphabetical": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==" }, "is-alphanumerical": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, "requires": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" @@ -3780,8 +3781,7 @@ "is-decimal": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==" }, "is-descriptor": { "version": "0.1.6", @@ -3836,8 +3836,7 @@ "is-hexadecimal": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "dev": true + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" }, "is-number": { "version": "7.0.0", @@ -4055,6 +4054,11 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", "dev": true }, + "longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4140,6 +4144,15 @@ "unist-util-visit": "^2.0.0" } }, + "mdast-util-footnote": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/mdast-util-footnote/-/mdast-util-footnote-0.1.7.tgz", + "integrity": "sha512-QxNdO8qSxqbO2e3m09KwDKfWiLgqyCurdWTQ198NpbZ2hxntdc+VKS4fDJCmNWbAroUdYnSthu+XbZ8ovh8C3w==", + "requires": { + "mdast-util-to-markdown": "^0.6.0", + "micromark": "~2.11.0" + } + }, "mdast-util-to-hast": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", @@ -4156,6 +4169,24 @@ "unist-util-visit": "^2.0.0" } }, + "mdast-util-to-markdown": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.1.tgz", + "integrity": "sha512-4qJtZ0qdyYeexAXoOZiU0uHIFVncJAmCkHkSluAsvDaVWODtPyNEo9I1ns0T4ulxu2EHRH5u/bt1cV0pdHCX+A==", + "requires": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + } + }, + "mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==" + }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", @@ -4210,6 +4241,23 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "micromark": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.2.tgz", + "integrity": "sha512-IXuP76p2uj8uMg4FQc1cRE7lPCLsfAXuEfdjtdO55VRiFO1asrCSQ5g43NmPqFtRwzEnEhafRVzn2jg0UiKArQ==", + "requires": { + "debug": "^4.0.0", + "parse-entities": "^2.0.0" + } + }, + "micromark-extension-footnote": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/micromark-extension-footnote/-/micromark-extension-footnote-0.3.2.tgz", + "integrity": "sha512-gr/BeIxbIWQoUm02cIfK7mdMZ/fbroRpLsck4kvFtjbzP4yi+OPVbnukTc/zy0i7spC2xYE/dbX1Sur8BEDJsQ==", + "requires": { + "micromark": "~2.11.0" + } + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -4451,8 +4499,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "nan": { "version": "2.14.2", @@ -4987,7 +5034,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dev": true, "requires": { "character-entities": "^1.0.0", "character-entities-legacy": "^1.0.0", @@ -5710,10 +5756,13 @@ } }, "remark-footnotes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", - "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-3.0.0.tgz", + "integrity": "sha512-ZssAvH9FjGYlJ/PBVKdSmfyPc3Cz4rTWgZLI4iE/SX8Nt5l3o3oEjv3wwG5VD7xOjktzdwp5coac+kJV9l4jgg==", + "requires": { + "mdast-util-footnote": "^0.1.0", + "micromark-extension-footnote": "^0.3.0" + } }, "remark-math": { "version": "3.0.1", @@ -5786,8 +5835,7 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, "resolve": { "version": "1.17.0", @@ -7818,8 +7866,7 @@ "zwitch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", - "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", - "dev": true + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==" } } } diff --git a/package.json b/package.json index ef2531e..13cb1ca 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "latex-tailwind", "description": "A Tailwind CSS plugin for automatically styling plain HTML content with defaults to look like a LaTeX document", - "version": "1.2.0", + "version": "2.0.0", "license": "MIT", "scripts": { "dev": "next", @@ -30,5 +30,8 @@ "tailwindcss": "^2.0.1", "@mapbox/rehype-prism": "^0.5.0", "latex-tailwind-syntax": "^1.0.0" + }, + "dependencies": { + "remark-footnotes": "^3.0.0" } } diff --git a/pages/index.md b/pages/index.md index 4ff9a22..95e69c9 100644 --- a/pages/index.md +++ b/pages/index.md @@ -31,20 +31,28 @@ module.exports = { Then add `latex-style` to the outermost div you want to have LaTeX style -If you also want to have syntax highlighting with Prism.js then you can use the `latex-tailwind-syntax` plugin by extending your `tailwind.config.js` to look like this +### Options + +There are two options for this plugin, `footnotes` and `syntax`, they can be enabled like so ```js module.exports = { //... - purge: { - //... - layers: ["base", "utilities"], + theme: { + latex: { + footnotes: true, + syntax: true, + }, }, - plugins: [require("latex-tailwind"), require("latex-tailwind-syntax")], + plugins: [require("latex-tailwind")], }; ``` -Excluding components from the layers to purge is important as Tailwind doesn't see the classes created by Prism +Footnotes will only work with some markdown processors, only tested with `remark` and the `remark-footnotes` plugin. This will style the footnotes in a similar way to the rest of the document. It is optional as the `footnotes` class is external to the `div` it is created in, meaning that when enabled, it will apply for all `footnotes` classes in the document. + +Syntax provides syntax highlighting in the style of minted, designed to work with `prism.js`. + +Excluding components from the layers to purge is important as Tailwind doesn't see the classes created by Prism or the footnote generator ## Inspiration @@ -261,4 +269,216 @@ Let's add a closing paragraph here so things end with a decently sized block of What I've written here is probably long enough, but adding this final sentence can't hurt. +# A longer example including footnotes for good measure + +## A description of the non-local means denoising algorithm + +[^1] Non local means denoising uses samples from all +around the image, instead of conventional denoising which will just look +at the area around the given pixel to increase the accuracy of the +colour. The reason it does this is due to the fact that patterns and +shapes will be repeated in images, meaning that there will likely be an +area somewhere else in the image that looks very similar to the patch +around the pixel looking to be corrected. By finding these areas and +taking averages of the pixels in similar areas, the noise will reduce as +the random noise will converge around the true value. + +[^1]: Buades, A., Coll, B., and Morel, J.M. 2005. A Non-Local Algorithm for Image Denoising. In 2005 IEEE Computer Society Conference on Computer Vision and Pattern Recognition (CVPR'05) (pp. 60–65). IEEE. + +So the method by which non-local means runs is to look at many patches +throughout the image, and compare the similarities of those patches with +the patch around the pixel looking to be denoised. This comparison then +allows for assigning a weight to each patch looked at, which are then +used (along with the colour of the pixel in the centre of the patch) in +the calculation of the colour of the pixel to be denoised. + +## Various implementations of the algorithm and their efficiency + +### Pixelwise + +![Visualisation of pixelwise denoising](https://res.cloudinary.com/samrobbins/image/upload/v1600781993/drawing_tgntf0.png "Visualisation of pixelwise denoising") + +[^2]Taking an image u and a pixel in it you want to +denoise, p, you first need to decide a patch size, given by r, as the +dimensions of the patch (blue) are $(2r+1)\times(2r+1)$. You then look +at all the other pixels, $q\in Q$, but as it is intensive to do the +calculations, specifying a research zone (red) allows you to make the +processing faster as fewer comparisons have to be done. When looking at +the other pixels, calculate their patch of the same size as the patch of +p, then compare each pixel in the patch of q with the corresponding +pixel in the patch of p. This similarity is then used to compute the +similarity between the patch around p and the patch around q, and a +weighting is given to q to describe this. These weightings are then +averaged with the colours of the pixels to provide a more accurate +representation of the pixel. + +[^2]: Buades, A., Coll, B., and Morel, J.M. 2011. Non-Local Means Denoising. Image Processing On Line, 1. + +### Patchwise + +[^2] The main way in which patchwise differs from +pixelwise is in the formulation of the weighting, as you can see below + +$$C(p)=\sum_{q \in B(p, r)} w(p, q)$$ + +$$C=\sum_{Q=Q(q, f) \in B(p, r)} w(B, Q)$$ + +By calculating weights for pixels instead of patches we can make one +calculation per patch, therefore not needing to do $(2f+1)^2$ +calculations per pixel, providing a large increase in performance. The +overall quality of the two methods are the same, and so the patchwise +method is preferred as it has no drawbacks for an improvement in speed. + +## The strengths and limitations of non-local means compared to other denoising algorithms + +### Method noise + +[^3]**Definition (method noise)**. Let u be a (not +necessarily noisy) image and $D_h$ a denoising operator depending on h. +Then we define the method noise of u as the image difference + +$$ +n(D_h,u)=u-D_h(u) +$$ + +This method noise should be as similar to white +noise as possible. The image below is sourced from Buades, A., Coll, B., and Morel, J. 2005 [^3] + +[^3]: Buades, A., Coll, B., and Morel, J. 2005. A Review of Image Denoising Algorithms, with a New One. Multiscale Modeling & Simulation, 4(2), p.490–530. + +![image](https://res.cloudinary.com/samrobbins/image/upload/v1600781986/method_noise_lhu9zs.png) + +From left to right and from top to bottom: original image,Gaussian +convolution, mean curvature motion, total variation, Tadmor–Nezzar–Vese +iterated total variation, Osher et al. total variation, neighborhood +filter, soft TIWT, hard TIWT, DCT empirical Wiener filter, and the +NL-means algorithm. + +You can see that the NL means algorithm is closest to white noise, as it +is very difficult to make out the original image from the method noise, +and so is the best in this area + +### Mean square error + +[^4]The mean square error measures the average squared +difference between the estimated values and what is estimated. In images +this acts as a measure of how far from the true image the denoised image +is. These results are taken from Buades, A., Coll, B., and Morel, J. 2005 [^3] + +[^4]: Machine learning: an introduction to mean squared error and regression lines. URL https://www.freecodecamp.org/news/machine-learning-mean-squared-error-regression-line-c7dde9a26b93/. + +![image](https://res.cloudinary.com/samrobbins/image/upload/v1600781984/mean_eewg2j.png) + +Here it can be seen that the NL-means algorithm gives images that are +closest to the true image, and so performs best for image denoising +under this measurement. + +## The influence of the algorithmic parameters on the output + +In the following images I am changing the values of h, the template +window size and the search window size, from a standard set at h=5, +template window size=7 and search window size =21. I will adjust each +one in turn to show the differences yielded by changing them. + +![h=2](https://res.cloudinary.com/samrobbins/image/upload/v1600781994/h2_zk03fm.png "h=2") + +![h=10](https://res.cloudinary.com/samrobbins/image/upload/v1600781996/h10_vmlxaf.png "h=10") + +![template=2](https://res.cloudinary.com/samrobbins/image/upload/v1600781996/h10_vmlxaf.png "template width = 2") + +![template=10](https://res.cloudinary.com/samrobbins/image/upload/v1600781991/template15_s8c518.png "template width = 10") + +![search=10](https://res.cloudinary.com/samrobbins/image/upload/v1600781993/search10_bzpgw4.png "search window size = 10") + +![search=30](https://res.cloudinary.com/samrobbins/image/upload/v1600781995/search30_uwv1vx.png "search window size = 30") + +By adjusting the value of h you get a large change in the amount of +smoothing, although a large amount of noise is still present. Increasing +the value of h does increase the PSNR from 28.60 to 29.66 + +The effects from adjusting the template width are much more subtle than +that of adjusting h, it can be noticed in the wires overhead that a +larger template width has reduced the detail. An increase in the +template width yields a small reduction in the PSNR from 28.68 to +28.51. + +The effects for the value of the search window are also very subtle, and +again can only be noticed fully in the overhead wires. An increase in +the search window yields a marginal increase in the PSNR from 28.51 to +28.52. + +## Modifications and extensions of the algorithm that have been proposed in the literature + +### Testing stationarity + +[^3] One proposed modification is one to test +stationarity. The original algorithm works under the conditional +expectation process: + +**Theorem** - Conditional Expectation Theorem + +Let $Z_j=\{X_j,Y_j\}$ for $j=1,2,...$ be a strictly stationary and mixing process. For $i\in I$, let $X$ and $Y$ be distributed as $X_i$ and $Y_i$. Let J be a compact subset $J\subset \mathbb{R}^p$ such that + +$$ +\inf\{f_X(x);x\in J\}>0 +$$ + +However this is not true everywhere, as each image may contain +exceptional, non-repeated structures, these would be blurred out by the +algorithm, so the algorithm should have a detection phase and special +treatment of nonstationary points. In order to use this strategy a good +estimate of the mean and variance at every pixel is needed, fortunately +the non-local means algorithm converges to the conditional mean, and the +variance can just be calculated using $EX^2-(EX)^2$ + +### Multiscale version + +Another improvement to make is one to speed up the algorithm, this is +proposed using a multiscale algorithm. + +1. Zoom out the image $u_0$ by a factor of 2. This gives the new image + $u_1$ + +2. Apply the NL means algorithm to $u_1$, so that with each pixel of + $u_1$, a list of windows centered in $(i_1,j_1)...(i_k,j_k)$ is + associated + +3. For each pixel of $u_0$, $(2i+r,2j+s)$ with $r,s\in \{0,1\}$, we + apply the NL means algorithm. However instead of comparing with all + the windows in the search zone, we just compare with the 9 + neighbouring windows of each pixel + +4. This procedure can be applied in a pyramid fashion + +## Applications of the original algorithm and its extensions + +### Medical Imaging + +[^5] It has been proposed that Non-Local means can +be used in X-Ray imaging, allowing for a reduction of noise in the +scans, making them easier to interpret. In CT scans a higher dose can be +given to give a clearer image, but with that is more dangerous, however +by applying the NL means algorithm a lower dose can be given for the +same clarity. It benefits from the improvement stated above to test +stationarity as the the noise and streak artifacts are non stationary. +The original algorithm was also not good at removing the streak +artifacts in low-flux CT images resulting from photon starvation. +However by applying one-dimensional nonlinear diffusion in the +stationary wavelet domain before applying the non-local means algorithm +these could be reduced. + +[^5]: Zhang, H., Zeng, D., Zhang, H., Wang, J., Liang, Z., and Ma, J. 2017. Applications of nonlocal means algorithm in low-dose X-ray CT image processing and reconstruction: A review. Medical Physics, 44(3), p.1168–1185. + +### Video Denoising + +[^6] NLM can also be applied in video denoising, it has +an adaptation as the denoising can be improved by using the data from +sequential frames. In the implementation proposed in the paper, the +current input frame and prior output frame are used to form the current +output frame. In the paper the measurements they make fail to show that +this algorithm is an improvement from current algorithms, however the +algorithm does have much better subjective visual performance. + +[^6]: Ali, R., and Hardie, R. 2017. Recursive non-local means filter for video denoising. EURASIP Journal on Image and Video Processing, 2017(1), p.29. + diff --git a/plugin/index.js b/plugin/index.js index 3c82cc3..df8e4df 100644 --- a/plugin/index.js +++ b/plugin/index.js @@ -16,7 +16,6 @@ const round = (num) => .toFixed(7) .replace(/(\.[0-9]+?)0+$/, "$1") .replace(/\.0$/, ""); -const rem = (px) => `${round(px / 16)}rem`; const em = (px, base) => `${round(px / base)}em`; const base = { @@ -377,61 +376,223 @@ components = { }, }; -module.exports = plugin(function ({ addBase, addUtilities, addComponents }) { - addBase({ - "@font-face": [ - { - "font-family": "'Latin Modern'", - "font-style": "normal", - "font-weight": "normal", - "font-display": "swap", - src: - 'url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-regular.ttf") format("truetype") , url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-regular.woff") format("woff"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-regular.woff2") format("woff2")', - }, - { - "font-family": "'Latin Modern'", - "font-style": "italic", - "font-weight": "normal", - "font-display": "swap", - src: - 'url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-italic.ttf") format("truetype"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-italic.woff") format("woff"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-italic.woff2") format("woff2")', - }, - { - "font-family": "'Latin Modern'", - "font-style": "normal", - "font-weight": "bold", - "font-display": "swap", - src: - 'url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold.ttf") format("truetype"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold.woff") format("woff"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold.woff2") format("woff2")', - }, - { - "font-family": "'Latin Modern'", - "font-style": "italic", - "font-weight": "bold", - "font-display": "swap", - src: - 'url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold-italic.ttf") format("truetype"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold-italic.woff") format("woff"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold-italic.woff2") format("woff2")', - }, - { - "font-family": "'CMU Typewriter Text'", - "font-style": "normal", - "font-weight": "500", - "font-display": "swap", - src: - 'url("https://fonts.cdnfonts.com/s/18083/cmuntt.woff") format("woff")', - }, - ], - ".latex-style": { - fontFamily: "Latin Modern", - lineHeight: "1.8", - maxWidth: "80ch", - margin: "0 auto", - padding: "2rem 1.25rem", - counterReset: "theorem definition sidenote-counter lemma", - color: "hsl(0, 5%, 10%)", +var base_output = { + "@font-face": [ + { + "font-family": "'Latin Modern'", + "font-style": "normal", + "font-weight": "normal", + "font-display": "swap", + src: + 'url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-regular.ttf") format("truetype") , url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-regular.woff") format("woff"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-regular.woff2") format("woff2")', }, - ...prefix(base, ".latex-style "), - }); + { + "font-family": "'Latin Modern'", + "font-style": "italic", + "font-weight": "normal", + "font-display": "swap", + src: + 'url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-italic.ttf") format("truetype"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-italic.woff") format("woff"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-italic.woff2") format("woff2")', + }, + { + "font-family": "'Latin Modern'", + "font-style": "normal", + "font-weight": "bold", + "font-display": "swap", + src: + 'url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold.ttf") format("truetype"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold.woff") format("woff"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold.woff2") format("woff2")', + }, + { + "font-family": "'Latin Modern'", + "font-style": "italic", + "font-weight": "bold", + "font-display": "swap", + src: + 'url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold-italic.ttf") format("truetype"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold-italic.woff") format("woff"), url("https://cdn.jsdelivr.net/gh/vincentdoerig/latex-css/fonts/LM-bold-italic.woff2") format("woff2")', + }, + { + "font-family": "'CMU Typewriter Text'", + "font-style": "normal", + "font-weight": "500", + "font-display": "swap", + src: + 'url("https://fonts.cdnfonts.com/s/18083/cmuntt.woff") format("woff")', + }, + ], + ".latex-style": { + fontFamily: "Latin Modern", + lineHeight: "1.8", + maxWidth: "80ch", + margin: "0 auto", + padding: "2rem 1.25rem", + counterReset: "theorem definition sidenote-counter lemma", + color: "hsl(0, 5%, 10%)", + }, + ...prefix(base, ".latex-style "), +}; + +const footnote_style = { + ".footnotes": { + fontFamily: "Latin Modern", + lineHeight: "1.8", + maxWidth: "80ch", + margin: "0 auto", + padding: "2rem 1.25rem", + counterReset: "theorem definition sidenote-counter lemma", + color: "hsl(0, 5%, 10%)", + }, + ".footnotes ol::before": { + content: "'References'", + fontSize: "1.5rem", + fontWeight: "bold", + }, +}; + +const syntax_base = { + "code[class*='language-'],pre[class*='language-']": { + color: "black", + textAlign: "left", + whiteSpace: "pre", + wordSpacing: "normal", + wordBreak: "normal", + wordWrap: "normal", + lineHeight: "1.5", + tabSize: "4", + hyphens: "none", + }, +}; + +const syntax_components = { + ".token.comment": { + color: "#407f80", + }, + ".token.prolog": { + color: "#407f80", + }, + ".token.doctype": { + color: "#407f80", + }, + ".token.cdata": { + color: "#407f80", + }, + ".token.punctuation": { + color: "#000000", + }, + ".token.constant": { + color: "#000000", + }, + ".token.punctuation.attr-equals": { + color: "#666666", + }, + ".token.number": { + color: "#666666", + }, + ".token.operator": { + color: "#666666", + }, + ".token.namespace": { + opacity: "0.7", + }, + ".token.property": { + color: "#007f00", + }, + ".token.tag": { + color: "#007f00", + }, + ".token.boolean": { + color: "#007f00", + }, + ".token.symbol": { + color: "#007f00", + }, + ".token.deleted": { + color: "#007f00", + }, + ".token.keyword": { + color: "#007f00", + }, + ".token.selector": { + color: "#7d8f29", + }, + ".token.attr-name": { + color: "#7d8f29", + }, + ".token.char": { + color: "#7d8f29", + }, + ".token.builtin": { + color: "#7d8f29", + }, + ".token.inserted": { + color: "#7d8f29", + }, + ".token.entity": { + color: "#9a6e3a", + }, + ".token.url": { + color: "#9a6e3a", + }, + ".language-css .token.string": { + color: "#9a6e3a", + }, + ".style .token.string": { + color: "#9a6e3a", + }, + ".token.atrule": { + color: "#ba2121", + }, + ".token.attr-value": { + color: "#ba2121", + }, + ".token.string": { + color: "#ba2121", + }, + ".token.attr-value .punctuation:not(.attr-equals)": { + color: "#ba2121", + }, + ".token.class-name": { + color: "#dd4a68", + }, + ".token.important": { + color: "#e90", + fontWeight: "bold", + }, + ".token.regex": { + color: "#BA6687", + }, + ".token.bold": { + fontWeight: "bold", + }, + ".token.entity": { + fontStyle: "italic", + }, +}; + +var components_output = prefix(components, ".latex-style "); + +module.exports = plugin(function ({ + addBase, + addUtilities, + addComponents, + theme, +}) { + const options = theme("latex", {}); + if (options["footnotes"]) { + base_output = Object.assign(base_output, prefix(base, ".footnotes ")); + components_output = Object.assign(components_output, footnote_style); + } + if (options["syntax"]) { + base_output = Object.assign( + base_output, + prefix(syntax_base, ".latex-style ") + ); + components_output = Object.assign( + components_output, + prefix(syntax_components, ".latex-style ") + ); + } + + addBase(base_output); addUtilities(prefix(utilities, ".latex-style ")); - addComponents(prefix(components, ".latex-style ")); + addComponents(components_output); }); diff --git a/tailwind.config.js b/tailwind.config.js index 56a64f5..1ed827e 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -3,6 +3,12 @@ module.exports = { content: ["./components/**/*.{js,ts,jsx,tsx}", "./pages/**/*.{js,mdx}"], layers: ["base", "utilities"], }, + theme: { + latex: { + footnotes: true, + syntax: true, + }, + }, variants: {}, - plugins: [require("./plugin"), require("latex-tailwind-syntax")], + plugins: [require("./plugin")], };