📄 cpartwork.java
字号:
for (int j = dstRect.top; j < dstRect.bottom; j++) {
int dstOffset = dstRect.left + j * width;
for (int i = dstRect.left; i < dstRect.right; i++, dstOffset++) {
int opacityAlpha = opacityData[dstOffset] / 255;
if (opacityAlpha > 0) {
int destColor = undoData[dstOffset];
if ((destColor & 0xff000000) != 0) {
// opacityAlpha = 255 - opacityAlpha;
int r = destColor >>> 16 & 0xff;
int g = destColor >>> 8 & 0xff;
int b = destColor & 0xff;
r = r - (BURN_CONSTANT - r) * opacityAlpha / 255;
g = g - (BURN_CONSTANT - g) * opacityAlpha / 255;
b = b - (BURN_CONSTANT - b) * opacityAlpha / 255;
if (r < 0) {
r = 0;
}
if (g < 0) {
g = 0;
}
if (b < 0) {
b = 0;
}
int newColor = destColor & 0xff000000 | r << 16 | g << 8 | b;
curLayer.data[dstOffset] = newColor;
}
}
}
}
}
}
class CPBrushToolBlur extends CPBrushToolSimpleBrush {
public void mergeOpacityBuf(CPRect dstRect, int color) {
int[] opacityData = opacityBuffer.data;
int[] undoData = undoBuffer.data;
for (int j = dstRect.top; j < dstRect.bottom; j++) {
int dstOffset = dstRect.left + j * width;
for (int i = dstRect.left; i < dstRect.right; i++, dstOffset++) {
int opacityAlpha = opacityData[dstOffset] / 255;
if (opacityAlpha > 0) {
int blur = BLUR_MIN + (BLUR_MAX - BLUR_MIN) * opacityAlpha / 255;
int destColor = undoData[dstOffset];
int a = blur * (destColor >>> 24 & 0xff);
int r = blur * (destColor >>> 16 & 0xff);
int g = blur * (destColor >>> 8 & 0xff);
int b = blur * (destColor & 0xff);
int sum = blur + 4;
destColor = undoData[j > 0 ? dstOffset - width : dstOffset];
a += destColor >>> 24 & 0xff;
r += destColor >>> 16 & 0xff;
g += destColor >>> 8 & 0xff;
b += destColor & 0xff;
destColor = undoData[j < height - 1 ? dstOffset + width : dstOffset];
a += destColor >>> 24 & 0xff;
r += destColor >>> 16 & 0xff;
g += destColor >>> 8 & 0xff;
b += destColor & 0xff;
destColor = undoData[i > 0 ? dstOffset - 1 : dstOffset];
a += destColor >>> 24 & 0xff;
r += destColor >>> 16 & 0xff;
g += destColor >>> 8 & 0xff;
b += destColor & 0xff;
destColor = undoData[i < width - 1 ? dstOffset + 1 : dstOffset];
a += destColor >>> 24 & 0xff;
r += destColor >>> 16 & 0xff;
g += destColor >>> 8 & 0xff;
b += destColor & 0xff;
a /= sum;
r /= sum;
g /= sum;
b /= sum;
curLayer.data[dstOffset] = a << 24 | r << 16 | g << 8 | b;
}
}
}
}
}
// Brushes derived from this class use the opacity buffer
// as a simple alpha layer
class CPBrushToolDirectBrush extends CPBrushToolSimpleBrush {
public void mergeOpacityBuf(CPRect dstRect, int color) {
int[] opacityData = opacityBuffer.data;
int[] undoData = undoBuffer.data;
for (int j = dstRect.top; j < dstRect.bottom; j++) {
int dstOffset = dstRect.left + j * width;
for (int i = dstRect.left; i < dstRect.right; i++, dstOffset++) {
int color1 = opacityData[dstOffset];
int alpha1 = (color1 >>> 24);
if (alpha1 <= 0) {
continue;
}
int color2 = undoData[dstOffset];
int alpha2 = (color2 >>> 24) * fusion.alpha / 100;
int newAlpha = alpha1 + alpha2 - alpha1 * alpha2 / 255;
if (newAlpha > 0) {
int realAlpha = alpha1 * 255 / newAlpha;
int invAlpha = 255 - realAlpha;
curLayer.data[dstOffset] = newAlpha << 24
| (((color1 >>> 16 & 0xff) * realAlpha + (color2 >>> 16 & 0xff) * invAlpha) / 255) << 16
| (((color1 >>> 8 & 0xff) * realAlpha + (color2 >>> 8 & 0xff) * invAlpha) / 255) << 8
| (((color1 & 0xff) * realAlpha + (color2 & 0xff) * invAlpha) / 255);
}
}
}
}
}
class CPBrushToolWatercolor extends CPBrushToolDirectBrush {
static final int wcMemory = 50;
static final int wxMaxSampleRadius = 64;
LinkedList<CPColorFloat> previousSamples;
public void beginStroke(float x, float y, float pressure) {
previousSamples = null;
super.beginStroke(x, y, pressure);
}
void paintDabImplementation(CPRect srcRect, CPRect dstRect, CPBrushDab dab) {
if (previousSamples == null) {
CPColorFloat startColor = sampleColor((dstRect.left + dstRect.right) / 2,
(dstRect.top + dstRect.bottom) / 2, Math.max(1, Math.min(wxMaxSampleRadius,
dstRect.getWidth() * 2 / 6)), Math.max(1, Math.min(wxMaxSampleRadius, dstRect
.getHeight() * 2 / 6)));
previousSamples = new LinkedList();
for (int i = 0; i < wcMemory; i++) {
previousSamples.addLast(startColor);
}
}
CPColorFloat wcColor = new CPColorFloat(0, 0, 0);
for (CPColorFloat sample : previousSamples) {
wcColor.r += sample.r;
wcColor.g += sample.g;
wcColor.b += sample.b;
}
wcColor.r /= previousSamples.size();
wcColor.g /= previousSamples.size();
wcColor.b /= previousSamples.size();
// resaturation
int color = curColor & 0xffffff;
wcColor.mixWith(new CPColorFloat(color), curBrush.resat * curBrush.resat);
int newColor = wcColor.toInt();
// bleed
wcColor.mixWith(sampleColor((dstRect.left + dstRect.right) / 2, (dstRect.top + dstRect.bottom) / 2, Math
.max(1, Math.min(wxMaxSampleRadius, dstRect.getWidth() * 2 / 6)), Math.max(1, Math.min(
wxMaxSampleRadius, dstRect.getHeight() * 2 / 6))), curBrush.bleed);
previousSamples.addLast(wcColor);
previousSamples.removeFirst();
paintDirect(srcRect, dstRect, dab.brush, dab.width, Math.max(1, dab.alpha / 4), newColor);
mergeOpacityBuffer(0, false);
if (sampleAllLayers) {
fusionLayers();
}
}
void paintDirect(CPRect srcRect, CPRect dstRect, byte[] brush, int w, int alpha, int color1) {
int[] opacityData = opacityBuffer.data;
int by = srcRect.top;
for (int j = dstRect.top; j < dstRect.bottom; j++, by++) {
int srcOffset = srcRect.left + by * w;
int dstOffset = dstRect.left + j * width;
for (int i = dstRect.left; i < dstRect.right; i++, srcOffset++, dstOffset++) {
int alpha1 = (brush[srcOffset] & 0xff) * alpha / 255;
if (alpha1 <= 0) {
continue;
}
int color2 = opacityData[dstOffset];
int alpha2 = (color2 >>> 24);
int newAlpha = alpha1 + alpha2 - alpha1 * alpha2 / 255;
if (newAlpha > 0) {
int realAlpha = alpha1 * 255 / newAlpha;
int invAlpha = 255 - realAlpha;
// The usual alpha blending formula C = A * alpha + B * (1 - alpha)
// has to rewritten in the form C = A + (1 - alpha) * B - (1 - alpha) *A
// that way the rounding up errors won't cause problems
int newColor = newAlpha << 24
| ((color1 >>> 16 & 0xff) + (((color2 >>> 16 & 0xff) * invAlpha - (color1 >>> 16 & 0xff)
* invAlpha) / 255)) << 16
| ((color1 >>> 8 & 0xff) + (((color2 >>> 8 & 0xff) * invAlpha - (color1 >>> 8 & 0xff)
* invAlpha) / 255)) << 8
| ((color1 & 0xff) + (((color2 & 0xff) * invAlpha - (color1 & 0xff) * invAlpha) / 255));
opacityData[dstOffset] = newColor;
}
}
}
}
CPColorFloat sampleColor(int x, int y, int dx, int dy) {
LinkedList<CPColorFloat> samples = new LinkedList<CPColorFloat>();
CPLayer layerToSample = sampleAllLayers ? fusion : getActiveLayer();
samples.addLast(new CPColorFloat(layerToSample.getPixel(x, y) & 0xffffff));
for (float r = 0.25f; r < 1.001f; r += .25f) {
samples.addLast(new CPColorFloat(layerToSample.getPixel((int) (x + r * dx), y) & 0xffffff));
samples.addLast(new CPColorFloat(layerToSample.getPixel((int) (x - r * dx), y) & 0xffffff));
samples.addLast(new CPColorFloat(layerToSample.getPixel(x, (int) (y + r * dy)) & 0xffffff));
samples.addLast(new CPColorFloat(layerToSample.getPixel(x, (int) (y - r * dy)) & 0xffffff));
samples.addLast(new CPColorFloat(layerToSample.getPixel((int) (x + r * .7f * dx), (int) (y + r * .7f
* dy)) & 0xffffff));
samples.addLast(new CPColorFloat(layerToSample.getPixel((int) (x + r * .7f * dx), (int) (y - r * .7f
* dy)) & 0xffffff));
samples.addLast(new CPColorFloat(layerToSample.getPixel((int) (x - r * .7f * dx), (int) (y + r * .7f
* dy)) & 0xffffff));
samples.addLast(new CPColorFloat(layerToSample.getPixel((int) (x - r * .7f * dx), (int) (y - r * .7f
* dy)) & 0xffffff));
}
CPColorFloat average = new CPColorFloat(0, 0, 0);
for (CPColorFloat sample : samples) {
average.r += sample.r;
average.g += sample.g;
average.b += sample.b;
}
average.r /= samples.size();
average.g /= samples.size();
average.b /= samples.size();
return average;
}
}
class CPBrushToolOil extends CPBrushToolDirectBrush {
void paintDabImplementation(CPRect srcRect, CPRect dstRect, CPBrushDab dab) {
if (brushBuffer == null) {
brushBuffer = new int[dab.width * dab.height];
for (int i = brushBuffer.length - 1; --i >= 0;) {
brushBuffer[i] = 0;
}
// curLayer.copyRect(dstRect, brushBuffer);
oilAccumBuffer(srcRect, dstRect, brushBuffer, dab.width, 255);
} else {
oilResatBuffer(srcRect, dstRect, brushBuffer, dab.width, (int) ((curBrush.resat <= 0f) ? 0 : Math.max(
1, (curBrush.resat * curBrush.resat) * 255)), curColor & 0xffffff);
oilPasteBuffer(srcRect, dstRect, brushBuffer, dab.brush, dab.width, dab.alpha);
oilAccumBuffer(srcRect, dstRect, brushBuffer, dab.width, (int) ((curBrush.bleed) * 255));
}
mergeOpacityBuffer(0, false);
if (sampleAllLayers) {
fusionLayers();
}
}
private void oilAccumBuffer(CPRect srcRect, CPRect dstRect, int[] buffer, int w, int alpha) {
CPLayer layerToSample = sampleAllLayers ? fusion : getActiveLayer();
int by = srcRect.top;
for (int j = dstRect.top; j < dstRect.bottom; j++, by++) {
int srcOffset = srcRect.left + by * w;
int dstOffset = dstRect.left + j * width;
for (int i = dstRect.left; i < dstRect.right; i++, srcOffset++, dstOffset++) {
int color1 = layerToSample.data[dstOffset];
int alpha1 = (color1 >>> 24) * alpha / 255;
if (alpha1 <= 0) {
continue;
}
int color2 = buffer[srcOffset];
int alpha2 = (color2 >>> 24);
int newAlpha = alpha1 + alpha2 - alpha1 * alpha2 / 255;
if (newAlpha > 0) {
int realAlpha = alpha1 * 255 / newAlpha;
int invAlpha = 255 - realAlpha;
int newColor = newAlpha << 24
| ((color1 >>> 16 & 0xff) + (((color2 >>> 16 & 0xff) * invAlpha - (color1 >>> 16 & 0xff)
* invAlpha) / 255)) << 16
| ((color1 >>> 8 & 0xff) + (((color2 >>> 8 & 0xff) * invAlpha - (color1 >>> 8 & 0xff)
* invAlpha) / 255)) << 8
| ((color1 & 0xff) + (((color2 & 0xff) * invAlpha - (color1 & 0xff) * invAlpha) / 255));
buffer[srcOffset] = newColor;
}
}
}
}
private void oilResatBuffer(CPRect srcRect, CPRect dstRect, int[] buffer, int w, int alpha1, int color1) {
if (alpha1 <= 0) {
return;
}
int by = srcRect.top;
for (int j = dstRect.top; j < dstRect.bottom; j++, by++) {
int srcOffset = srcRect.left + by * w;
int dstOffset = dstRect.left + j * width;
for (int i = dstRect.left; i < dstRect.right; i++, srcOffset++, dstOffset++) {
int color2 = buffer[srcOffset];
int alpha2 = (color2 >>> 24);
int newAlpha = alpha1 + alpha2 - alpha1 * alpha2 / 255;
if (newAlpha > 0) {
int realAlpha = alpha1 * 255 / newAlpha;
int invAlpha = 255 - realAlpha;
int newColor = newAlpha << 24
| ((color1 >>> 16 & 0xff) + (((color2 >>> 16 & 0xff) * invAlpha - (color1 >>> 16 & 0xff)
* invAlpha) / 255)) << 16
| ((color1 >>> 8 & 0xff) + (((color2 >>> 8 & 0xff) * invAlpha - (color1 >>> 8 & 0xff)
* invAlpha) / 255)) << 8
| ((color1 & 0xff) + (((color2 & 0xff) * invAlpha - (color1 & 0xff) * invAlpha) / 255));
buffer[srcOffset] = newColor;
}
}
}
}
private void oilPasteBuffer(CPRect srcRect, CPRect dstRect, int[] buffer, byte[] brush, int w, int alpha) {
int[] opacityData = opacityBuffer.data;
int by = srcRect.top;
for (int j = dstRect.top; j < dstRect.bottom; j++, by++) {
int srcOffset = srcRect.left + by * w;
int dstOffset = dstRect.left + j * width;
for (int i = dstRect.left; i < dstRect.right; i++, srcOffset++, dstOffset++) {
int color1 = buffer[srcOffset];
int alpha1 = (color1 >>> 24) * (brush[srcOffset] & 0xff) * alpha / (255 * 255);
if (alpha1 <= 0) {
continue;
}
int color2 = curLayer.data[dstOffset];
int alpha2 = (color2 >>> 24);
int newAlpha = alpha1 + alpha2 - alpha1 * alpha2 / 255;
if (newAlpha > 0) {
int realAlpha = alpha1 * 255 / newAlpha;
int invAlpha = 255 - realAlpha;
int newColor = newAlpha << 24
| ((color1 >>> 16 & 0xff) + (((color2 >>> 16 & 0xff) * invAlpha - (color1 >>> 16 & 0xff)
* invAlpha) / 255)) << 16
| ((color1 >>> 8 & 0xff) + (((color2 >>> 8 & 0xff) * invAlpha - (color1 >>> 8 & 0xff)
* invAlpha) / 255)) << 8
| ((color1 & 0xff) + (((color2 & 0xff) * invAlpha - (color1 & 0xff) * invAlpha) / 255));
opacityData[dstOffset] = newColor;
}
}
}
}
}
class CPBrushToolSmudge extends CPBrushToolDirectBrush {
void paintDabImplementation(CPRect srcRect, CPRect dstRect, CPBrushDab dab) {
if (brushBuffer == null) {
brushBuffer = new int[dab.width * dab.height];
smudgeAccumBuffer(srcRect, dstRect, brushBuffer, dab.width, 0);
} else {
smudgeAccumBuffer(srcRect, dstRect, brushBuffer, dab.width, dab.alpha);
smudgePasteBuffer(srcRect, dstRect, brushBuffer, dab.brush, dab.width, dab.alpha);
if (lockAlpha) {
restoreAlpha(dstRect);
}
}
opacityArea.makeEmpty();
if (sampleAllLayers) {
fusionLayers();
}
}
public void mergeOpacityBuf(CPRect dstRect, int color) {
}
private void smudgeAccumBuffer(CPRect srcRect, CPRect dstRect, int[] buffer, int w, int alpha) {
CPLayer layerToSample = sampleAllLayers ? fusion : getActiveLayer();
int by = srcRect.top;
for (int j = dstRect.top; j < dstRect.bottom; j++, by++) {
int srcOffset = srcRect.left + by * w;
int dstOffset = dstRect.left + j * width;
for (int i = dstRect.left; i < dstRect.right; i++, srcOffset++, dstOffset++) {
int layerColor = layerToSample.data[dstOffset];
int opacityAlpha = 255 - alpha;
if (opacityAlpha > 0) {
int destColor = buffer[srcOffset];
int destAlpha = 255;
int newLayerAlpha = opacityAlpha + destAlpha * (255 - opacityAlpha) / 255;
int realAlpha = 255 * opacityAlpha / newLayerAlpha;
int invAlpha = 255 - realAlpha;
int newColor = (((layerColor >>> 24 & 0xff) * realAlpha + (destColor >>> 24 & 0xff) * invAlpha) / 255) << 24
& 0xff000000
| (((layerColor >>> 16 & 0xff) * realAlpha + (destColor >>> 16 & 0xff) * invAlpha) / 255) << 16
& 0xff0000
| (((layerColor >>> 8 & 0xff) * realAlpha + (destColor >>> 8 & 0xff) * invAlpha) / 255) << 8
& 0xff00
| (((layerColor & 0xff) * realAlpha + (destColor & 0xff) * invAlpha) / 255)
& 0xff;
if (newColor == destColor) {
if ((layerColor & 0xff0000) > (destColor & 0xff0000)) {
newColor += 1 << 16;
} else if ((layerColor & 0xff0000) < (destColor & 0xff0000)) {
newColor -= 1 << 16;
}
if ((layerColor & 0xff00) > (destColor & 0xff00)) {
newColor += 1 << 8;
} else if ((layerColor & 0xff00) < (destColor & 0xff00)) {
newColor -= 1 << 8;
}
if ((layerColor & 0xff) > (destColor & 0xff)) {
newColor += 1;
} else if ((layerColor & 0xff) < (destColor & 0xff)) {
newColor -= 1;
}
}
buffer[srcOffset] = newColor;
}
}
}
if (srcRect.left > 0) {
int fill = srcRect.left;
for (int j = srcRect.top; j < srcRect.bottom; j++) {
int offset = j * w;
int fillColor = buffer[offset + srcRect.left];
for (int i = 0; i < fill; i++) {
buffer[offset++] = fillColor;
}
}
}
if (srcRect.right < w) {
int fill = w - srcRect.right;
for (int j = srcRect.top; j < srcRect.bottom; j++) {
int offset = j * w + srcRect.right;
int fillColor = buffer[offset - 1];
for (int i = 0; i < fill; i++) {
buffer[offset++] = fillColor;
}
}
}
for (int j = 0; j < srcRect.top; j++) {
System.arraycopy(buffer, srcRect.top * w, buffer, j * w, w);
}
for (int j = srcRect.bottom; j < w; j++) {
System.arraycopy(buffer, (srcRect.bottom - 1) * w, buffer, j * w, w);
}
}
private void smudgePasteBuffer(CPRect srcRect, CPRect dstRect, int[] buffer, byte[] brush, int w, int alpha) {
int[] undoData = undoBuffer.data;
int by = srcRect.top;
for (int j = dstRect.top; j < dstRect.bottom; j++, by++) {
int srcOffset = srcRect.left + by * w;
int dstOffset = dstRect.left + j * width;
for (int i = dstRect.left; i < dstRect.right; i++, srcOffset++, dstOffset++) {
int bufferColor = buffer[srcOffset];
int opacityAlpha = (bufferColor >>> 24) * (brush[srcOffset] & 0xff) / 255;
if (opacityAlpha > 0) {
int destColor = undoData[dstOffset];
int realAlpha = 255;
int invAlpha = 255 - realAlpha;
int newColor = (((bufferColor >>> 24 & 0xff) * realAlpha + (destColor >>> 24 & 0xff) * invAlpha) / 255) << 24
& 0xff000000
| (((bufferColor >>> 16 & 0xff) * realAlpha + (destColor >>> 16 & 0xff) * invAlpha) / 255) << 16
& 0xff0000
| (((bufferColor >>> 8 & 0xff) * realAlpha + (destColor >>> 8 & 0xff) * invAlpha) / 255) << 8
& 0xff00
| (((bufferColor & 0xff) * realAlpha + (destColor & 0xff) * invAlpha) / 255)
& 0xff;
curLayer.data[dstOffset] = newColor;
}
}
}
}
}
// ///////////////////////////////////////////////////////////////////////////////////
// Layer methods
// ///////////////////////////////////////////////////////////////////////////////////
public void setActiveLayer(int i) {
if (i < 0 || i >= layers.size()) {
return;
}
activeLayer = i;
curLayer = layers.get(i);
callListenersLayerChange();
}
public int getActiveLayerNb() {
return activeLayer;
}
public CPLayer getActiveLayer() {
return curLayer;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -