Project

General

Profile

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

magiccube / src / main / java / org / distorted / bandaged / BandagedCreatorWorkerThread.java @ f404152d

1 7cb8d4b0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6 44fec653 Leszek Koltunski
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8 7cb8d4b0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10
package org.distorted.bandaged;
11
12
import android.app.Activity;
13
import android.content.Intent;
14
import android.graphics.Bitmap;
15
import android.net.Uri;
16
import android.widget.Toast;
17
18
import java.io.BufferedOutputStream;
19
import java.io.File;
20
import java.io.FileOutputStream;
21
import java.io.IOException;
22
import java.lang.ref.WeakReference;
23
import java.nio.ByteBuffer;
24
import java.nio.ByteOrder;
25
import java.util.Vector;
26
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28
29
class BandagedCreatorWorkerThread extends Thread
30
  {
31
  private static Vector<WorkLoad> mBuffers;
32
  private static BandagedCreatorWorkerThread mThis=null;
33
  private static WeakReference<Activity> mWeakAct;
34
35
  private static class WorkLoad
36
    {
37
    ByteBuffer buffer;
38
    int width;
39
    int height;
40
    int numColors;
41
    String filename;
42
43
    WorkLoad(ByteBuffer buf, int w, int h, int n, String name)
44
      {
45
      buffer   = buf;
46
      width    = w;
47
      height   = h;
48
      numColors= n;
49
      filename = name;
50
      }
51
    }
52
53 ba52835a Leszek Koltunski
  private int mCreatedBufSize;
54
55 7cb8d4b0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
56
57
  private BandagedCreatorWorkerThread()
58
    {
59
    }
60
61
///////////////////////////////////////////////////////////////////////////////////////////////////
62
63
  static void create(Activity act)
64
    {
65
    mWeakAct = new WeakReference<>(act);
66
67
    if( mThis==null )
68
      {
69
      mBuffers = new Vector<>();
70
      mThis = new BandagedCreatorWorkerThread();
71
      mThis.start();
72
      }
73
    }
74
75
///////////////////////////////////////////////////////////////////////////////////////////////////
76
77
  public void run()
78
    {
79
    WorkLoad load;
80
81
    while(true)
82
      {
83
      synchronized(mThis)
84
        {
85
        while( mBuffers.size()>0 )
86
          {
87
          load = mBuffers.remove(0);
88
          process(load);
89
          }
90
91
        try  { mThis.wait(); }
92 f404152d Leszek Koltunski
        catch(InterruptedException ignored) { }
93 7cb8d4b0 Leszek Koltunski
        }
94
      }
95
    }
96
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98
99
  static void newBuffer(ByteBuffer buffer, int width, int height, int numColors, String filename)
100
    {
101
    synchronized(mThis)
102
      {
103
      WorkLoad load = new WorkLoad(buffer,width,height,numColors,filename);
104
      mBuffers.add(load);
105
      mThis.notify();
106
      }
107
    }
108
109
///////////////////////////////////////////////////////////////////////////////////////////////////
110
111 ba52835a Leszek Koltunski
  private int firstBlackPixel(byte[] tmp, int width)
112 7cb8d4b0 Leszek Koltunski
    {
113
    for(int i=0; i<width; i++)
114
      {
115 ba52835a Leszek Koltunski
      if( tmp[4*i]==0 && tmp[4*i+3]==-1 ) return i;
116
      }
117
118
    return -1;
119
    }
120
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122
123
  private int lastBlackPixel(byte[] tmp, int width)
124
    {
125
    for(int i=width-1; i>=0; i--)
126
      {
127
      if( tmp[4*i]==0 && tmp[4*i+3]==-1 ) return i;
128 7cb8d4b0 Leszek Koltunski
      }
129
130 ba52835a Leszek Koltunski
    return -1;
131 7cb8d4b0 Leszek Koltunski
    }
132
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134
135
  private int computeFirstRow(ByteBuffer buf, byte[] tmp, int width, int height)
136
    {
137
    int wBytes = 4*width;
138
139
    for(int i=0; i<height; i++)
140
      {
141
      buf.position(i*wBytes);
142
      buf.get(tmp);
143
144 ba52835a Leszek Koltunski
      if( firstBlackPixel(tmp,width)>=0 ) return i;
145 7cb8d4b0 Leszek Koltunski
      }
146
147 20b60ad9 Leszek Koltunski
    return 0;
148 7cb8d4b0 Leszek Koltunski
    }
149
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151
152
  private int computeLastRow(ByteBuffer buf, byte[] tmp, int width, int height)
153
    {
154
    int wBytes = 4*width;
155
156
    for(int i=height-1; i>=0; i--)
157
      {
158
      buf.position(i*wBytes);
159
      buf.get(tmp);
160
161 ba52835a Leszek Koltunski
      if( firstBlackPixel(tmp,width)>=0 ) return i;
162 7cb8d4b0 Leszek Koltunski
      }
163
164 20b60ad9 Leszek Koltunski
    return width-1;
165 7cb8d4b0 Leszek Koltunski
    }
166
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168
169 ba52835a Leszek Koltunski
  private int computeLeftColumn(ByteBuffer buf, byte[] tmp, int width, int firstrow, int lastrow)
170 7cb8d4b0 Leszek Koltunski
    {
171
    int wBytes = 4*width;
172 ba52835a Leszek Koltunski
    int currentBest = width;
173 7cb8d4b0 Leszek Koltunski
174 ba52835a Leszek Koltunski
    for(int i=firstrow; i<lastrow; i++)
175 7cb8d4b0 Leszek Koltunski
      {
176 ba52835a Leszek Koltunski
      buf.position(i*wBytes);
177
      buf.get(tmp);
178
179
      int pixel = firstBlackPixel(tmp,width);
180
      if( pixel>=0 && pixel<currentBest ) currentBest = pixel;
181 7cb8d4b0 Leszek Koltunski
      }
182
183 ba52835a Leszek Koltunski
    return currentBest;
184 7cb8d4b0 Leszek Koltunski
    }
185
186
///////////////////////////////////////////////////////////////////////////////////////////////////
187
188 ba52835a Leszek Koltunski
  private int computeRightColumn(ByteBuffer buf, byte[] tmp, int width, int firstrow, int lastrow)
189 7cb8d4b0 Leszek Koltunski
    {
190 ba52835a Leszek Koltunski
    int wBytes = 4*width;
191
    int currentBest = 0;
192 7cb8d4b0 Leszek Koltunski
193 ba52835a Leszek Koltunski
    for(int i=firstrow; i<lastrow; i++)
194 7cb8d4b0 Leszek Koltunski
      {
195 ba52835a Leszek Koltunski
      buf.position(i*wBytes);
196
      buf.get(tmp);
197
198
      int pixel = lastBlackPixel(tmp,width);
199
      if( pixel>=0 && pixel>currentBest ) currentBest = pixel;
200 7cb8d4b0 Leszek Koltunski
      }
201 ba52835a Leszek Koltunski
202
    return currentBest;
203 7cb8d4b0 Leszek Koltunski
    }
204
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206 ba52835a Leszek Koltunski
// GL uses a coordinate system from mathematics; i.e. (0,0) is in the lower-left corner. 2D stuff
207
// has the origin on the upper-left corner; we have to flip our bitmap upside down!
208
//
209
// We also need to figure out the topmost and bottommost rows where the object starts and cut out
210
// a square section from the 'input' so that the object is vertically centralized.
211 7cb8d4b0 Leszek Koltunski
212 ba52835a Leszek Koltunski
  private ByteBuffer adjustBuffer(ByteBuffer input, byte[] tmp, int width, int height)
213 7cb8d4b0 Leszek Koltunski
    {
214 ba52835a Leszek Koltunski
    int firstRow   = computeFirstRow(input,tmp,width,height);
215
    int lastRow    = computeLastRow(input,tmp,width,height);
216
    int leftColumn = computeLeftColumn(input,tmp,width,firstRow,lastRow);
217
    int rightColumn= computeRightColumn(input,tmp,width,firstRow,lastRow);
218
219
    int rowHeight = lastRow-firstRow;
220
    int colWidth  = rightColumn-leftColumn;
221
    int size      = Math.max(rowHeight,colWidth);
222
    size = (int)(1.1f*size);
223
    int half = size/2;
224
    int centerX = (leftColumn+rightColumn)/2;
225
    int centerY = (firstRow+lastRow)/2;
226
    int sL=size, sR=size, sT=size, sB=size;
227
228
    if( centerX-half<    0 )
229
      {
230
      android.util.Log.e("D", "buffer encroaches on the left!   centerX="+centerX+" centerY="+centerY+" size="+size);
231
      sL = 2*centerX;
232
      }
233
    if( centerX+half>width )
234
      {
235
      android.util.Log.e("D", "buffer encroaches on the right!  centerX="+centerX+" centerY="+centerY+" size="+size);
236
      sR = 2*(width-centerX);
237
      }
238
    if( centerY-half<    0 )
239
      {
240
      android.util.Log.e("D", "buffer encroaches on the top!    centerX="+centerX+" centerY="+centerY+" size="+size);
241
      sT = 2*centerY;
242
      }
243
    if( centerY+half>height)
244
      {
245
      android.util.Log.e("D", "buffer encroaches on the bottom! centerX="+centerX+" centerY="+centerY+" size="+size);
246
      sB = 2*(height-centerY);
247
      }
248
/*
249
    if( sL==size && sR==size && sT==size && sB==size )
250
      {
251
      android.util.Log.e("D", "EVERYTHING ALL RIGHT centerX="+centerX+" centerY="+centerY+" size="+size);
252
      }
253
*/
254
    int minH = Math.min(sL,sR);
255
    int minV = Math.min(sT,sB);
256
    mCreatedBufSize = Math.min(minH,minV);
257
    half = mCreatedBufSize/2;
258
    int wBytes = 4*mCreatedBufSize;
259
    ByteBuffer output = ByteBuffer.allocateDirect(wBytes*mCreatedBufSize);
260 7cb8d4b0 Leszek Koltunski
    output.order(ByteOrder.LITTLE_ENDIAN);
261 ba52835a Leszek Koltunski
    int startRow = centerY+half;
262
    int distR = width-centerX-half;
263 7cb8d4b0 Leszek Koltunski
264 ba52835a Leszek Koltunski
    for(int i=0; i<mCreatedBufSize; i++)
265 7cb8d4b0 Leszek Koltunski
      {
266 ba52835a Leszek Koltunski
      input.position((startRow-i)*4*width + 4*distR );
267
      input.get(tmp,0,wBytes);
268 7cb8d4b0 Leszek Koltunski
      output.position(i*wBytes);
269 ba52835a Leszek Koltunski
      output.put(tmp,0,wBytes);
270 7cb8d4b0 Leszek Koltunski
      }
271
272
    output.rewind();
273
    return output;
274
    }
275
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277
278
  private void process(WorkLoad load)
279
    {
280 ba52835a Leszek Koltunski
    int width  = load.width;
281
    int height = load.height;
282 7cb8d4b0 Leszek Koltunski
283
    byte[] tmp = new byte[4*width];
284
    ByteBuffer bufSquare = adjustBuffer(load.buffer,tmp,width,height);
285
    final String filename = load.filename;
286
    BufferedOutputStream bos =null;
287
    final Activity act = mWeakAct.get();
288
289
    try
290
      {
291
      bos = new BufferedOutputStream(new FileOutputStream(filename));
292 ba52835a Leszek Koltunski
      Bitmap bmp = Bitmap.createBitmap( mCreatedBufSize, mCreatedBufSize, Bitmap.Config.ARGB_8888);
293 eb6bccbd Leszek Koltunski
      bmp.copyPixelsFromBuffer(bufSquare);
294 7cb8d4b0 Leszek Koltunski
      bmp.compress(Bitmap.CompressFormat.PNG, 90, bos);
295
296
      BandagedCreatorActivity cact = (BandagedCreatorActivity)act;
297
      cact.iconCreationDone(bmp);
298
      }
299
    catch(final Exception ex)
300
      {
301
      act.runOnUiThread(new Runnable()
302
        {
303
        public void run()
304
          {
305
          Toast.makeText(act,
306
              "Saving to \n\n"+filename+"\n\n failed: "+"\n\n"+ex.getMessage() ,
307
              Toast.LENGTH_LONG).show();
308
          }
309
        });
310
      }
311
    finally
312
      {
313
      if(bos!=null)
314
        {
315
        try { bos.close(); }
316 f404152d Leszek Koltunski
        catch(IOException ignored) {}
317 7cb8d4b0 Leszek Koltunski
        }
318
      }
319
320
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
321
    File f = new File(filename);
322
    Uri contentUri = Uri.fromFile(f);
323
    mediaScanIntent.setData(contentUri);
324
    act.sendBroadcast(mediaScanIntent);
325
    }
326
  }