Files
PDFPatcher/App/Processor/Mupdf/PixmapData.cs
T
2022-01-06 09:08:16 +08:00

226 lines
6.8 KiB
C#

using System;
using System.Drawing;
using System.Drawing.Imaging;
using FreeImageAPI;
using CC = System.Runtime.InteropServices.CallingConvention;
using DllImport = System.Runtime.InteropServices.DllImportAttribute;
namespace MuPdfSharp
{
internal sealed class PixmapData : IDisposable
{
readonly ContextHandle _context;
readonly PixmapHandle _pixmap;
public PixmapData(ContextHandle context, PixmapHandle pixmap) {
Width = NativeMethods.GetWidth(context, pixmap);
Height = NativeMethods.GetHeight(context, pixmap);
Components = NativeMethods.GetComponents(context, pixmap);
Samples = NativeMethods.GetSamples(context, pixmap);
_context = context;
_pixmap = pixmap;
}
public int Width { get; private set; }
public int Height { get; private set; }
public int Components { get; private set; }
/// <summary>获取指向 Pixmap 数据内容的指针。</summary>
public IntPtr Samples { get; private set; }
/// <summary>获取 Pixmap 的边框。</summary>
public BBox BBox => NativeMethods.GetBBox(_context, _pixmap);
/// <summary>number of colorants (components, less any spots and alpha)。</summary>
public int Colorants => NativeMethods.GetColorants(_context, _pixmap);
/// <summary>number of spots (components, less colorants and alpha). Does not throw exceptions.。</summary>
public int Spots => NativeMethods.GetColorants(_context, _pixmap);
/// <summary>获取 Pixmap 一行像素的字节数。</summary>
public int Stride => NativeMethods.GetStride(_context, _pixmap);
/// <summary>
/// 将 Pixmap 的数据转换为 <see cref="Bitmap"/>。
/// </summary>
public unsafe Bitmap ToBitmap(ImageRendererOptions options) {
int width = Width;
int height = Height;
bool grayscale = options.ColorSpace == ColorSpace.Gray;
bool invert = options.InvertColor;
var bmp = new Bitmap(width, height, grayscale ? PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb);
var imageData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bmp.PixelFormat);
var ptrSrc = (byte*)Samples;
var ptrDest = (byte*)imageData.Scan0;
if (grayscale) {
var palette = bmp.Palette;
for (int i = 0; i < 256; ++i)
palette.Entries[i] = Color.FromArgb(i, i, i);
bmp.Palette = palette;
for (int y = 0; y < height; y++) {
var pl = ptrDest;
var sl = ptrSrc;
for (int x = 0; x < width; x++) {
*pl = invert ? (byte)(*sl ^ 0xFF) : *sl;
pl++;
sl++;
}
ptrDest += imageData.Stride;
ptrSrc = sl;
}
}
else { // DeviceBGR
for (int y = 0; y < height; y++) {
var pl = ptrDest;
var sl = ptrSrc;
if (invert) {
for (int x = 0; x < width; x++) {
// 在这里进行 RGB 到 DIB BGR 的转换(省去 Mupdf 内部的转换工作)
pl[2] = (byte)(*sl ^ 0xFF); sl++; // R
pl[1] = (byte)(*sl ^ 0xFF); sl++; // G
pl[0] = (byte)(*sl ^ 0xFF); sl++; // B
pl += 3;
}
}
else {
for (int x = 0; x < width; x++) {
// 在这里进行 RGB 到 DIB BGR 的转换(省去 Mupdf 内部的转换工作)
pl[2] = *sl; sl++; // R
pl[1] = *sl; sl++; // G
pl[0] = *sl; sl++; // B
pl += 3;
}
}
ptrDest += imageData.Stride;
ptrSrc = sl;
}
}
bmp.UnlockBits(imageData);
if (options.Dpi > 0) {
bmp.SetResolution(options.Dpi, options.Dpi);
}
return bmp;
}
/// <summary>
/// 将 Pixmap 的数据转换为 <see cref="FreeImageBitmap"/>。
/// </summary>
public unsafe FreeImageBitmap ToFreeImageBitmap(ImageRendererOptions options) {
int width = Width;
int height = Height;
bool grayscale = options.ColorSpace == ColorSpace.Gray;
bool invert = options.InvertColor;
var bmp = new FreeImageBitmap(width, height, grayscale ? PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb);
var ptrSrc = (byte*)Samples;
if (grayscale) {
bmp.Palette.CreateGrayscalePalette();
for (int y = height - 1; y >= 0; y--) {
var pDest = bmp.GetScanlinePointer(y);
var pl = (byte*)pDest.ToPointer();
var sl = ptrSrc;
for (int x = 0; x < width; x++) {
*pl = invert ? (byte)(*sl ^ 0xFF) : *sl;
pl++;
sl++;
}
ptrSrc = sl;
}
}
else { // DeviceBGR
for (int y = height - 1; y >= 0; y--) {
var pDest = bmp.GetScanlinePointer(y);
var pl = (byte*)pDest.ToPointer();
var sl = ptrSrc;
if (invert) {
for (int x = 0; x < width; x++) {
// 在这里进行 RGB 到 DIB BGR 的转换(省去 Mupdf 内部的转换工作)
pl[2] = (byte)(*sl ^ 0xFF); sl++; // R
pl[1] = (byte)(*sl ^ 0xFF); sl++; // G
pl[0] = (byte)(*sl ^ 0xFF); sl++; // B
pl += 3;
}
}
else {
for (int x = 0; x < width; x++) {
// 在这里进行 RGB 到 DIB BGR 的转换(省去 Mupdf 内部的转换工作)
pl[2] = *sl; sl++; // R
pl[1] = *sl; sl++; // G
pl[0] = *sl; sl++; // B
pl += 3;
}
}
ptrSrc = sl;
}
}
bmp.SetResolution(options.Dpi, options.Dpi);
return bmp;
}
/// <summary>
/// 反转 Pixmap 的颜色。
/// </summary>
public void Invert() {
NativeMethods.InvertPixmap(_context, _pixmap);
}
/// <summary>
/// 为 Pixmap 蒙上色层。
/// </summary>
/// <param name="color">需要蒙上的颜色。</param>
public void Tint(Color color) {
NativeMethods.TintPixmap(_context, _pixmap, 0, color.ToArgb());
}
/// <summary>
/// 对 Pixmap 执行 Gamma 校正。
/// </summary>
/// <param name="gamma">需要应用的 Gamma 值。1.0 表示不更改。</param>
public void Gamma(float gamma) {
if (gamma == 1) {
return;
}
NativeMethods.GammaPixmap(_context, _pixmap, gamma);
}
/// <summary>
/// 获取 Pixmap 内的数据。
/// </summary>
/// <returns>字节数组。</returns>
public byte[] GetSampleBytes() {
if (Samples == IntPtr.Zero) {
return null;
}
var d = new byte[Width * Height * Components];
System.Runtime.InteropServices.Marshal.Copy(Samples, d, 0, d.Length);
return d;
}
#region 实现 IDisposable 接口的属性和方法
private bool disposed = false;
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this); // 抑制析构函数
}
/// <summary>释放由 MuPdfPage 占用的资源。</summary>
/// <param name="disposing">是否手动释放托管资源。</param>
void Dispose(bool disposing) {
if (!disposed) {
if (disposing) {
#region 释放托管资源
//_components.Dispose ();
#endregion
}
#region 释放非托管资源
// 注意这里不是线程安全的
_pixmap.DisposeHandle();
#endregion
}
disposed = true;
}
// 析构函数只在未调用 Dispose 方法时调用
// 派生类中不必再提供析构函数
~PixmapData() {
Dispose(false);
}
#endregion
}
}