When saving bitmap to disk, solid paths show artifacts
<p>[Edit: I've made a minimal project to try to narrow down what's going on.  The code at the bottom still generates the same artifacts when saved]</p>

<p>I have an app that draws simple 2D geometry using Paths.  The shapes are all solid colors, sometimes with alpha &lt; 255, and may be decorated with lines.  In the View that draws the geometry, there has never been an issue with how things get drawn.  However, when I use the same code to draw to a Bitmap, and then save it as either a JPEG (with 100 quality) or PNG, there is always the same artifacting in the solid-colored areas of the output files.  It's a sort of mottling that is usually associated with JPEG compression.</p>

<p>Screenshot of View:
<a href="https://i.stack.imgur.com/srSLh.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/srSLh.png" alt="Screenshot of Activity"></a></p>

<p>Saved image:
<a href="https://i.stack.imgur.com/GIG27.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/GIG27.png" alt="Saved image file"></a></p>

<p>Zoom in on artifacts:
<a href="https://i.stack.imgur.com/x24KJ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/x24KJ.png" alt="Zoom in on artifacts"></a></p>

<p>I have tried the following</p>

<ul>
<li>Saving to either PNG and JPEG</li>
<li>Turning dithering and antialiasing on and off</li>
<li>Increasing the DPI of the Bitmap, and also allowed the Bitmap to use its default API</li>
<li>Applying the matrix I use as a camera to the geometric representation, instead of applying it to the Canvas for the bitmap</li>
<li>Turning HW Acceleration on and off app-wide</li>
<li>Using a 3rd party library to save the Bitmap to a .bmp file</li>
</ul>

<p>All yield the same artifacts, neither making it worse nor better.</p>

<pre><code>public class MainActivity extends AppCompatActivity {
Context context;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    this.context = getApplicationContext();
}

// button OnClick listener
public void saveImage(View view) {
    new saveBitmapToDisk().execute(false);
}

public Bitmap getBitmap() {
    final int bitmapHeight = 600, bitmapWidth = 600;
    Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
    Canvas bitmapCanvas = new Canvas(bitmap);

    float[] triangle = new float[6];
    triangle[0] = bitmapWidth / 2;
    triangle[1] = 0;
    triangle[2] = 0;
    triangle[3] = bitmapHeight / 2;
    triangle[4] = bitmapWidth / 2;
    triangle[5] = bitmapHeight / 2;

    Path solidPath = new Path();
    Paint solidPaint = new Paint();
    solidPaint.setStyle(Paint.Style.FILL);

    solidPath.moveTo(triangle[0], triangle[1]);

    for(int i = 2; i &lt; triangle.length; i += 2)
        solidPath.lineTo(triangle[i], triangle[i+1]);

    solidPath.close();

    solidPaint.setColor(Color.GREEN);
    bitmapCanvas.drawPath(solidPath, solidPaint);
    return bitmap;
}

private class saveBitmapToDisk extends AsyncTask&lt;Boolean, Integer, Uri&gt; {
    Boolean toShare;

    @Override
    protected Uri doInBackground(Boolean... shareFile) {
        this.toShare = shareFile[0];
        final String appName = context.getResources().getString(R.string.app_name);
        final String IMAGE_SAVE_DIRECTORY = String.format("/%s/", appName);
        final String fullPath = Environment.getExternalStorageDirectory().getAbsolutePath() + IMAGE_SAVE_DIRECTORY;
        File dir, file;

        try {
            dir = new File(fullPath);
            if (!dir.exists())
                dir.mkdirs();

            OutputStream fOut;

            file = new File(fullPath, String.format("%s.png", appName));

            for (int suffix = 0; file.exists(); suffix++)
                file = new File(fullPath, String.format("%s%03d.png", appName, suffix));

            file.createNewFile();
            fOut = new FileOutputStream(file);

            Bitmap saveBitmap = getBitmap();
            saveBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
            fOut.flush();
            fOut.close();
            MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());

        } catch (OutOfMemoryError e) {
            Log.e("MainActivity", "Out of Memory saving bitmap; bitmap is too large");
            return null;
        } catch (Exception e) {
            Log.e("MainActivity", e.getMessage());
            return null;
        }

        return Uri.fromFile(file);
    }

    @Override
    protected void onPostExecute(Uri uri) {
        super.onPostExecute(uri);
        Toast.makeText(context, "Image saved", Toast.LENGTH_SHORT).show();
    }
}
}
</code></pre>