6

ユーザーがイメージを参照してから、キャンバスに描画されたイメージのプレビューを表示できるダイアログを作成しました。画像は、ボックスに収まっている間、縦横比が維持されるようにスケーリングされます。この回答で見つかったサイズ変更の方法を使用しました。これには、画像を SWT から AWT に変換し、サイズ変更を実行し、AWT から SWT に変換し、最後にキャンバスに描画します。このプロセスは時間と処理能力の点で非常にコストがかかるため、画像が正確に正しいサイズである場合はサイズ変更の手順をスキップすることを選択し、したがって、いかなる方法でも変換する必要はありません。

この問題は、アルファ透明度のある画像を扱うときに発生します。場合によっては、最初に変換された透明度のある画像が、黒い背景のキャンバスに描画されます。キャンバスの正確なサイズにサイズ変更されているため、変換されていない同じイメージのコピーは、白い背景を持ちます。

Fluttershy のバックグラウンドは不安定で一貫性がありません。

ただし、これも常に当てはまるわけではありません。背景が透明な一部の画像は、変換されているかどうかにかかわらず、常に白で表示されます。

彼らは怒りの日を見てきました。

SWT キャンバスで透明な背景を持つ画像がある色で別の色で描画される原因は何ですか? AWT 変換はどのように影響しますか? また、必要に応じて一貫性を持たせるにはどうすればよいですか?

別のソースから全体を取得した変換コードを次に示します。

public static BufferedImage convertToAWT (ImageData data) {
    ColorModel colorModel = null;
    PaletteData palette = data.palette;
    if (palette.isDirect) {
        colorModel = new DirectColorModel(data.depth, palette.redMask, palette.greenMask, palette.blueMask);
        BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height),
                false, null);
        WritableRaster raster = bufferedImage.getRaster();
        int[] pixelArray = new int[3];
        for (int y = 0; y < data.height; y++) {
            for (int x = 0; x < data.width; x++) {
                int pixel = data.getPixel(x, y);
                RGB rgb = palette.getRGB(pixel);
                pixelArray[0] = rgb.red;
                pixelArray[1] = rgb.green;
                pixelArray[2] = rgb.blue;
                raster.setPixels(x, y, 1, 1, pixelArray);
            }
        }
        return bufferedImage;
    }
    else {
        RGB[] rgbs = palette.getRGBs();
        byte[] red = new byte[rgbs.length];
        byte[] green = new byte[rgbs.length];
        byte[] blue = new byte[rgbs.length];
        for (int i = 0; i < rgbs.length; i++) {
            RGB rgb = rgbs[i];
            red[i] = (byte) rgb.red;
            green[i] = (byte) rgb.green;
            blue[i] = (byte) rgb.blue;
        }
        if (data.transparentPixel != -1) {
            colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue, data.transparentPixel);
        } else {
            colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue);
        }
        BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height),
                false, null);
        WritableRaster raster = bufferedImage.getRaster();
        int[] pixelArray = new int[1];
        for (int y = 0; y < data.height; y++) {
            for (int x = 0; x < data.width; x++) {
                int pixel = data.getPixel(x, y);
                pixelArray[0] = pixel;
                raster.setPixel(x, y, pixelArray);
            }
        }
        return bufferedImage;
    }
}

public static ImageData convertToSWT (BufferedImage bufferedImage) {
    if (bufferedImage.getColorModel() instanceof DirectColorModel) {
        DirectColorModel colorModel = (DirectColorModel) bufferedImage.getColorModel();
        PaletteData palette = new PaletteData(colorModel.getRedMask(), colorModel.getGreenMask(), colorModel.getBlueMask());
        ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette);
        WritableRaster raster = bufferedImage.getRaster();
        int[] pixelArray = new int[3];
        for (int y = 0; y < data.height; y++) {
            for (int x = 0; x < data.width; x++) {
                raster.getPixel(x, y, pixelArray);
                int pixel = palette.getPixel(new RGB(pixelArray[0], pixelArray[1], pixelArray[2]));
                data.setPixel(x, y, pixel);
            }
        }
        return data;
    }
    else if (bufferedImage.getColorModel() instanceof IndexColorModel) {
        IndexColorModel colorModel = (IndexColorModel) bufferedImage.getColorModel();
        int size = colorModel.getMapSize();
        byte[] reds = new byte[size];
        byte[] greens = new byte[size];
        byte[] blues = new byte[size];
        colorModel.getReds(reds);
        colorModel.getGreens(greens);
        colorModel.getBlues(blues);
        RGB[] rgbs = new RGB[size];
        for (int i = 0; i < rgbs.length; i++) {
            rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF);
        }
        PaletteData palette = new PaletteData(rgbs);
        ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette);
        data.transparentPixel = colorModel.getTransparentPixel();
        WritableRaster raster = bufferedImage.getRaster();
        int[] pixelArray = new int[1];
        for (int y = 0; y < data.height; y++) {
            for (int x = 0; x < data.width; x++) {
                raster.getPixel(x, y, pixelArray);
                data.setPixel(x, y, pixelArray[0]);
            }
        }
        return data;
    }
    return null;
}
4

2 に答える 2

2

今は答えが少し遅いですが、同様の経験と問題があったので、私の発見が他の人に役立つかもしれないと思いました.

元の問題は、SWT->AWT および AWT->SWT 変換を行う提供されたコードにあります。ダイレクト パレットを使用する場合、透明度 (アルファ) はまったく考慮されませんが、これはインデックス付きパレット用です。そのため、機能する画像と機能しない画像があります。

透明性に対処するためにそのコードを修正するのは比較的簡単ですが、サイズ変更された画像を取得するために AWT 経由で取得する必要がない、より優れたソリューションがあります。

変換された画像のアンチエイリアシング (滑らかさ) を気にしない場合、簡単な解決策は次のとおりです。

Image newImage = new Image(image.getDevice(),
                    image.getImageData().scaledTo(newWidth, newHeight));

滑らかさを気にする場合、解決策はほぼ同じです。

Image newImage = new Image(image.getDevice(), newWidth, newHeight);
GC gc = new GC(newImage);
gc.setAdvanced(true);
gc.setAntialias(SWT.ON);
gc.drawImage(image, 0, 0, origWidth, origHeight, 0, 0, newWidth, newHeight);
gc.dispose();
于 2015-05-18T12:09:15.707 に答える
2

わかりました、ようやくあなたの要件を理解したと思うので、回答を投稿することにしました。私がそれを正しく理解していることを確認させてください:

サイズを変更できるImage何らかの形でアプリに表示したいとします。Widget画像はその親に合わせてサイズ変更し、透過性を維持する必要があります。

Label画像のサイズを変更してやその他ので表示する代わりに、を使用し、 を使用して画像を適切なサイズにペイントWidgetできます。CanvasGC#drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight)

この関数を使用するにはImage、 のサイズ、 のサイズ、Canvasおよび正しくスケーリングされた (アスペクト比) バージョンのイメージのサイズが必要です。

コードは次のとおりです。

public static void main(String[] args)
{
    Display display = Display.getDefault();
    final Shell shell = new Shell(display);
    shell.setLayout(new GridLayout(1, false));

    /* Load the image and calculate size and ratio */
    final Image image = new Image(display, "settings.png");
    final Rectangle imageSize = image.getBounds();
    final double imageRatio = 1.0 * imageSize.width / imageSize.height;

    /* Define the canvas and set the background color */
    final Canvas canvas = new Canvas(shell, SWT.BORDER);
    canvas.setBackground(display.getSystemColor(SWT.COLOR_DARK_GRAY));
    canvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    canvas.addListener(SWT.Paint, new Listener()
    {
        @Override
        public void handleEvent(Event e)
        {
            Rectangle canvasSize = canvas.getBounds();

            double canvasRatio = 1.0 * canvasSize.width / canvasSize.height;

            int newHeight;
            int newWidth;

            /* Determine scaled height and width of the image */
            if (canvasRatio > imageRatio)
            {
                newWidth = (int) (imageSize.width * (1.0 * canvasSize.height / imageSize.height));
                newHeight = (int) (canvasSize.height);
            }
            else
            {
                newWidth = (int) (canvasSize.width);
                newHeight = (int) (imageSize.height * (1.0 * canvasSize.width / imageSize.width));
            }

            /* Compute position such that the image is centered in the canvas */
            int top = (int) ((canvasSize.height - newHeight) / 2.0);
            int left = (int) ((canvasSize.width - newWidth) / 2.0);

            /* Draw the image */
            e.gc.drawImage(image, 0, 0, imageSize.width, imageSize.height, left, top, newWidth, newHeight);
        }
    });

    shell.pack();
    shell.open();
    while (!shell.isDisposed())
    {
        if (!display.readAndDispatch())
            display.sleep();
    }
    display.dispose();

    /* DISPOSE THE IMAGE !!! */
    image.dispose();
}

そして、これは開始後の外観です。

ここに画像の説明を入力

サイズ変更後:

ここに画像の説明を入力


: Windows でテストする時間はありませんでしたが、動作することはかなり確信しています。

Windowsでも動作します!


編集

次の行を追加して、アンチエイリアシングを有効にします。

e.gc.setAntialias(SWT.ON);
e.gc.setAdvanced(true);
于 2013-10-12T08:44:59.693 に答える