SetPixel ist zu langsam. Gibt es einen schnelleren Weg zu ziehen, um zu bitmap?
Ich habe ein kleines paint Programm ich arbeite. Ich bin mit SetPixel auf ein bitmap zu tun, dass die Zeichnung der Linien. Wenn die Größe des Pinsels wird groß, wie die 25 Pixel über gibt es eine spürbare performance-drop. Ich Frage mich, ob es eine schnellere Möglichkeit zum zeichnen in ein bitmap. Hier ist ein bisschen der hintergrund des Projekts:
- Ich bin mit bitmaps, so dass ich verwenden können Ebenen, wie in Photoshop oder GIMP.
- Linien sind gezeichnet von Hand eingeben, denn dieser wird letztendlich Grafiktablett den Druck zu ändern, die Größe der line-über seine Länge.
- Die Linien sollen schließlich werden anti-aliaced/geschliffen, an den Kanten.
Ist, werde ich meine Zeichnung code nur für den Fall, es ist diese, die langsam ist und nicht die Set-Pixel-bit.
Dies ist in dem Fenster, wo die Malerei passiert:
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
m_lastPosition = m_currentPosition;
m_currentPosition = e.Location;
if(m_penDown && m_pointInWindow)
m_currentTool.MouseMove(m_lastPosition, m_currentPosition, m_layer);
canvas.Invalidate();
}
Umsetzung von MouseMove:
public override void MouseMove(Point lastPos, Point currentPos, Layer currentLayer)
{
DrawLine(lastPos, currentPos, currentLayer);
}
Umsetzung von DrawLine:
//The primary drawing code for most tools. A line is drawn from the last position to the current position
public override void DrawLine(Point lastPos, Point currentPos, Layer currentLayer)
{
//Creat a line vector
Vector2D vector = new Vector2D(currentPos.X - lastPos.X, currentPos.Y - lastPos.Y);
//Create the point to draw at
PointF drawPoint = new Point(lastPos.X, lastPos.Y);
//Get the amount to step each time
PointF step = vector.GetNormalisedVector();
//Find the length of the line
double length = vector.GetMagnitude();
//For each step along the line...
for (int i = 0; i < length; i++)
{
//Draw a pixel
PaintPoint(currentLayer, new Point((int)drawPoint.X, (int)drawPoint.Y));
drawPoint.X += step.X;
drawPoint.Y += step.Y;
}
}
Umsetzung von PaintPoint:
public override void PaintPoint(Layer layer, Point position)
{
//Rasterise the pencil tool
//Assume it is square
//Check the pixel to be set is witin the bounds of the layer
//Set the tool size rect to the locate on of the point to be painted
m_toolArea.Location = position;
//Get the area to be painted
Rectangle areaToPaint = new Rectangle();
areaToPaint = Rectangle.Intersect(layer.GetRectangle(), m_toolArea);
//Check this is not a null area
if (!areaToPaint.IsEmpty)
{
//Go through the draw area and set the pixels as they should be
for (int y = areaToPaint.Top; y < areaToPaint.Bottom; y++)
{
for (int x = areaToPaint.Left; x < areaToPaint.Right; x++)
{
layer.GetBitmap().SetPixel(x, y, m_colour);
}
}
}
}
Vielen Dank für jede Hilfe können Sie bereitstellen.
InformationsquelleAutor Pyro | 2011-10-14
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sperren Sie können die bitmap-Daten und Zeiger verwenden, um manuell die Werte einstellen. Es ist viel schneller. Wenn Sie haben, Verwendung von unsicheren code.
Müssen Sie die msdn.microsoft.com/en-us/library/... um eine alpha-Komponente. Ändern Sie einfach
PixelFormat.Format24bppRgb
zuPixelFormat.Format32bppArgb
. Ich glaube, es sollte nach R, so nur kompensiert werden durch +3. Wenn Sie die Verwendung von 32 bit pro pixel, Sie wird sich ändern müssenx * 3
zux * 4
da, es werden 4 bytes pro pixel jetzt.Ich habe das gerade einmal ausprobiert. Es ist schön und schnell jetzt auf alle Pinsel-Größen! Allerdings gibt es nun einige merkwürdige Verhaltensweisen: Das eigentliche zeichnen geschieht bei einem offset, wo die Maus ist. Ich Frage mich, ob es etwas zu tun mit dieser Zeile hier: BitmapData-data = bmp.LockBits(new Rectangle(areaToPaint.Recht, areaToPaint.Unten), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); Es muss eine position angegeben, die für das Rechteck. Ich benutzte geliefert, '- position' Wert. Ist das richtig?
Die
position
Wert für das Rechteck die position des Rechtecks auf Ihrem picturebox oder panel. Sie sind mit der position der Maus. Wenn das Bild-layout nicht zentriert ist, können Sie nur verwenden, (0, 0) für die position. Wenn es zentriert ist und Ihre picturebox größer ist als dein Bild, dann passen Sie den offset. Auch sollte man ändernnew Rectangle(areaToPaint.Right, areaToPaint.Bottom)
zunew Rectangle(0, 0, bmp.Width, bmp.Height)
. Ich dachteareaToPaint
wurde die Abmessungen des gesamten Bildes.Ist es notwendig, unsicheren code zu tun? Konnte Sie nicht verwenden
Marshal.WriteByte
zu schreiben, um die Speicher-Adresse desIntPtr
anstelle der Umwandlung in einbyte*
zu tun unsafe-Zeiger-Operationen? Oder wäre das langsamer?InformationsquelleAutor Jack
SetPixel tut:
ist sperren das gesamte Bild, wird das pixel auf und entsperrt es
versuchen, das zu tun: Sie erwerben eine Sperre für den gesamten Speicher Bild mit lockbits, Prozess, die Sie aktualisieren und freigeben der sperren nach.
lockbits
ich Mach dir ein Beispiel, einen moment...
3 Jahre später, immer noch kein Beispiel
Es ist nur ein langer Augenblick
SetPixel != LockBits
InformationsquelleAutor fixagon
Normalerweise verwende ich ein array darstellen, die rohen pixel-Daten. Und dann kopieren zwischen Arrays und die bitmap mit unsicherem code.
Das array von
Color
ist eine schlechte Idee, da dieColor
struct ist relativ groß(12 bytes+). So können Sie entweder definieren Sie Ihre eigenen 4 byte struct(das ist die, die ich wählte) oder einfach ein array vonint
oderbyte
.Sollten Sie auch wieder das array, da GC auf der LOH tendenziell teurer.
Mein code kann gefunden werden unter:
https://github.com/CodesInChaos/ChaosUtil/blob/master/Chaos.Image/
Alternative ist schreiben alle Ihren code mit Zeiger in die bitmap direkt. Das ist ein bisschen schneller noch, kann aber den code hässlicher und mehr fehleranfällig.
In meiner Anwendung habe ich ein array mit der gleichen Größe wie die bitmap, die ich aber benötigt, um die gesamte bitmap. Aber selbst wenn, würde ich die Arbeit nur auf einen Teil der bitmap, ich würde immer noch die volle Bandbreite, aber vielleicht füllen Sie nur den Teil von Ihr, die ich brauche. So brauche ich nicht zu reservieren, wird ein neues array bei der Arbeit auf ein unterschiedlich großer Bereich des Bildes.
InformationsquelleAutor CodesInChaos
Nur eine Idee: Füllen Sie eine offscreen-bitmap mit dem Pinsel Pixel. Sie brauchen nur, sich zu regenerieren diese bitmap wenn der Pinsel, Größe oder Farbe verändert wird. Und dann ziehen Sie einfach das bitmap auf Ihre vorhandenen bitmap, wo die Maus liegt.
Wenn Sie modulieren können Sie eine bitmap mit der Farbe, Sie können die Pixel in Graustufen und modulieren es mit dem aktuellen Pinsel Farbe.
Oder vielleicht halten Sie ein Array von
Bitmap
s Pinsel (weiß in Farbe), und die Farbe-modulation (falls erforderlich) wie du bereits erwähnt hast 🙂 (ja ich bin zu spät auf diesen Beitrag)InformationsquelleAutor dowhilefor
Die Sie aufrufen GetBitmap in Ihrem verschachtelten for-Schleife. Es sieht aus wie das ist nicht notwendig, Sie sollten GetBitmap außerhalb der for-Schleifen als Referenz, ist nicht zu ändern.
Schauen Sie auch unter @fantasticfix Antwort, Lockbits fast immer Arten langsame performance-Probleme mit bekommen/Einstellung Pixel
InformationsquelleAutor RichK