Project

General

Profile

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

magiccube / src / main / java / org / distorted / bandaged / BandagedCreatorWorkerThread.java @ 707f79ff

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 0;
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 width-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
    int startRow = (firstRow+lastRow+width)/2;
180

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

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

    
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194

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

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

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

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

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

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

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

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

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

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

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

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

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

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

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

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

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