Introduzione
Uno dei metodi più comodi e più utilizzati per ottenere thumbnail di immagini dinamicamente
è il metodo GetThumbnailImage() dell'oggetto Image presente nel namespace
System.Drawing, come ripreso anche da Turibbio in uno dei suoi
post.
L'utilizzo di questo metodo pone però alcune limitazioni, come lo stesso msdn afferma:
Il metodo GetThumbnailImage garantisce migliori risultati quando le dimensioni
dell'immagine di anteprima richiesta sono pari a circa 120x120 pixel. Se si richiede
un'immagine di anteprima di grandi dimensioni, ad esempio 300x300, da un oggetto
Image che dispone di un'anteprima incorporata, è possibile che si verifichi una
notevole perdita di qualità dell'immagine dell'anteprima. Potrebbe essere consigliabile
ridimensionare l'immagine principale, anziché ridimensionare l'anteprima incorporata,
chiamando il metodo DrawImage. (1)
Qualche considerazione nata dalla mia esperienza di web developer: il più delle
volte mi è capitato di dover gestire thumbnail che fossero in qualche modo uniformi
nelle dimensioni e nel colore di sfondo. Ho deciso di affrontare entrambi gli aspetti
in modo da approcciare il problema nella sua variegata casistica.
Ho affrontato il problema suddividendolo in due blocchi.
Dapprima viene curato l'aspetto legato al contenitore dell'immagine di output:
è' possibile immaginarlo come il livello di sfondo dell'immagine risultante.
Successivamente viene curato il ridimensionamento dell'immagine e come questa viene
disegnata rispetto al contenitore.
Utilizzare la procedura proposta in questo post per effettuare il ridimensionamento
dell'immagine in input prevederà dunque la definizione delle dimensioni di larghezza
ed altezza desiderate del container, e delle dimensioni di larghezza ed altezza
desiderate dell'immagine ridimensionata, le quali non sempre e non necessariamente
devono combaciare. Per questo motivo, ho definito quattro membri e relative proprietà:
private int _imageWidth;
private int _imageHeight;
private int _containerWidth;
private int _containerHeight;
public int Width
{
get { return _imageWidth; }
set { _imageWidth = value; }
}
public int Height
{
get { return _imageHeight; }
set { _imageHeight = value; }
}
public int ContainerWidth
{
get { return _containerWidth; }
set { _containerWidth = value; }
}
public int ContainerHeight
{
get { return _containerHeight; }
set { _containerHeight = value; }
}
Il modo in cui queste quattro dimensioni interagiscono tra di loro è definito dall'enumerazione
public enum ScaleMode
{
FitContainer,
FitImage,
FitAuto,
NoFit
}
dove:
- FitContainer: forza il ridimensionamento in modo da adeguarsi alle dimensioni
specificate per il contenitore. L'immagine di output avrà le dimensioni specificate
per il contenitore.
- FitImage: effettua il ridimensionamento in base alle dimensioni specificate
per imageWidth e imageHeight, forzando il contenitore ad adeguarsi a queste dimensioni
- FitAuto: esegue un ridimensionamento calcolando in automatico le dimensioni
dell'immagine risultante all'interno del contenitore. L'immagine di output avrà
le dimensioni specificate per il contenitore.
- NoFit: non adegua il ridimensionamento al contenitore. Esegue il ridimensionamento
sull'immagine in base alle dimensioni specificate, effettuando un taglio dell'immagine
qualora questa superi le dimensioni del contenitore. L'immagine di output avrà le
dimensioni specificate per il contenitore. E' possibile gestire la modalità di taglio
con le strutture seguenti:
public enum Position
{
TopLeft,
TopCenter,
TopRight,
MiddleLeft,
MiddleCenter,
MiddleRight,
BottomLeft,
BottomCenter,
BottomRight,
Undefined
}
private int _offsetX;
private int _offsetY;
private Position _drawingPosition;
public int OffsetX
{
get { return _offsetX; }
set { _offsetX = value; }
}
public int OffsetY
{
get { return _offsetY; }
set { _offsetY = value; }
}
public Position DrawingPosition {
get { return _drawingPosition; }
set { _drawingPosition = value; }
}
L'enumerazione Position definisce in che modo l'immagine viene allineata
rispetto al container. E se proprio questo non bastasse è possibile valorizzare
le variabili OffsetX e OffsetY che consentono di avere uno scostamento rispetto
all'origine (l'angolo superiore sinistro del contenitore).
A queste modalità operative si aggiunge il controllo sul ridimensionamento proporzionale,
come si vedrà in seguito.
Per quanto riguarda invece la definizione del colore di sfondo, ho definito due
variabili, la prima è il colore vero e proprio, la seconda l'intensità del canale
alfa/trasparenza. Questi due valori vengono combinati nel metodo GetBackground()
che inoltre effettua un controllo sulla coerenza del valore di Alpha, che ammette
valori compresi tra 0 e 255.
private Color _backgroundColor;
private int _alpha;
public Color BackgroundColor
{
get { return _backgroundColor; }
set { _backgroundColor = value; }
}
public int Alpha
{
get { return _alpha; }
set { _alpha = value; }
}
private SolidBrush GetBackground()
{
int alphaCheck = 255;
if (_alpha < 0)
alphaCheck = 0;
else if (_alpha > 255)
alphaCheck = 255;
else
alphaCheck = _alpha;
return new SolidBrush(Color.FromArgb(alphaCheck, _backgroundColor));
}
Vediamo ora come utilizzare il metodo DrawImage, come suggerito in msdn.
public Image Resize(Image image)
{
// Temp variables
int newContainerWidth = _containerWidth;
int newContainerHeight = _containerHeight;
int newImageWidth = _imageWidth;
int newImageHeight = _imageHeight;
int newPositionX = 0;
int newPositionY = 0;
GetNewSizes(image, ref newContainerWidth, ref newContainerHeight, ref newImageWidth, ref newImageHeight);
GetPositions(ref newPositionX, ref newPositionY, newContainerWidth, newContainerHeight, newImageWidth, newImageHeight);
Bitmap retObj = new Bitmap(newContainerWidth, newContainerHeight);
retObj.SetResolution(_horizontalResolution, _verticalResolution);
Graphics g = Graphics.FromImage(retObj);
g.CompositingMode = _compositingMode;
g.CompositingQuality = _compositingQuality;
g.SmoothingMode = _smoothing;
g.InterpolationMode = _interpolation;
g.FillRectangle(GetBackground(), 0f, 0f, newContainerWidth, newContainerHeight);
g.DrawImage(image, newPositionX + _offsetX, newPositionY + _offsetY, newImageWidth, newImageHeight);
g.Dispose();
return (Image)retObj;
}
Come si osserva dal codice, vengono definite una serie di variabili temporanee che
saranno popolate successivamente da due metodi di supporto che vengono richiamati
per effettuare i dovuti controlli sulle dimensioni del container e dell'immagine
e definire quindi i valori finali che saranno utilizzati durante il processo di
resizing dell'immagine.
private void GetProportionalSizes(Image image, ref int imageWidth, ref int imageHeight)
{
bool exceedWidth = image.Width > imageWidth ? true : false;
bool exceedHeight = image.Height > imageHeight ? true : false;
if (exceedWidth & exceedHeight)
{
int horizontalSurplus = image.Width - _imageWidth;
int verticalSurplus = image.Height - _imageHeight;
if (horizontalSurplus > verticalSurplus)
{
imageWidth = _imageWidth;
imageHeight = imageWidth * image.Height / image.Width;
}
else
{
imageHeight = _imageHeight;
imageWidth = imageHeight * image.Width / image.Height;
}
}
else
{
if (exceedWidth)
{
imageWidth = _imageWidth;
imageHeight = imageWidth * image.Height / image.Width;
}
else
{
imageHeight = _imageHeight;
imageWidth = imageHeight * image.Width / image.Height;
}
}
}
Il metodo GetProportionalSizes() calcola le dimensioni finali dell'immagine in modo
da effettuare un ridimensionamento proporzionale ed evitare così il fastidioso effetto
di stretching delle immagini. Nella serie di if-else innestate viene eseguito un
controllo sulla coerenza della proporzioni in base alle dimensioni dell'immagine
originale e delle dimensioni desiderate.
Infatti il primo controllo si occupa di verificare quale delle due dimensioni (orizzontale
o verticale) richieste eccede rispetto alla dimensione dell'immagine originale.
Se entrambe eccedono, viene verificata quale delle due dimensioni eccede maggiormente
di modo che il calcolo proporzionale venga fatto su questa. Il discorso è analogo
qualora solo una delle due dimensioni ecceda rispetto alle dimensioni dell'immagine
originale. Il terzo caso, non contemplato nel corpo del metodo, è il caso in cui
nessuna delle due dimensioni richieste per il ridimensionamento ecceda le dimensioni
originali: in questo caso le dimensioni richieste sono superiori a quella dell'immagine
originale, assumendo l'assenza di ridimensionamento, ed evitando quindi il calcolo
delle dimensioni proporzionali.
private void CheckContainerSizes(ref int imageWidth, ref int imageHeight)
{
bool exceedWidth = imageWidth > _containerWidth ? true : false;
bool exceedHeight = imageHeight > _containerHeight ? true : false;
if (exceedWidth & exceedHeight)
{
int horizontalSurplus = imageWidth - _containerWidth;
int verticalSurplus = imageHeight - _containerHeight;
if (horizontalSurplus > verticalSurplus)
{
imageWidth = _containerWidth;
imageHeight = imageWidth * _containerHeight / _containerWidth;
}
else
{
imageHeight = _containerHeight;
imageWidth = imageHeight * _containerWidth / _containerHeight;
}
}
else
{
if (exceedWidth)
{
imageWidth = _containerWidth;
imageHeight = imageWidth * _containerHeight / _containerWidth;
}
else
{
imageHeight = _containerHeight;
imageWidth = imageHeight * _containerWidth / _containerHeight;
}
}
// Change required size for auto fit
_imageWidth = imageWidth;
_imageHeight = imageHeight;
}
Il metodo CheckContainerSizes() viene richiamato nel solo caso in cui la modalità
operativa scelta sia FitAuto, ovvero quando viene richiesto che l'immagine venga
ridimensionata nel rispetto delle dimensioni del container, senza andare oltre queste.
Leggendo il corpo di questo metodo, si nota che è praticamente identico al corpo
del metodo GetProportionalSizes(), ma ha una differenza importante: oltre ad effettuare
le verifiche del caso, è in grado di reimpostare le dimensioni di ridimensionamento
richieste affinchè soddisfino il criterio operativo scelto.
public void Save(Image image, ImageFormat format, string outputFile)
{
if (format == ImageFormat.Jpeg)
{
ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, _jpegCompression);
image.Save(outputFile, info[1], encoderParams);
}
else
{
image.Save(outputFile, format);
}
}
Il metodo Save() consente di salvare su filesystem l'immagine precedentemente ridimensionata
(o qualunque altra immagine precedentemente istanziata, visto che tra i parametri
di input c'è "image").
Si nota però che nel caso venga richiesto di salvare in formato Jpeg, è possibile
controllare il grado di compressione dell'immagine jpeg risultante, semplicemente
instanziando e valorizzando l'oggetto EncoderParameters e passandolo in input
ad uno specifico overload del metodo Save() dell'oggetto Image.
Tra i vari membri presenti, opportunamente mappati su proprietà, ne spiccano cinque
che consentono di avere un controllo dell'output piuttosto avanzato:
private InterpolationMode _interpolation;
private CompositingMode _compositingMode;
private CompositingQuality _compositingQuality;
private SmoothingMode _smoothing;
private PixelOffsetMode _pixelOffsetMode;
public InterpolationMode Interpolation
{
get { return _interpolation; }
set { _interpolation = value; }
}
public CompositingMode CompositingMode
{
get { return _compositingMode; }
set { _compositingMode = value; }
}
public CompositingQuality CompositingQuality
{
get { return _compositingQuality; }
set { _compositingQuality = value; }
}
public SmoothingMode Smoothing
{
get { return _smoothing; }
set { _smoothing = value; }
}
public PixelOffsetMode PixelOffset
{
get { return _pixelOffsetMode; }
set { _pixelOffsetMode = value; }
}
InterpolationMode
L'InterpolationMode è, in questo contesto, di importanza vitale. Specifica infatti
'algoritmo utilizzato quando le immagini vengono scalate o ruotate. Questi le possibili
scelte:
- Default: Specifica la modalità predefinita.
- Low: Specifica un'interpolazione di bassa qualità.
- High: Specifica un'interpolazione di elevata qualità.
- Bilinear: Specifica l'interpolazione bilineare. Non viene effettuata alcuna
operazione di prefiltraggio. Questa modalità non è adatta per la compattazione di
un'immagine al di sotto del 50% delle dimensioni originali.
- Bicubic: Specifica l'interpolazione bicubica. Non viene effettuata alcuna
operazione di prefiltraggio. Questa modalità non è adatta per la compattazione di
un'immagine al di sotto del 25% delle dimensioni originali.
- NearestNeighbor: Specifica l'interpolazione più simile.
- HighQualityBilinear: Specifica l'interpolazione bilineare di elevata qualità.
Viene effettuata un'operazione di prefiltraggio per assicurare una compattazione
di elevata qualità.
- HighQualityBicubic: Specifica l'interpolazione bicubica di elevata qualità.
Viene effettuata un'operazione di prefiltraggio per assicurare una compattazione
di elevata qualità. Questa modalità produce le immagini trasformate di qualità più
elevata.
CompositingMode
Il CompositingMode specifica il modo in cui i colori di origine vengono combinati
con i colori dello sfondo. E' possibile assegnare uno dei due valori:
- SourceOver: quando viene eseguito il rendering di un colore, tale colore
viene miscelato con il colore dello sfondo. La miscela di colori viene determinata
dal componente alpha del colore di cui viene eseguito il rendering.
- SourceCopy: quando viene eseguito il rendering di un colore, tale colore
sovrascrive il colore dello sfondo.
CompositingQuality
La CompositingQuality specifica il livello di qualità da utilizzare durante la composizione.
Questi sono i valori ammissibili:
- Default: qualità predefinita.
- HighSpeed: alta velocità, bassa qualità.
- HighQuality: composizione di elevata qualità e ridotta velocità.
- GammaCorrected: viene utilizzata la correzione gamma.
- AssumeLinear: vengono assunti i valori lineari.
SmoothingMode
Lo SmoothingMode specifica se e come viene applicato l'anti-aliasing. Anche i questo
caso abbiamo una serie di valori ammissibili:
- Default: Specifica l'assenza di antialias.
- HighSpeed: Specifica l'assenza di antialias.
- HighQuality: Specifica il rendering con antialias.
- None: Specifica l'assenza di antialias.
- AntiAlias: Specifica il rendering con antialias.
PixelOffsetMode
Il PixelOffsetMode specifica la modalità di offset dei pixel durante l'esecuzione
del rendering, in modo da controllare la qualità del rendering finale. Questi i
valori ammissibili:
- Default: Specifica la modalità predefinita.
- HighSpeed: Specifica un rendering di elevata velocità e ridotta qualità.
- HighQuality: Specifica un rendering di elevata qualità e ridotta velocità.
- None: Specifica l'assenza di offset di pixel.
- Half: Specifica l'offset dei pixel in base a unità - .5, sia in senso orizzontale
che verticale, per ottenere un anti-aliasing di elevata velocità.
g.FillRectangle(GetBackground(), 0f, 0f, newContainerWidth, newContainerHeight);
g.DrawImage(image, newPositionX + _offsetX, newPositionY + _offsetY, newImageWidth, newImageHeight);
Definiti tutti i parametri di disegno ed effettuati i calcoli sul ridimensionamento,
sono le due chiamate finali a generare l'immagine di output. Nella prima, il metodo
FillRectangle, in uno dei suoi overload (2), disegna il livello di sfondo. Su di
questo, la chiamata successiva, DrawImage, anch'essa in uno dei suoi overload (3),
disegna l'immagine ridimensionata.
Il codice sorgente
#region Using directives
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
#endregion
namespace DotNetCampania.Imager
{
public class ImageProcessor
{
#region Enums
public enum ScaleMode
{
FitContainer,
FitImage,
FitAuto,
NoFit
}
public enum Position
{
TopLeft,
TopCenter,
TopRight,
MiddleLeft,
MiddleCenter,
MiddleRight,
BottomLeft,
BottomCenter,
BottomRight,
Undefined
}
#endregion
#region Members
private int _imageWidth;
private int _imageHeight;
private int _containerWidth;
private int _containerHeight;
private ScaleMode _scale;
private Position _drawingPosition;
private bool _proportional;
private InterpolationMode _interpolation;
private CompositingMode _compositingMode;
private CompositingQuality _compositingQuality;
private SmoothingMode _smoothing;
private PixelOffsetMode _pixelOffsetMode;
private Color _backgroundColor;
private int _alpha;
private int _offsetX;
private int _offsetY;
private ImageFormat _outputImageFormat;
private long _jpegCompression;
private float _horizontalResolution;
private float _verticalResolution;
#endregion
#region Properties
public int Width
{
get { return _imageWidth; }
set { _imageWidth = value; }
}
public int Height
{
get { return _imageHeight; }
set { _imageHeight = value; }
}
public int ContainerWidth
{
get { return _containerWidth; }
set { _containerWidth = value; }
}
public int ContainerHeight
{
get { return _containerHeight; }
set { _containerHeight = value; }
}
public Position DrawingPosition
{
get { return _drawingPosition; }
set { _drawingPosition = value; }
}
public bool Proportional
{
get { return _proportional; }
set { _proportional = value; }
}
public InterpolationMode Interpolation
{
get { return _interpolation; }
set { _interpolation = value; }
}
public CompositingMode CompositingMode
{
get { return _compositingMode; }
set { _compositingMode = value; }
}
public CompositingQuality CompositingQuality
{
get { return _compositingQuality; }
set { _compositingQuality = value; }
}
public SmoothingMode Smoothing
{
get { return _smoothing; }
set { _smoothing = value; }
}
public PixelOffsetMode PixelOffset
{
get { return _pixelOffsetMode; }
set { _pixelOffsetMode = value; }
}
public Color BackgroundColor
{
get { return _backgroundColor; }
set { _backgroundColor = value; }
}
public int Alpha
{
get { return _alpha; }
set { _alpha = value; }
}
public int OffsetX
{
get { return _offsetX; }
set { _offsetX = value; }
}
public int OffsetY
{
get { return _offsetY; }
set { _offsetY = value; }
}
public ImageFormat OutputImageFormat
{
get { return this._outputImageFormat; }
set { _outputImageFormat = value; }
}
public long JPEGCompression
{
get { return _jpegCompression; }
set { _jpegCompression = value; }
}
public float HorizontalResolution
{
get { return _horizontalResolution; }
set { _horizontalResolution = value; }
}
public float VerticalResolution
{
get { return _verticalResolution; }
set { _verticalResolution = value; }
}
public ScaleMode Scale
{
get { return _scale; }
set { _scale = value; }
}
#endregion
#region Constructor(s)
public ImageProcessor()
{
_imageWidth = default(int);
_imageHeight = default(int);
_containerWidth = default(int);
_containerHeight = default(int);
_drawingPosition = Position.Undefined;
_interpolation = InterpolationMode.HighQualityBicubic;
_compositingMode = CompositingMode.SourceOver;
_compositingQuality = CompositingQuality.HighQuality;
_smoothing = SmoothingMode.HighQuality;
_pixelOffsetMode = PixelOffsetMode.HighQuality;
_proportional = true;
_alpha = 255;
_backgroundColor = Color.White;
_offsetX = 0;
_offsetY = 0;
_scale = ScaleMode.FitAuto;
_outputImageFormat = ImageFormat.Jpeg;
_jpegCompression = 80L;
_horizontalResolution = 72f;
_verticalResolution = 72f;
}
#endregion
#region Public methods
public Image Resize(Image image)
{
// Temp variables
int newContainerWidth = _containerWidth;
int newContainerHeight = _containerHeight;
int newImageWidth = _imageWidth;
int newImageHeight = _imageHeight;
int newPositionX = 0;
int newPositionY = 0;
GetNewSizes(image, ref newContainerWidth, ref newContainerHeight, ref newImageWidth, ref newImageHeight);
GetPositions(ref newPositionX, ref newPositionY, newContainerWidth, newContainerHeight, newImageWidth, newImageHeight);
Bitmap retObj = new Bitmap(newContainerWidth, newContainerHeight);
retObj.SetResolution(_horizontalResolution, _verticalResolution);
Graphics g = Graphics.FromImage(retObj);
g.CompositingMode = _compositingMode;
g.CompositingQuality = _compositingQuality;
g.SmoothingMode = _smoothing;
g.InterpolationMode = _interpolation;
g.PixelOffsetMode = _pixelOffsetMode;
g.FillRectangle(GetBackground(), 0f, 0f, newContainerWidth, newContainerHeight);
g.DrawImage(image, newPositionX + _offsetX, newPositionY + _offsetY, newImageWidth, newImageHeight);
g.Dispose();
return (Image)retObj;
}
public void Save(Image image, ImageFormat format, string outputFile)
{
if (format == ImageFormat.Jpeg)
{
ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, _jpegCompression);
image.Save(outputFile, info[1], encoderParams);
}
else
{
image.Save(outputFile, format);
}
}
#endregion
#region Private support methods
private void GetNewSizes(Image image, ref int containerWidth, ref int containerHeight, ref int imageWidth, ref int imageHeight)
{
switch (_scale)
{
case ScaleMode.NoFit:
if (_proportional)
{
GetProportionalSizes(image, ref imageWidth, ref imageHeight);
}
break;
case ScaleMode.FitAuto:
CheckContainerSizes(ref imageWidth, ref imageHeight);
if (_proportional)
GetProportionalSizes(image, ref imageWidth, ref imageHeight);
break;
case ScaleMode.FitContainer:
imageWidth = containerWidth;
imageHeight = containerHeight;
break;
case ScaleMode.FitImage:
if (_proportional)
GetProportionalSizes(image, ref imageWidth, ref imageHeight);
containerWidth = imageWidth;
containerHeight = imageHeight;
break;
}
}
private void GetPositions(ref int positionX, ref int positionY, int containerWidth, int containerHeight, int imageWidth, int imageHeight) {
switch (_drawingPosition) {
case Position.BottomCenter:
positionX = (int)((containerWidth / 2) - (imageWidth / 2));
positionY = containerHeight - imageHeight;
break;
case Position.BottomLeft:
positionX = 0;
positionY = containerHeight - imageHeight;
break;
case Position.BottomRight:
positionX = containerWidth - imageWidth;
positionY = containerHeight - imageHeight;
break;
case Position.MiddleCenter:
positionX = (int)((containerWidth / 2) - (imageWidth / 2));
positionY = (int)((containerHeight / 2) - (imageHeight / 2));
break;
case Position.MiddleLeft:
positionX = 0;
positionY = (int)((containerHeight / 2) - (imageHeight / 2));
break;
case Position.MiddleRight:
positionX = containerWidth - imageWidth;
positionY = (int)((containerHeight / 2) - (imageHeight / 2));
break;
case Position.TopCenter:
positionX = (int)((containerWidth / 2) - (imageWidth / 2));
positionY = 0;
break;
case Position.TopLeft:
positionX = 0;
positionY = 0;
break;
case Position.TopRight:
positionX = containerWidth - imageWidth;
positionY = 0;
break;
}
}
private void CheckContainerSizes(ref int imageWidth, ref int imageHeight)
{
bool exceedWidth = imageWidth > _containerWidth ? true : false;
bool exceedHeight = imageHeight > _containerHeight ? true : false;
if (exceedWidth & exceedHeight)
{
int horizontalSurplus = imageWidth - _containerWidth;
int verticalSurplus = imageHeight - _containerHeight;
if (horizontalSurplus > verticalSurplus)
{
imageWidth = _containerWidth;
imageHeight = imageWidth * _containerHeight / _containerWidth;
}
else
{
imageHeight = _containerHeight;
imageWidth = imageHeight * _containerWidth / _containerHeight;
}
}
else
{
if (exceedWidth)
{
imageWidth = _containerWidth;
imageHeight = imageWidth * _containerHeight / _containerWidth;
}
else
{
imageHeight = _containerHeight;
imageWidth = imageHeight * _containerWidth / _containerHeight;
}
}
// Change required size for auto fit
_imageWidth = imageWidth;
_imageHeight = imageHeight;
}
private void GetProportionalSizes(Image image, ref int imageWidth, ref int imageHeight)
{
bool exceedWidth = image.Width > imageWidth ? true : false;
bool exceedHeight = image.Height > imageHeight ? true : false;
if (exceedWidth & exceedHeight)
{
int horizontalSurplus = image.Width - _imageWidth;
int verticalSurplus = image.Height - _imageHeight;
if (horizontalSurplus > verticalSurplus)
{
imageWidth = _imageWidth;
imageHeight = imageWidth * image.Height / image.Width;
}
else
{
imageHeight = _imageHeight;
imageWidth = imageHeight * image.Width / image.Height;
}
}
else
{
if (exceedWidth)
{
imageWidth = _imageWidth;
imageHeight = imageWidth * image.Height / image.Width;
}
else
{
imageHeight = _imageHeight;
imageWidth = imageHeight * image.Width / image.Height;
}
}
}
private SolidBrush GetBackground()
{
int alphaCheck = 255;
if (_alpha < 0)
alphaCheck = 0;
else if (_alpha > 255)
alphaCheck = 255;
else
alphaCheck = _alpha;
return new SolidBrush(Color.FromArgb(alphaCheck, _backgroundColor));
}
#endregion
}
}
Download
Riferimenti
- Riferimento a .NET Framework - Metodo Image.GetThumbnailImage [http://msdn.microsoft.com/it-it/library/system.drawing.image.getthumbnailimage.aspx]
- Graphics.FillRectangle Method (Brush, Rectangle) [http://msdn.microsoft.com/en-us/library/yysstebh.aspx
- Metodo Graphics.DrawImage (Image, Int32, Int32, Int32, Int32) [http://msdn.microsoft.com/it-it/library/dbsak4dc(v=VS.80).aspx]