Project

General

Profile

Download (10.8 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / bandaged / BandagedCreatorWorkerThread.java @ 7cb8d4b0

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.bandaged;
21

    
22
import android.app.Activity;
23
import android.content.Intent;
24
import android.graphics.Bitmap;
25
import android.net.Uri;
26
import android.widget.Toast;
27

    
28
import java.io.BufferedOutputStream;
29
import java.io.File;
30
import java.io.FileOutputStream;
31
import java.io.IOException;
32
import java.lang.ref.WeakReference;
33
import java.nio.ByteBuffer;
34
import java.nio.ByteOrder;
35
import java.util.Vector;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38

    
39
class BandagedCreatorWorkerThread extends Thread
40
  {
41
  private static Vector<WorkLoad> mBuffers;
42
  private static BandagedCreatorWorkerThread mThis=null;
43
  private static WeakReference<Activity> mWeakAct;
44

    
45
  private static class WorkLoad
46
    {
47
    ByteBuffer buffer;
48
    int width;
49
    int height;
50
    int numColors;
51
    String filename;
52

    
53
    WorkLoad(ByteBuffer buf, int w, int h, int n, String name)
54
      {
55
      buffer   = buf;
56
      width    = w;
57
      height   = h;
58
      numColors= n;
59
      filename = name;
60
      }
61
    }
62

    
63
///////////////////////////////////////////////////////////////////////////////////////////////////
64

    
65
  private BandagedCreatorWorkerThread()
66
    {
67
    }
68

    
69
///////////////////////////////////////////////////////////////////////////////////////////////////
70

    
71
  static void create(Activity act)
72
    {
73
    mWeakAct = new WeakReference<>(act);
74

    
75
    if( mThis==null )
76
      {
77
      mBuffers = new Vector<>();
78
      mThis = new BandagedCreatorWorkerThread();
79
      mThis.start();
80
      }
81
    }
82

    
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84

    
85
  public void run()
86
    {
87
    WorkLoad load;
88

    
89
    while(true)
90
      {
91
      synchronized(mThis)
92
        {
93
        while( mBuffers.size()>0 )
94
          {
95
          load = mBuffers.remove(0);
96
          process(load);
97
          }
98

    
99
        try  { mThis.wait(); }
100
        catch(InterruptedException ex) { }
101
        }
102
      }
103
    }
104

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

    
107
  static void newBuffer(ByteBuffer buffer, int width, int height, int numColors, String filename)
108
    {
109
    synchronized(mThis)
110
      {
111
      WorkLoad load = new WorkLoad(buffer,width,height,numColors,filename);
112
      mBuffers.add(load);
113
      mThis.notify();
114
      }
115
    }
116

    
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118

    
119
  private boolean containsBlackness(byte[] tmp, int width)
120
    {
121
    for(int i=0; i<width; i++)
122
      {
123
      if( tmp[4*i]==0 && tmp[4*i+3]==-1 ) return true;
124
      }
125

    
126
    return false;
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
  private int computeFirstRow(ByteBuffer buf, byte[] tmp, int width, int height)
132
    {
133
    int wBytes = 4*width;
134

    
135
    for(int i=0; i<height; i++)
136
      {
137
      buf.position(i*wBytes);
138
      buf.get(tmp);
139

    
140
      if( containsBlackness(tmp,width) ) return i;
141
      }
142

    
143
    return -1;
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  private int computeLastRow(ByteBuffer buf, byte[] tmp, int width, int height)
149
    {
150
    int wBytes = 4*width;
151

    
152
    for(int i=height-1; i>=0; i--)
153
      {
154
      buf.position(i*wBytes);
155
      buf.get(tmp);
156

    
157
      if( containsBlackness(tmp,width) ) return i;
158
      }
159

    
160
    return -1;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164
// GL uses a coordinate system from mathematics; i.e. (0,0) is in the lower-left corner. 2D stuff
165
// has the origin on the upper-left corner; we have to flip our bitmap upside down!
166
//
167
// We also need to figure out the topmost and bottommost rows where the object starts and cut out
168
// a square section from the 'input' so that the object is vertically centralized.
169

    
170
  private ByteBuffer adjustBuffer(ByteBuffer input, byte[] tmp, int width, int height)
171
    {
172
    int wBytes = 4*width;
173

    
174
    ByteBuffer output = ByteBuffer.allocateDirect(wBytes*width);
175
    output.order(ByteOrder.LITTLE_ENDIAN);
176

    
177
    int firstRow = computeFirstRow(input,tmp,width,height);
178
    int lastRow  = computeLastRow(input,tmp,width,height);
179

    
180
    int startRow = (firstRow+lastRow+width)/2;
181

    
182
    for(int i=0; i<width; i++)
183
      {
184
      input.position((startRow-i)*wBytes);
185
      input.get(tmp);
186
      output.position(i*wBytes);
187
      output.put(tmp);
188
      }
189

    
190
    output.rewind();
191
    return output;
192
    }
193

    
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195

    
196
  private void replaceColor(byte[] tmp, int index, int numColors)
197
    {
198
    byte A = (byte)0xab;
199
    int CUTOFF = 100;
200

    
201
    switch(numColors)
202
      {
203
      case 4: if( tmp[index+1]==0 ) { tmp[index]=A; tmp[index+1]=0; tmp[index+2]=0; }
204
              else
205
                {
206
                if( tmp[index]==tmp[index+1] )
207
                  {
208
                  if( tmp[index]<0 || tmp[index]>CUTOFF )  { tmp[index]=A; tmp[index+1]=A; tmp[index+2]=0; }
209
                  }
210
                else { tmp[index]=0; tmp[index+1]=0; tmp[index+2]=A; }
211
                }
212
              break;
213
      case 6: if( tmp[index+2]!=0 )
214
                {
215
                if( tmp[index]==0 ) { tmp[index]=0; tmp[index+1]=0; tmp[index+2]=A; }
216
                }
217
              else
218
                {
219
                if( tmp[index]==tmp[index+1] ) { tmp[index]=A; tmp[index+1]=A; tmp[index+2]=0; }
220
                else { tmp[index]=A; tmp[index+1]=0; tmp[index+2]=0; }
221
                }
222
              break;
223
      case 8: if( tmp[index+2]!=0 )
224
                {
225
                if( tmp[index+1]==0 ) { tmp[index]=A; tmp[index+1]=0; tmp[index+2]=0; }
226
                }
227
              else
228
                {
229
                if( tmp[index+1]==0 ) { tmp[index]=0; tmp[index+1]=0; tmp[index+2]=A; }
230
                else
231
                  {
232
                  if( tmp[index]==tmp[index+1] ) { tmp[index]=A; tmp[index+1]=A; tmp[index+2]=0; }
233
                  else { tmp[index]=0; tmp[index+1]=A; tmp[index+2]=0; }
234
                  }
235
                }
236
              break;
237

    
238
      case 12:if( tmp[index+2]==0 )
239
                {
240
                if( tmp[index+1]==0 )  {tmp[index]=A; tmp[index+1]=0; tmp[index+2]=0;}
241
                else  {tmp[index]=0; tmp[index+1]=A; tmp[index+2]=0;}
242
                }
243
              else
244
                {
245
                if( tmp[index]==tmp[index+1] )
246
                  {
247
                  if( tmp[index]<0 || tmp[index]>CUTOFF ) {tmp[index]=A; tmp[index+1]=A; tmp[index+2]=0;}
248
                  }
249
                else  {tmp[index]=0; tmp[index+1]=0; tmp[index+2]=A;}
250
                }
251
              break;
252
      }
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256

    
257
  private ByteBuffer replaceColors(ByteBuffer input, byte[] tmp, int size, int numColors)
258
    {
259
    int marker = (int)(255*BandagedCreatorRenderer.BRIGHTNESS);
260
    int wBytes = 4*size;
261

    
262
    ByteBuffer output = ByteBuffer.allocateDirect(wBytes*size);
263
    output.order(ByteOrder.LITTLE_ENDIAN);
264

    
265
    for(int i=0; i<size; i++)
266
      {
267
      input.position(i*wBytes);
268
      input.get(tmp);
269

    
270
      for(int j=0; j<size; j++)
271
        {
272
        if( tmp[4*j]==marker && tmp[4*j+1]==marker && tmp[4*j+2]==marker )
273
          {
274
          tmp[4*j  ]=0;
275
          tmp[4*j+1]=0;
276
          tmp[4*j+2]=0;
277
          tmp[4*j+3]=0;
278
          }
279
        else if( tmp[4*j]!=0 || tmp[4*j+1]!=0 || tmp[4*j+2]!=0 ) replaceColor(tmp,4*j,numColors);
280
        }
281

    
282
      output.position(i*wBytes);
283
      output.put(tmp);
284
      }
285

    
286
    output.rewind();
287
    return output;
288
    }
289

    
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

    
292
  private void process(WorkLoad load)
293
    {
294
    int width = load.width;
295
    int height= load.height;
296

    
297
    byte[] tmp = new byte[4*width];
298
    ByteBuffer bufSquare = adjustBuffer(load.buffer,tmp,width,height);
299
    ByteBuffer bufTransp = replaceColors(bufSquare,tmp,width,load.numColors);
300

    
301
    final String filename = load.filename;
302
    BufferedOutputStream bos =null;
303
    final Activity act = mWeakAct.get();
304

    
305
    try
306
      {
307
      bos = new BufferedOutputStream(new FileOutputStream(filename));
308
      Bitmap bmp = Bitmap.createBitmap( width, width, Bitmap.Config.ARGB_8888);
309
      bmp.copyPixelsFromBuffer(bufTransp);
310
      bmp.compress(Bitmap.CompressFormat.PNG, 90, bos);
311

    
312
      BandagedCreatorActivity cact = (BandagedCreatorActivity)act;
313
      cact.iconCreationDone(bmp);
314
      }
315
    catch(final Exception ex)
316
      {
317
      act.runOnUiThread(new Runnable()
318
        {
319
        public void run()
320
          {
321
          Toast.makeText(act,
322
              "Saving to \n\n"+filename+"\n\n failed: "+"\n\n"+ex.getMessage() ,
323
              Toast.LENGTH_LONG).show();
324
          }
325
        });
326
      }
327
    finally
328
      {
329
      if(bos!=null)
330
        {
331
        try { bos.close(); }
332
        catch(IOException io) {}
333
        }
334
      }
335

    
336
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
337
    File f = new File(filename);
338
    Uri contentUri = Uri.fromFile(f);
339
    mediaScanIntent.setData(contentUri);
340
    act.sendBroadcast(mediaScanIntent);
341
    }
342
  }
(6-6/13)