APNG’leri Java aracılığıyla karikatürize edin
Sunucu tarafı API’lerini kullanarak APNG dosyalarını Karikatürleştirmek için kendi Java uygulamalarınızı oluşturun.
Java Kullanarak APNG Dosyalarını Karikatürleştirme
Çizgi film efektlerinin doğası gereği çekiciliği vardır ve çoğu zaman nostaljik çocukluk anılarını çağrıştırır. Neredeyse her grafik tasarım makalesi, karikatür görsellerini temel bir unsur olarak birleştirir. Portreleri karikatürize etmek, aydınlatmayı ince ayarlamak, siyah beyaza dönüştürmek, renkleri denemek, çeşitli düzenleme tekniklerini karıştırmak ve karmaşık görüntü efektleri oluşturmak; bunların tümü, AyarlamaBrightness, BinarizeFixed, Filter, ReplaceColor ve ApplyMask gibi görüntü filtreleri aracılığıyla elde edilebilir. Bu filtreler orijinal yüklenen fotoğraflara uygulanabilir. Web sayfanızın konusu ne olursa olsun, Karikatür tarzı görseller illüstrasyon amaçlı olarak uygundur. Bilimsel bir makale canlılık kazanırken, çeşitli içerik kullanıcılar için daha cazip hale gelir ve böylece web sitesi trafiği artar. APNG dosyalarını karikatürize etmek için şunu kullanacağız: Aspose.Imaging for Java Java platformu için zengin özelliklere sahip, güçlü ve kullanımı kolay bir görüntü işleme ve dönüştürme API’si olan API. En son sürümünü doğrudan adresinden indirebilirsiniz. Maven ve pom.xml dosyasına aşağıdaki konfigürasyonları ekleyerek Maven tabanlı projenize kurun.
Repository
<repository>
<id>AsposeJavaAPI</id>
<name>Aspose Java API</name>
<url>https://repository.aspose.com/repo/</url>
</repository>
Bağımlılık
<dependency>
<groupId>com.aspose</groupId>
<artifactId>aspose-imaging</artifactId>
<version>version of aspose-imaging API</version>
<classifier>jdk16</classifier>
</dependency>
APNG'leri Java aracılığıyla Karikatürleştirme Adımları
ihtiyacın var aspose-imaging-version-jdk16.jar aşağıdaki iş akışını kendi ortamınızda denemek için
- APNG dosyalarını Image.Load yöntemiyle yükleyin
- Resimleri karikatürize edin;
- Sıkıştırılmış görüntüyü Aspose.Imaging formatında diske kaydedin
sistem gereksinimleri
Aspose.Imaging for Java tüm büyük işletim sistemlerinde desteklenir. Sadece aşağıdaki ön koşullara sahip olduğunuzdan emin olun.
- JDK 1.6 veya üstü yüklü.
APNG resimleri karikatürize edin - Java
import com.aspose.imaging.*; | |
import com.aspose.imaging.fileformats.png.PngImage; | |
import com.aspose.imaging.imagefilters.filteroptions.FilterOptionsBase; | |
import com.aspose.imaging.imagefilters.filteroptions.MedianFilterOptions; | |
import com.aspose.imaging.imageoptions.PngOptions; | |
import com.aspose.imaging.masking.ImageMasking; | |
import com.aspose.imaging.masking.options.MaskingOptions; | |
import java.io.File; | |
import java.util.*; | |
import java.util.function.Consumer; | |
import java.util.function.Function; | |
import java.util.stream.Collectors; | |
cartoonify(); | |
public static void cartoonify() | |
{ | |
filterImages(image -> | |
{ | |
try (PngImage processedImage = new PngImage(image)) | |
{ | |
image.resize(image.getWidth() * 2, image.getHeight(), ResizeType.LeftTopToLeftTop); | |
ImageFilterExtensions.cartoonify(processedImage); | |
Graphics gr = new Graphics(image); | |
gr.drawImage(processedImage, processedImage.getWidth(), 0); | |
gr.drawLine(new Pen(Color.getDarkRed(), 3), processedImage.getWidth(), 0, processedImage.getWidth(), image.getHeight()); | |
} | |
}, "cartoonify"); | |
} | |
static String templatesFolder = "D:\\TestData\\"; | |
public static void filterImages(Consumer<RasterImage> doFilter, String filterName) | |
{ | |
List<String> rasterFormats = Arrays.asList("jpg", "png", "bmp", "apng", "dicom", | |
"jp2", "j2k", "tga", "webp", "tif", "gif", "ico"); | |
List<String> vectorFormats = Arrays.asList("svg", "otg", "odg", "eps", "wmf", "emf", "wmz", "emz", "cmx", "cdr"); | |
List<String> allFormats = new LinkedList<>(rasterFormats); | |
allFormats.addAll(vectorFormats); | |
allFormats.forEach( | |
formatExt -> | |
{ | |
String inputFile = templatesFolder + "template." + formatExt; | |
boolean isVectorFormat = vectorFormats.contains(formatExt); | |
//Need to rasterize vector formats before background remove | |
if (isVectorFormat) | |
{ | |
inputFile = rasterizeVectorImage(formatExt, inputFile); | |
} | |
String outputFile = templatesFolder + String.format("%s_%s.png", filterName, formatExt); | |
System.out.println("Processing " + formatExt); | |
try (RasterImage image = (RasterImage) Image.load(inputFile)) | |
{ | |
doFilter.accept(image); | |
//If image is multipage save each page to png to demonstrate results | |
if (image instanceof IMultipageImage && ((IMultipageImage) image).getPageCount() > 1) | |
{ | |
IMultipageImage multiPage = (IMultipageImage) image; | |
final int pageCount = multiPage.getPageCount(); | |
final Image[] pages = multiPage.getPages(); | |
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) | |
{ | |
String fileName = String.format("%s_page%d_%s.png", filterName, pageIndex, formatExt); | |
pages[pageIndex].save(fileName, new PngOptions()); | |
} | |
} | |
else | |
{ | |
image.save(outputFile, new PngOptions()); | |
} | |
} | |
//Remove rasterized vector image | |
if (isVectorFormat) | |
{ | |
new File(inputFile).delete(); | |
} | |
} | |
); | |
} | |
private static String rasterizeVectorImage(String formatExt, String inputFile) | |
{ | |
String outputFile = templatesFolder + "rasterized." + formatExt + ".png"; | |
try (Image image = Image.load(inputFile)) | |
{ | |
image.save(outputFile, new PngOptions()); | |
} | |
return outputFile; | |
} | |
interface IImageDataContext | |
{ | |
void applyData(); | |
} | |
class ImageFilterExtensions | |
{ | |
public static void cartoonify(RasterImage image) | |
{ | |
try (RasterImage outlines = detectOutlines(image, Color.getBlack())) | |
{ | |
image.adjustBrightness(30); | |
image.filter(image.getBounds(), new MedianFilterOptions(7)); | |
Graphics gr = new Graphics(image); | |
gr.drawImage(outlines, Point.getEmpty()); | |
} | |
} | |
public static RasterImage detectOutlines(RasterImage image, Color outlineColor) | |
{ | |
PngImage outlines = new PngImage(image); | |
IImageDataContext ctx = getDataContext(outlines); | |
applyConvolutionFilter(ctx, ConvolutionFilterOptions.getBlur()); | |
applyConvolutionFilter(ctx, ConvolutionFilterOptions.getOutline()); | |
ctx.applyData(); | |
outlines.binarizeFixed((byte)30); | |
ImageMasking.applyMask(outlines, outlines, new MaskingOptions() | |
{{ | |
setBackgroundReplacementColor(Color.getTransparent()); | |
}}); | |
outlines.replaceColor(Color.fromArgb(255, 255, 255), (byte)0, outlineColor); | |
applyConvolutionFilter(outlines, ConvolutionFilterOptions.getBlur()); | |
return outlines; | |
} | |
public static RasterImage applyOperationToRasterImage(RasterImage image, Consumer<RasterImage> operation) | |
{ | |
if (image instanceof IMultipageImage) | |
{ | |
IMultipageImage multipage = (IMultipageImage) image; | |
for (Image page : multipage.getPages()) | |
{ | |
operation.accept((RasterImage) page); | |
} | |
} | |
else | |
{ | |
operation.accept(image); | |
} | |
return image; | |
} | |
public static RasterImage applyFilter(RasterImage image, FilterOptionsBase filterOptions) | |
{ | |
return applyOperationToRasterImage(image, img -> | |
img.filter(img.getBounds(), filterOptions)); | |
} | |
public static RasterImage applyConvolutionFilter(RasterImage image, ConvolutionFilterOptions filterOptions) | |
{ | |
return applyOperationToRasterImage(image, img -> | |
{ | |
ImagePixelsLoader pixelsLoader = new ImagePixelsLoader(img.getBounds()); | |
img.loadPartialArgb32Pixels(img.getBounds(), pixelsLoader); | |
PixelBuffer outBuffer = new PixelBuffer(img.getBounds(), new int[img.getWidth() * img.getHeight()]); | |
ConvolutionFilter.doFiltering(pixelsLoader.getPixelsBuffer(), outBuffer, filterOptions); | |
img.saveArgb32Pixels(outBuffer.getRectangle(), outBuffer.getPixels()); | |
}); | |
} | |
public static IImageDataContext getDataContext(RasterImage image) | |
{ | |
if (image instanceof IMultipageImage) | |
{ | |
return new MultipageDataContext( | |
Arrays.stream(((IMultipageImage)image).getPages()).map(page -> { | |
ImageDataContext buf = new ImageDataContext((RasterImage) page); | |
buf.setBuffer(getImageBuffer((RasterImage)page)); | |
return buf; | |
}).collect(Collectors.toList())); | |
} | |
ImageDataContext buf = new ImageDataContext(image); | |
buf.setBuffer(getImageBuffer(image)); | |
return buf; | |
} | |
static IPixelBuffer getImageBuffer(RasterImage img) | |
{ | |
ImagePixelsLoader pixelsLoader = new ImagePixelsLoader(img.getBounds()); | |
img.loadPartialArgb32Pixels(img.getBounds(), pixelsLoader); | |
return pixelsLoader.getPixelsBuffer(); | |
} | |
public static IImageDataContext applyToDataContext(IImageDataContext dataContext, | |
Function<IPixelBuffer, IPixelBuffer> processor) | |
{ | |
if (dataContext instanceof MultipageDataContext) | |
{ | |
for (ImageDataContext context : (MultipageDataContext) dataContext) | |
{ | |
context.setBuffer(processor.apply(context.getBuffer())); | |
} | |
} | |
if (dataContext instanceof ImageDataContext) | |
{ | |
ImageDataContext ctx = (ImageDataContext)dataContext; | |
ctx.setBuffer(processor.apply(ctx.getBuffer())); | |
} | |
return dataContext; | |
} | |
public static IImageDataContext applyConvolutionFilter(IImageDataContext dataContext, | |
ConvolutionFilterOptions filterOptions) | |
{ | |
return applyToDataContext(dataContext, buffer -> | |
{ | |
PixelBuffer outBuffer = new PixelBuffer(buffer.getRectangle(), new int[buffer.getRectangle().getWidth() * buffer.getRectangle().getHeight()]); | |
ConvolutionFilter.doFiltering(buffer, outBuffer, filterOptions); | |
return outBuffer; | |
}); | |
} | |
} | |
class ImageDataContext implements IImageDataContext | |
{ | |
private final RasterImage image; | |
private IPixelBuffer buffer; | |
public ImageDataContext(RasterImage image) | |
{ | |
this.image = image; | |
} | |
public RasterImage getImage() | |
{ | |
return image; | |
} | |
public IPixelBuffer getBuffer() | |
{ | |
return buffer; | |
} | |
public void setBuffer(IPixelBuffer buffer) | |
{ | |
this.buffer = buffer; | |
} | |
public void applyData() | |
{ | |
this.buffer.saveToImage(this.image); | |
} | |
} | |
class MultipageDataContext extends LinkedList<ImageDataContext> implements IImageDataContext | |
{ | |
public MultipageDataContext(Collection<ImageDataContext> enumerable) | |
{ | |
addAll(enumerable); | |
} | |
public void applyData() | |
{ | |
for (ImageDataContext context : this) | |
{ | |
context.applyData(); | |
} | |
} | |
} | |
class ImagePixelsLoader implements IPartialArgb32PixelLoader | |
{ | |
private final CompositePixelBuffer pixelsBuffer; | |
public ImagePixelsLoader(Rectangle rectangle) | |
{ | |
this.pixelsBuffer = new CompositePixelBuffer(rectangle); | |
} | |
public CompositePixelBuffer getPixelsBuffer() | |
{ | |
return pixelsBuffer; | |
} | |
@Override | |
public void process(Rectangle pixelsRectangle, int[] pixels, Point start, Point end) | |
{ | |
this.pixelsBuffer.addPixels(pixelsRectangle,pixels); | |
} | |
} | |
interface IPixelBuffer | |
{ | |
Rectangle getRectangle(); | |
int get(int x, int y); | |
void set(int x, int y, int value); | |
void saveToImage(RasterImage image); | |
} | |
class PixelBuffer implements IPixelBuffer | |
{ | |
private final Rectangle rectangle; | |
private final int[] pixels; | |
public PixelBuffer(Rectangle rectangle,int[] pixels) | |
{ | |
this.rectangle = rectangle; | |
this.pixels = pixels; | |
} | |
@Override | |
public com.aspose.imaging.Rectangle getRectangle() | |
{ | |
return rectangle; | |
} | |
public int[] getPixels() | |
{ | |
return pixels; | |
} | |
@Override | |
public int get(int x, int y) | |
{ | |
return pixels[getIndex(x,y)]; | |
} | |
@Override | |
public void set(int x, int y, int value) | |
{ | |
pixels[getIndex(x,y)] = value; | |
} | |
public void saveToImage(RasterImage image) | |
{ | |
image.saveArgb32Pixels(this.rectangle, this.pixels); | |
} | |
public boolean contains(int x,int y) | |
{ | |
return this.rectangle.contains(x,y); | |
} | |
private int getIndex(int x,int y) | |
{ | |
x -= this.rectangle.getLeft(); | |
y -= this.rectangle.getTop(); | |
return x + y * this.rectangle.getWidth(); | |
} | |
} | |
class CompositePixelBuffer implements IPixelBuffer | |
{ | |
private final List<PixelBuffer> _buffers = new ArrayList<>(); | |
private final Rectangle rectangle; | |
public CompositePixelBuffer(Rectangle rectangle) | |
{ | |
this.rectangle = rectangle; | |
} | |
@Override | |
public com.aspose.imaging.Rectangle getRectangle() | |
{ | |
return rectangle; | |
} | |
@Override | |
public int get(int x, int y) | |
{ | |
return getBuffer(x,y).get(x, y); | |
} | |
@Override | |
public void set(int x, int y, int value) | |
{ | |
getBuffer(x, y).set(x, y, value); | |
} | |
@Override | |
public void saveToImage(RasterImage image) | |
{ | |
for (PixelBuffer buffer : this._buffers) | |
{ | |
buffer.saveToImage(image); | |
} | |
} | |
public void addPixels(Rectangle rectangle,int[] pixels) | |
{ | |
if(rectangle.intersectsWith(rectangle)) | |
{ | |
this._buffers.add(new PixelBuffer(rectangle,pixels)); | |
} | |
} | |
private PixelBuffer getBuffer(int x,int y) | |
{ | |
return this._buffers.stream().filter(b -> b.contains(x,y)).findFirst().get(); | |
} | |
} | |
class ConvolutionFilter | |
{ | |
public static void doFiltering( | |
IPixelBuffer inputBuffer, | |
IPixelBuffer outputBuffer, | |
ConvolutionFilterOptions options) | |
{ | |
double factor = options.getFactor(); | |
int bias = options.getBias(); | |
double[][] kernel = options.getKernel(); | |
int filterWidth = kernel[0].length; | |
int filterCenter = (filterWidth - 1) / 2; | |
int x, y; | |
int filterX, filterY, filterPx, filterPy, filterYPos, pixel; | |
double r, g, b, kernelValue; | |
int top = inputBuffer.getRectangle().getTop(); | |
int bottom = inputBuffer.getRectangle().getBottom(); | |
int left = inputBuffer.getRectangle().getLeft(); | |
int right = inputBuffer.getRectangle().getRight(); | |
for (y = top; y < bottom; y++) | |
{ | |
for (x = left; x < right; x++) | |
{ | |
r = 0; | |
g = 0; | |
b = 0; | |
for (filterY = -filterCenter; filterY <= filterCenter; filterY++) | |
{ | |
filterYPos = filterY + filterCenter; | |
filterPy = filterY + y; | |
if (filterPy >= top && filterPy < bottom) | |
{ | |
for (filterX = -filterCenter; filterX <= filterCenter; filterX++) | |
{ | |
filterPx = filterX + x; | |
if (filterPx >= left && filterPx < right) | |
{ | |
kernelValue = kernel[filterYPos][filterX + filterCenter]; | |
pixel = inputBuffer.get(filterPx, filterPy); | |
r += ((pixel >> 16) & 0xFF) * kernelValue; | |
g += ((pixel >> 8) & 0xFF) * kernelValue; | |
b += (pixel & 0xFF) * kernelValue; | |
} | |
} | |
} | |
} | |
r = (factor * r) + bias; | |
g = (factor * g) + bias; | |
b = (factor * b) + bias; | |
r = r > 255 ? 255 : (r < 0 ? 0 : r); | |
g = g > 255 ? 255 : (g < 0 ? 0 : g); | |
b = b > 255 ? 255 : (b < 0 ? 0 : b); | |
outputBuffer.set(x, y, (inputBuffer.get(x, y) & 0xFF000000) | ((int)r << 16) | ((int)g << 8) | (int)b); | |
} | |
} | |
} | |
} | |
class ConvolutionFilterOptions | |
{ | |
private double factor = 1.0; | |
public double getFactor() | |
{ | |
return factor; | |
} | |
public void setFactor(double factor) | |
{ | |
this.factor = factor; | |
} | |
private int bias = 0; | |
public int getBias() | |
{ | |
return bias; | |
} | |
public void setBias(int bias) | |
{ | |
this.bias = bias; | |
} | |
private double[][] kernel; | |
public double[][] getKernel() | |
{ | |
return kernel; | |
} | |
public void setKernel(double[][] kernel) | |
{ | |
this.kernel = kernel; | |
} | |
public ConvolutionFilterOptions() | |
{ | |
} | |
public ConvolutionFilterOptions(double[][] kernel) | |
{ | |
this.kernel = kernel; | |
} | |
public static ConvolutionFilterOptions getBlur() | |
{ | |
ConvolutionFilterOptions filterOptions = new ConvolutionFilterOptions(); | |
filterOptions.setKernel(new double[][] { { 1, 2, 1 }, { 2, 4, 2 }, { 1, 2, 1 } }); | |
filterOptions.setFactor(0.25 * 0.25); | |
return filterOptions; | |
} | |
public static ConvolutionFilterOptions getSharpen() | |
{ | |
return new ConvolutionFilterOptions(new double[][] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); | |
} | |
public static ConvolutionFilterOptions getEmboss() | |
{ | |
return new ConvolutionFilterOptions(new double[][] { { -2, -1, 0 }, { -1, 1, 1 }, { 0, 1, 2 } }); | |
} | |
public static ConvolutionFilterOptions getOutline() | |
{ | |
return new ConvolutionFilterOptions(new double[][] { { -1, -1, -1 }, { -1, 8, -1 }, { -1, -1, -1 } }); | |
} | |
public static ConvolutionFilterOptions getBottomSobel() | |
{ | |
return new ConvolutionFilterOptions(new double[][] { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } }); | |
} | |
public static ConvolutionFilterOptions getTopSobel() | |
{ | |
return new ConvolutionFilterOptions(new double[][] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } }); | |
} | |
public static ConvolutionFilterOptions getLeftSobel() | |
{ | |
return new ConvolutionFilterOptions(new double[][] { { 1, 0, -1 }, { 2, 0, -2 }, { 1, 0, -1 } }); | |
} | |
public static ConvolutionFilterOptions getRightSobel() | |
{ | |
return new ConvolutionFilterOptions(new double[][] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }); | |
} | |
} |
Java API için Aspose.Imaging Hakkında
Aspose.Imaging API, uygulamalar içinde görüntüleri (fotoğrafları) oluşturmak, değiştirmek, çizmek veya dönüştürmek için kullanılan bir görüntü işleme çözümüdür. Şunları sunar: Çeşitli görüntü formatları (tek tip çok sayfalı veya çok çerçeveli görüntü işleme dahil) arasındaki dönüştürmeler dahil ancak bunlarla sınırlı olmamak üzere çapraz platform Görüntü işleme, çizim, grafik temel öğeleriyle çalışma, dönüştürmeler (yeniden boyutlandırma, kırpma, çevirme ve döndürme) gibi değişiklikler , ikilileştirme, gri tonlama, ayarlama), gelişmiş görüntü işleme özellikleri (filtreleme, renk taklidi, maskeleme, eğrilik düzeltme) ve bellek optimizasyon stratejileri. Bu bağımsız bir kitaplıktır ve görüntü işlemleri için herhangi bir yazılıma bağlı değildir. Projelere yerel API’ler ile yüksek performanslı görüntü dönüştürme özellikleri kolayca eklenebilir. Bunlar %100 özel şirket içi API’lerdir ve görüntüler sunucularınızda işlenir.APNG’leri Çevrimiçi Uygulama ile Cartoonify
Canlı Demolar web sitemizi ziyaret ederek APNG belgelerini karikatürize edin. Canlı demo aşağıdaki avantajlara sahiptir
APNG Nedir APNG Dosya formatı
.apng (Animasyonlu Taşınabilir Ağ Grafikleri) uzantılı bir dosya, bir raster grafik biçimidir ve Taşınabilir Ağ Grafiğinin (PNG) resmi olmayan bir uzantısıdır. Bir animasyon dizisini temsil eden birden çok kareden (PNG görüntüsünün her biri) oluşur. Bu, bir GIF dosyasına benzer görselleştirme sağlar. APNG dosyaları 24 bit görüntüleri ve 8 bit şeffaflığı destekler. APNG, animasyonsuz GIF dosyalarıyla geriye dönük olarak uyumludur. APNG dosyaları aynı .png uzantısını kullanır ve Mozilla Firefox, APNG destekli Chrome, iOS 10 için iMessage uygulamaları gibi uygulamalar tarafından açılabilir.
Daha fazla okuDesteklenen Diğer Cartoonify Formatları
Java kullanarak, dahil olmak üzere farklı formatları kolayca Karikatürleştirebilirsiniz.