Image.RotateFlip,無損操作 EXIF 方向標籤。Graphics.TranslateTransform/RotateTransform 繪製新 Bitmap。// 掃描支援格式
public static List GetImages(string folder)
{
var exts = new[] { ".jpg", ".jpeg", ".png", ".bmp" };
return Directory.GetFiles(folder)
.Where(f => exts.Contains(Path.GetExtension(f).ToLower()))
.ToList();
}
// 循環索引邏輯
private int CurrentIndex { get; set; }
private List ImageFiles { get; set; }
private void ShowImage(int index)
{
if (index < 0) index = ImageFiles.Count - 1;
if (index >= ImageFiles.Count) index = 0;
CurrentImage?.Dispose(); // 釋放舊圖,避免 GDI+ 通用錯誤
CurrentImage = Image.FromFile(ImageFiles[index]);
picBox.Image = CurrentImage;
CurrentIndex = index;
Text = $"圖片查看器 - {Path.GetFileName(ImageFiles[index])} ({CurrentIndex + 1}/{ImageFiles.Count})";
}
private void BtnPrev_Click(object s, EventArgs e) => ShowImage(CurrentIndex - 1);
private void BtnNext_Click(object s, EventArgs e) => ShowImage(CurrentIndex + 1);
RotateFlip 直接操作像素資料並更新 EXIF Orientation 標籤,速度極快且無畫質損耗。
// 順時針 90°
private void BtnRotateCw_Click(object s, EventArgs e)
{
CurrentImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
picBox.Image = CurrentImage;
IsModified = true; // 標記需保存
}
// 逆時針 90° (相當於 270°)
private void BtnRotateCcw_Click(object s, EventArgs e)
{
CurrentImage.RotateFlip(RotateFlipType.Rotate270FlipNone);
picBox.Image = CurrentImage;
IsModified = true;
}
// 水平/垂直翻轉
CurrentImage.RotateFlip(RotateFlipType.RotateNoneFlipX); // 水平鏡像
CurrentImage.RotateFlip(RotateFlipType.RotateNoneFlipY); // 垂直鏡像
需計算旋轉後外接矩形尺寸,避免圖片被裁切。
public static Bitmap RotateImage(Image src, float angleDeg, Color backColor)
{
double rad = angleDeg * Math.PI / 180;
double cos = Math.Abs(Math.Cos(rad));
double sin = Math.Abs(Math.Sin(rad));
int newW = (int)(src.Width * cos + src.Height * sin);
int newH = (int)(src.Width * sin + src.Height * cos);
var dest = new Bitmap(newW, newH);
dest.SetResolution(src.HorizontalResolution, src.VerticalResolution);
using (Graphics g = Graphics.FromImage(dest))
{
g.Clear(backColor);
g.TranslateTransform(newW / 2f, newH / 2f); // 移至中心
g.RotateTransform(angleDeg);
g.TranslateTransform(-src.Width / 2f, -src.Height / 2f); // 移回左上
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(src, 0, 0, src.Width, src.Height);
}
return dest;
}
// 使用範例
private void BtnRotateFree_Click(object s, EventArgs e)
{
var newImg = RotateImage(CurrentImage, 45f, Color.White);
CurrentImage.Dispose();
CurrentImage = newImg;
picBox.Image = CurrentImage;
IsModified = true;
}
private void Form_FormClosed(object s, FormClosedEventArgs e)
{
if (!IsModified || string.IsNullOrEmpty(CurrentPath)) return;
try
{
var ext = Path.GetExtension(CurrentPath).ToLower();
ImageFormat fmt = ext switch
{
".png" => ImageFormat.Png,
".jpg" or ".jpeg" => ImageFormat.Jpeg,
_ => ImageFormat.Bmp
};
CurrentImage.Save(CurrentPath, fmt);
}
catch (Exception ex)
{
MessageBox.Show($"保存失敗:{ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
CurrentImage?.Dispose();
}
}
picBox.SizeMode = PictureBoxSizeMode.Zoom 保持比例適應;提供 Actual Size 切換至 100%。Task.Run(() => Image.FromFile(path)) 配合 await 載入縮圖先顯示。PropertyItem.Id == 0x0112 (Orientation),載入時自動 RotateFlip 校正。ProcessCmdKey。